diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 1f824a391..4a16d36ab 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,25 @@ +2009-07-06 Corinna Vinschen + + * cygtls.h (struct _local_storage): Add thread storage pointers for + memory used by socket select functions. Combine them into a single + struct select. + * cygtls.cc: Accommodate above change throughout. + (_cygtls::init_thread): Drop initalizing of sockevt to + INVALID_HANDLE_VALUE. + (_cygtls::fixup_after_fork): Reset sockevt to NULL. + (_cygtls::remove): Don't use sockevt value to bail out prematurely. + Set sockevt to NULL. Free malloced select members. + * select.h (struct select_socket_info): Drop max_w4 member. + * select.cc (thread_socket): Use INFINITE timeout value if number of + objects to wait for is <= MAXIMUM_WAIT_OBJECTS. Use num_w4 member + of select_socket_info struct rather than dropped max_w4. + (init_tls_select_info): New inline function to initialize TLS select + members. + (start_thread_socket): Just call init_tls_select_info to initialize TLS + select members and use them later on. + (socket_cleanup): Don't free select_socket_info pointer members since + they are thread local now. + 2009-07-06 Christopher Faylor * dtable.cc (handle_to_fn): Detect failing NtQueryObject. diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 1d8153a32..16743af46 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -96,7 +96,6 @@ _cygtls::init_thread (void *x, DWORD (*func) (void *, void *)) thread_id = GetCurrentThreadId (); initialized = CYGTLS_INITIALIZED; - locals.select_sockevt = INVALID_HANDLE_VALUE; errno_addr = &(local_clib._errno); if ((void *) func == (void *) cygthread::stub @@ -126,7 +125,7 @@ _cygtls::fixup_after_fork () sig = 0; } stacklock = spinning = 0; - locals.select_sockevt = INVALID_HANDLE_VALUE; + locals.select.sockevt = NULL; wq.thread_ev = NULL; } @@ -141,7 +140,7 @@ void _cygtls::remove (DWORD wait) { initialized = 0; - if (!locals.select_sockevt || exit_state >= ES_FINAL) + if (exit_state >= ES_FINAL) return; debug_printf ("wait %p", wait); @@ -149,10 +148,12 @@ _cygtls::remove (DWORD wait) { /* FIXME: Need some sort of atthreadexit function to allow things like select to control this themselves. */ - if (locals.select_sockevt != INVALID_HANDLE_VALUE) + if (!locals.select.sockevt) { - CloseHandle (locals.select_sockevt); - locals.select_sockevt = (HANDLE) NULL; + CloseHandle (locals.select.sockevt); + locals.select.sockevt = NULL; + free_local (select.ser_num); + free_local (select.w4); } free_local (process_ident); free_local (ntoa_buf); diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 5b944eb91..138d8f2bb 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -104,7 +104,12 @@ struct _local_storage char mnt_dir[CYG_MAX_PATH]; /* select.cc */ - HANDLE select_sockevt; + struct { + HANDLE sockevt; + int max_w4; + LONG *ser_num; // note: malloced + HANDLE *w4; // note: malloced + } select; /* strerror */ char strerror_buf[sizeof ("Unknown error 4294967295")]; diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 07fb30e09..6e46c4ed1 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -16,6 +16,7 @@ details. */ #include "winsup.h" #include +#include #include "ntdll.h" #include @@ -1315,7 +1316,10 @@ static DWORD WINAPI thread_socket (void *arg) { select_socket_info *si = (select_socket_info *) arg; - DWORD timeout = 64 / (si->max_w4 / MAXIMUM_WAIT_OBJECTS); + DWORD timeout = (si->num_w4 <= MAXIMUM_WAIT_OBJECTS) + ? INFINITE + : (64 / (roundup2 (si->num_w4, MAXIMUM_WAIT_OBJECTS) + / MAXIMUM_WAIT_OBJECTS)); bool event = false; select_printf ("stuff_start %p", si->start); @@ -1326,18 +1330,19 @@ thread_socket (void *arg) if (peek_socket (s, false)) event = true; if (!event) - for (int i = 0; i < si->max_w4; i += MAXIMUM_WAIT_OBJECTS) + for (int i = 0; i < si->num_w4; i += MAXIMUM_WAIT_OBJECTS) switch (WaitForMultipleObjects (min (si->num_w4 - i, MAXIMUM_WAIT_OBJECTS), si->w4 + i, FALSE, timeout)) { case WAIT_FAILED: goto out; + case WAIT_TIMEOUT: + continue; case WAIT_OBJECT_0: if (!i) /* Socket event set. */ goto out; - break; - case WAIT_TIMEOUT: + /*FALLTHRU*/ default: break; } @@ -1347,6 +1352,36 @@ out: return 0; } +static inline bool init_tls_select_info () __attribute__ ((always_inline)); +static inline bool +init_tls_select_info () +{ + if (!_my_tls.locals.select.sockevt) + { + _my_tls.locals.select.sockevt = CreateEvent (&sec_none_nih, TRUE, FALSE, + NULL); + if (!_my_tls.locals.select.sockevt) + return false; + } + if (!_my_tls.locals.select.ser_num) + { + _my_tls.locals.select.ser_num + = (LONG *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (LONG)); + if (!_my_tls.locals.select.ser_num) + return false; + _my_tls.locals.select.w4 + = (HANDLE *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (HANDLE)); + if (!_my_tls.locals.select.w4) + { + free (_my_tls.locals.select.ser_num); + _my_tls.locals.select.ser_num = NULL; + return false; + } + _my_tls.locals.select.max_w4 = MAXIMUM_WAIT_OBJECTS; + } + return true; +} + static int start_thread_socket (select_record *me, select_stuff *stuff) { @@ -1359,19 +1394,17 @@ start_thread_socket (select_record *me, select_stuff *stuff) } si = new select_socket_info; - si->ser_num = (LONG *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (LONG)); - si->w4 = (HANDLE *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (HANDLE)); - if (!si->ser_num || !si->w4) + + if (!init_tls_select_info ()) return 0; - si->max_w4 = MAXIMUM_WAIT_OBJECTS; - select_record *s = &stuff->start; - if (_my_tls.locals.select_sockevt != INVALID_HANDLE_VALUE) - si->w4[0] = _my_tls.locals.select_sockevt; - else if (!(si->w4[0] = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL))) - return 1; - else - _my_tls.locals.select_sockevt = si->w4[0]; + + si->ser_num = _my_tls.locals.select.ser_num; + si->w4 = _my_tls.locals.select.w4; + + si->w4[0] = _my_tls.locals.select.sockevt; si->num_w4 = 1; + + select_record *s = &stuff->start; while ((s = s->next)) if (s->startup == start_thread_socket) { @@ -1382,21 +1415,23 @@ start_thread_socket (select_record *me, select_stuff *stuff) for (int i = 1; i < si->num_w4; ++i) if (si->ser_num[i] == ser_num) goto continue_outer_loop; - if (si->num_w4 >= si->max_w4) + if (si->num_w4 >= _my_tls.locals.select.max_w4) { LONG *nser = (LONG *) realloc (si->ser_num, - (si->max_w4 + MAXIMUM_WAIT_OBJECTS) + (_my_tls.locals.select.max_w4 + + MAXIMUM_WAIT_OBJECTS) * sizeof (LONG)); if (!nser) return 0; - si->ser_num = nser; + _my_tls.locals.select.ser_num = si->ser_num = nser; HANDLE *nw4 = (HANDLE *) realloc (si->w4, - (si->max_w4 + MAXIMUM_WAIT_OBJECTS) + (_my_tls.locals.select.max_w4 + + MAXIMUM_WAIT_OBJECTS) * sizeof (HANDLE)); if (!nw4) return 0; - si->w4 = nw4; - si->max_w4 += MAXIMUM_WAIT_OBJECTS; + _my_tls.locals.select.w4 = si->w4 = nw4; + _my_tls.locals.select.max_w4 += MAXIMUM_WAIT_OBJECTS; } si->ser_num[si->num_w4] = ser_num; si->w4[si->num_w4++] = ((fhandler_socket *) s->fh)->wsock_event (); @@ -1423,10 +1458,6 @@ socket_cleanup (select_record *, select_stuff *stuff) si->thread->detach (); ResetEvent (si->w4[0]); stuff->device_specific_socket = NULL; - if (si->ser_num) - free (si->ser_num); - if (si->w4) - free (si->w4); delete si; } select_printf ("returning"); diff --git a/winsup/cygwin/select.h b/winsup/cygwin/select.h index 766f8c679..743222ebd 100644 --- a/winsup/cygwin/select.h +++ b/winsup/cygwin/select.h @@ -58,7 +58,6 @@ struct select_pipe_info: public select_info struct select_socket_info: public select_info { - int max_w4; int num_w4; LONG *ser_num; HANDLE *w4;