diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 51d79af9b..f3e21c767 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,24 @@ +2002-12-10 Christopher Faylor + + * cygthread.h (cygthread::stack_ptr): New element. + (cygthread::detach): Accept a "wait_for_signal" argument. + (cygthread::terminate_thread): New function. + * cygthread.cc (cygthread::stub): Set stack pointer argument. + (cygthread::terminate_thread): New function. Forcibly terminate + thread. + (cygthread::detach): Optionally wait for signals and kill thread when + signal arrives. + * exceptions.cc (signal_exit): Set signal_arrived prior to exiting to + wake up anything blocking on signals. + * fhandler.h (fhandler_base::set_r_no_interrupt): Change to accept bool + argument. + (fhandler_pipe::ready_for_read): Declare. + * pipe.cc (pipeargs): New structure. + (read_pipe): New thread stub wrapper for normal pipe read. + (fhandler_pipe::read): Modify to call reader in a cygthread, + terminating on signal, as appropriate. + * select.cc (fhandler_pipe::ready_for_read): Define new function. + 2002-12-10 Corinna Vinschen * net.cc (free_protoent_ptr): Add missing free() for base structure. @@ -6,16 +27,17 @@ 2002-12-10 Craig McGeachie - * netdb.cc (parse_alias_list, parse_services_line) - (parse_protocol_line): Change strtok calls to strtok_r. + * netdb.cc (parse_alias_list): Change strtok calls to strtok_r. + (parse_services_line): Ditto. + (parse_protocol_line): Ditto. 2002-12-10 Pierre Humblet * pwdgrp.h (pwdgrp_check::pwdgrp_state): Replace by pwdgrp_check::isinitializing (). (pwdgrp_check::isinitializing): Create. - * passwd.cc (grab_int): Change type to unsigned, use strtoul and - set the pointer content to 0 if the field is invalid. + * passwd.cc (grab_int): Change type to unsigned, use strtoul and set + the pointer content to 0 if the field is invalid. (parse_pwd): Move validity test after getting pw_gid. (read_etc_passwd): Replace "passwd_state <= " by passwd_state::isinitializing (). @@ -23,7 +45,7 @@ (internal_getpwnam): Ditto. (getpwent): Ditto. (getpass): Ditto. - * grp.cc (parse_grp): Use strtoul for gr_gid and verify the validity. + * grp.cc (parse_grp): Use strtoul for gr_gid and verify the validity. (read_etc_group): Replace "group_state <= " by group_state::isinitializing (). (internal_getgrgid): Ditto. diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 27e7f9442..0c591d01f 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -9,14 +9,17 @@ details. */ #include "winsup.h" #include #include +#include #include "exceptions.h" #include "security.h" #include "cygthread.h" #include "sync.h" +#include "cygerrno.h" +#include "sigproc.h" #undef CloseHandle -static cygthread NO_COPY threads[9]; +static cygthread NO_COPY threads[18]; #define NTHREADS (sizeof (threads) / sizeof (threads[0])) DWORD NO_COPY cygthread::main_thread_id; @@ -37,11 +40,12 @@ cygthread::stub (VOID *arg) cygthread *info = (cygthread *) arg; if (info->arg == cygself) - info->ev = info->thread_sync = NULL; + info->ev = info->thread_sync = info->stack_ptr = NULL; else { info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + info->stack_ptr = &arg; } while (1) { @@ -231,22 +235,72 @@ cygthread::exit_thread () ExitThread (0); } +/* Forcibly terminate a thread. */ +void +cygthread::terminate_thread () +{ + if (!is_freerange) + SetEvent (*this); + (void) TerminateThread (h, 0); + (void) WaitForSingleObject (h, INFINITE); + + MEMORY_BASIC_INFORMATION m; + memset (&m, 0, sizeof (m)); + (void) VirtualQuery (stack_ptr, &m, sizeof m); + + if (m.RegionSize) + (void) VirtualFree (m.AllocationBase, m.RegionSize, MEM_DECOMMIT); + + if (is_freerange) + is_freerange = false; + else + { + CloseHandle (ev); + CloseHandle (thread_sync); + } + CloseHandle (h); + thread_sync = ev = h = NULL; + __name = NULL; + id = 0; +} + /* Detach the cygthread from the current thread. Note that the theory is that cygthreads are only associated with one thread. So, there should be no problems with multiple threads doing waits on the one cygthread. */ void -cygthread::detach () +cygthread::detach (bool wait_for_sig) { if (avail) system_printf ("called detach on available thread %d?", avail); else { DWORD avail = id; - DWORD res = WaitForSingleObject (*this, INFINITE); - thread_printf ("WFSO returns %d, id %p", res, id); + DWORD res; - if (is_freerange) + if (!wait_for_sig) + res = WaitForSingleObject (*this, INFINITE); + else + { + HANDLE w4[2]; + w4[0] = signal_arrived; + w4[1] = *this; + res = WaitForMultipleObjects (2, w4, FALSE, INFINITE); + if (res == WAIT_OBJECT_0) + { + terminate_thread (); + set_errno (EINTR); /* caller should be dealing with return + values. */ + avail = 0; + } + } + + thread_printf ("%s returns %d, id %p", wait_for_sig ? "WFMO" : "WFSO", + res, id); + + if (!avail) + /* already handled */; + else if (is_freerange) { CloseHandle (h); free (this); diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h index 774c656da..479a0682c 100644 --- a/winsup/cygwin/cygthread.h +++ b/winsup/cygwin/cygthread.h @@ -13,6 +13,7 @@ class cygthread HANDLE h; HANDLE ev; HANDLE thread_sync; + void *stack_ptr; const char *__name; LPTHREAD_START_ROUTINE func; VOID *arg; @@ -26,12 +27,13 @@ class cygthread cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *); cygthread () {}; static void init (); - void detach (); + void detach (bool = false); operator HANDLE (); static bool is (); void * operator new (size_t); static cygthread *freerange (); void exit_thread (); + void terminate_thread (); static void terminate (); bool SetThreadPriority (int nPriority) {return ::SetThreadPriority (h, nPriority);} void zap_h () diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 380697eb0..bbd5518d0 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1117,6 +1117,7 @@ signal_exit (int rc) TerminateProcess (hExeced, rc); sigproc_printf ("about to call do_exit (%x)", rc); + (void) SetEvent (signal_arrived); do_exit (rc); } diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 3dcc8b64d..56be17b59 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -219,7 +219,7 @@ class fhandler_base int get_default_fmode (int flags); bool get_r_no_interrupt () { return FHISSETF (NOEINTR); } - void set_r_no_interrupt (int b) { FHCONDSETF (b, NOEINTR); } + void set_r_no_interrupt (bool b) { FHCONDSETF (b, NOEINTR); } bool get_close_on_exec () { return FHISSETF (CLOEXEC); } int set_close_on_exec_flag (int b) { return FHCONDSETF (b, CLOEXEC); } @@ -473,6 +473,7 @@ class fhandler_pipe: public fhandler_base void set_eof () {broken_pipe = true;} friend int make_pipe (int fildes[2], unsigned int psize, int mode); HANDLE get_guard () const {return guard;} + int ready_for_read (int fd, DWORD howlong); }; class fhandler_dev_raw: public fhandler_base diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index fe712e25e..49093728c 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -22,6 +22,7 @@ details. */ #include "cygheap.h" #include "thread.h" #include "pinfo.h" +#include "cygthread.h" static unsigned pipecount; static const NO_COPY char pipeid_fmt[] = "stupid_pipe.%u.%u"; @@ -50,14 +51,36 @@ fhandler_pipe::set_close_on_exec (int val) set_inheritance (writepipe_exists, val); } +struct pipeargs +{ + fhandler_base *fh; + void *ptr; + size_t len; + int res; +}; + +static DWORD WINAPI +read_pipe (void *arg) +{ + pipeargs *pi = (pipeargs *) arg; + pi->res = pi->fh->fhandler_base::read (pi->ptr, pi->len); + return 0; +} + int __stdcall fhandler_pipe::read (void *in_ptr, size_t in_len) { if (broken_pipe) return 0; - int res = this->fhandler_base::read (in_ptr, in_len); + pipeargs pi; + pi.fh = this; + pi.ptr = in_ptr; + pi.len = in_len; + pi.res = -1; + cygthread *th = new cygthread (read_pipe, &pi, "read_pipe"); + th->detach (1); (void) ReleaseMutex (guard); - return res; + return pi.res; } int fhandler_pipe::close () diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 369bea90f..d8d89999c 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -431,7 +431,7 @@ peek_pipe (select_record *s, bool from_select) { case FH_PTYM: case FH_TTYM: - if (((fhandler_pty_master *)fh)->need_nl) + if (((fhandler_pty_master *) fh)->need_nl) { gotone = s->read_ready = true; goto out; @@ -521,7 +521,7 @@ struct pipeinf static DWORD WINAPI thread_pipe (void *arg) { - pipeinf *pi = (pipeinf *)arg; + pipeinf *pi = (pipeinf *) arg; BOOL gotone = FALSE; for (;;) @@ -563,18 +563,18 @@ start_thread_pipe (select_record *me, select_stuff *stuff) pipeinf *pi = new pipeinf; pi->start = &stuff->start; pi->stop_thread_pipe = FALSE; - pi->thread = new cygthread (thread_pipe, (LPVOID)pi, "select_pipe"); + pi->thread = new cygthread (thread_pipe, (LPVOID) pi, "select_pipe"); me->h = *pi->thread; if (!me->h) return 0; - stuff->device_specific[FHDEVN (FH_PIPE)] = (void *)pi; + stuff->device_specific[FHDEVN (FH_PIPE)] = (void *) pi; return 1; } static void pipe_cleanup (select_record *, select_stuff *stuff) { - pipeinf *pi = (pipeinf *)stuff->device_specific[FHDEVN (FH_PIPE)]; + pipeinf *pi = (pipeinf *) stuff->device_specific[FHDEVN (FH_PIPE)]; if (pi && pi->thread) { pi->stop_thread_pipe = true; @@ -584,6 +584,16 @@ pipe_cleanup (select_record *, select_stuff *stuff) } } +int +fhandler_pipe::ready_for_read (int fd, DWORD howlong) +{ + if (!howlong) + return this->fhandler_base::ready_for_read (fd, howlong); + + get_guard (); + return true; +} + select_record * fhandler_pipe::select_read (select_record *s) { @@ -631,7 +641,7 @@ static int peek_console (select_record *me, bool) { extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *); - fhandler_console *fh = (fhandler_console *)me->fh; + fhandler_console *fh = (fhandler_console *) me->fh; if (!me->read_selected) return me->write_ready; @@ -748,19 +758,19 @@ fhandler_console::select_except (select_record *s) select_record * fhandler_tty_common::select_read (select_record *s) { - return ((fhandler_pipe*)this)->fhandler_pipe::select_read (s); + return ((fhandler_pipe *) this)->fhandler_pipe::select_read (s); } select_record * fhandler_tty_common::select_write (select_record *s) { - return ((fhandler_pipe *)this)->fhandler_pipe::select_write (s); + return ((fhandler_pipe *) this)->fhandler_pipe::select_write (s); } select_record * fhandler_tty_common::select_except (select_record *s) { - return ((fhandler_pipe *)this)->fhandler_pipe::select_except (s); + return ((fhandler_pipe *) this)->fhandler_pipe::select_except (s); } static int @@ -846,7 +856,7 @@ peek_serial (select_record *s, bool) { COMSTAT st; - fhandler_serial *fh = (fhandler_serial *)s->fh; + fhandler_serial *fh = (fhandler_serial *) s->fh; if (fh->get_readahead_valid () || fh->overlapped_armed < 0) return s->read_ready = true; @@ -944,7 +954,7 @@ err: static DWORD WINAPI thread_serial (void *arg) { - serialinf *si = (serialinf *)arg; + serialinf *si = (serialinf *) arg; BOOL gotone= FALSE; for (;;) @@ -980,16 +990,16 @@ start_thread_serial (select_record *me, select_stuff *stuff) serialinf *si = new serialinf; si->start = &stuff->start; si->stop_thread_serial = FALSE; - si->thread = new cygthread (thread_serial, (LPVOID)si, "select_serial"); + si->thread = new cygthread (thread_serial, (LPVOID) si, "select_serial"); me->h = *si->thread; - stuff->device_specific[FHDEVN (FH_SERIAL)] = (void *)si; + stuff->device_specific[FHDEVN (FH_SERIAL)] = (void *) si; return 1; } static void serial_cleanup (select_record *, select_stuff *stuff) { - serialinf *si = (serialinf *)stuff->device_specific[FHDEVN (FH_SERIAL)]; + serialinf *si = (serialinf *) stuff->device_specific[FHDEVN (FH_SERIAL)]; if (si && si->thread) { si->stop_thread_serial = true; @@ -1200,7 +1210,7 @@ static int start_thread_socket (select_record *, select_stuff *); static DWORD WINAPI thread_socket (void *arg) { - socketinf *si = (socketinf *)arg; + socketinf *si = (socketinf *) arg; select_printf ("stuff_start %p", &si->start); int r = WINSOCK_SELECT (0, &si->readfds, &si->writefds, &si->exceptfds, NULL); @@ -1243,7 +1253,7 @@ start_thread_socket (select_record *me, select_stuff *stuff) { socketinf *si; - if ((si = (socketinf *)stuff->device_specific[FHDEVN (FH_SOCKET)])) + if ((si = (socketinf *) stuff->device_specific[FHDEVN (FH_SOCKET)])) { me->h = *si->thread; return 1; @@ -1314,7 +1324,7 @@ start_thread_socket (select_record *me, select_stuff *stuff) stuff->device_specific[FHDEVN (FH_SOCKET)] = (void *) si; si->start = &stuff->start; select_printf ("stuff_start %p", &stuff->start); - si->thread = new cygthread (thread_socket, (LPVOID)si, "select_socket"); + si->thread = new cygthread (thread_socket, (LPVOID) si, "select_socket"); me->h = *si->thread; return 1; @@ -1327,7 +1337,7 @@ err: void socket_cleanup (select_record *, select_stuff *stuff) { - socketinf *si = (socketinf *)stuff->device_specific[FHDEVN (FH_SOCKET)]; + socketinf *si = (socketinf *) stuff->device_specific[FHDEVN (FH_SOCKET)]; select_printf ("si %p si->thread %p", si, si ? si->thread : NULL); if (si && si->thread) {