From 4ae63783821bd2114246166957d25b2acd26c875 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sun, 17 Jun 2012 20:50:24 +0000 Subject: [PATCH] Add '#include "cygwait.h"' throughout, where appropriate. * DevNotes: Add entry cgf-000012. * Makefile.in (DLL_OFILES): Add cygwait.o. * sigproc.h: Remove cygwait definitions. * cygwait.h: New file. Define/declare Cygwin waitfor functions. * cygwait.cc: Ditto. * exceptions.cc: Include cygwait.h. (handle_sigsuspend): Accommodate change in cancelable_wait arguments. (sigpacket::process): Display thread tls in debugging output. * fhandler.cc (fhandler_base_overlapped::wait_overlapped): Use symbolic names for signal and cancel return. * fhandler_console.cc (fhandler_console::read): Ditto. (fhandler_dev_dsp::Audio_out::waitforspace): Ditto. fhandler_dev_dsp::Audio_in::waitfordata): Ditto. * fhandler_fifo.cc (fhandler_fifo::wait): Ditto. * fhandler_serial.cc (fhandler_serial::raw_read): Ditto. * fhandler_tty.cc (fhandler_pty_slave::read): Ditto. * select.cc (cygwin_select): Ditto. * wait.cc (wait4): Ditto. * thread.cc (cancelable_wait): Move definition to cygwait.h. (pthread_cond::wait): Accommodate change in cancelable_wait arguments. (pthread_mutex::lock): Ditto. (pthread_spinlock::lock): Ditto. (pthread::join): Ditto. (pthread::thread_init_wrapper): Display tls in debugging output. (semaphore::_timedwait): Ditto. * thread.h (cw_sig_wait): Move to cygwait.h. (cw_cancel_action): Delete. (cancelable_wait): Move declaration to cygwait.h. --- winsup/cygwin/ChangeLog | 32 +++++++++ winsup/cygwin/DevNotes | 22 ++++++ winsup/cygwin/Makefile.in | 16 ++--- winsup/cygwin/cygwait.cc | 108 ++++++++++++++++++++++++++++++ winsup/cygwin/cygwait.h | 47 +++++++++++++ winsup/cygwin/exceptions.cc | 4 +- winsup/cygwin/fhandler.cc | 3 +- winsup/cygwin/fhandler_console.cc | 5 +- winsup/cygwin/fhandler_dsp.cc | 9 +-- winsup/cygwin/fhandler_fifo.cc | 17 ++--- winsup/cygwin/fhandler_serial.cc | 9 +-- winsup/cygwin/fhandler_tty.cc | 11 +-- winsup/cygwin/select.cc | 5 +- winsup/cygwin/signal.cc | 1 + winsup/cygwin/sigproc.h | 27 -------- winsup/cygwin/thread.cc | 102 +++------------------------- winsup/cygwin/thread.h | 22 +----- winsup/cygwin/wait.cc | 5 +- 18 files changed, 269 insertions(+), 176 deletions(-) create mode 100644 winsup/cygwin/cygwait.cc create mode 100644 winsup/cygwin/cygwait.h diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6bfb7ef67..ef885e083 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,35 @@ +2012-06-17 Christopher Faylor + + Add '#include "cygwait.h"' throughout, where appropriate. + * DevNotes: Add entry cgf-000012. + * Makefile.in (DLL_OFILES): Add cygwait.o. + * sigproc.h: Remove cygwait definitions. + * cygwait.h: New file. Define/declare Cygwin waitfor functions. + * cygwait.cc: Ditto. + * exceptions.cc: Include cygwait.h. + (handle_sigsuspend): Accommodate change in cancelable_wait arguments. + (sigpacket::process): Display thread tls in debugging output. + * fhandler.cc (fhandler_base_overlapped::wait_overlapped): Use symbolic + names for signal and cancel return. + * fhandler_console.cc (fhandler_console::read): Ditto. + (fhandler_dev_dsp::Audio_out::waitforspace): Ditto. + fhandler_dev_dsp::Audio_in::waitfordata): Ditto. + * fhandler_fifo.cc (fhandler_fifo::wait): Ditto. + * fhandler_serial.cc (fhandler_serial::raw_read): Ditto. + * fhandler_tty.cc (fhandler_pty_slave::read): Ditto. + * select.cc (cygwin_select): Ditto. + * wait.cc (wait4): Ditto. + * thread.cc (cancelable_wait): Move definition to cygwait.h. + (pthread_cond::wait): Accommodate change in cancelable_wait arguments. + (pthread_mutex::lock): Ditto. + (pthread_spinlock::lock): Ditto. + (pthread::join): Ditto. + (pthread::thread_init_wrapper): Display tls in debugging output. + (semaphore::_timedwait): Ditto. + * thread.h (cw_sig_wait): Move to cygwait.h. + (cw_cancel_action): Delete. + (cancelable_wait): Move declaration to cygwait.h. + 2012-06-11 Yaakov Selkowitz * regex/regcomp.c (p_ere): Allow vertical-line following diff --git a/winsup/cygwin/DevNotes b/winsup/cygwin/DevNotes index a311256e2..7bec42017 100644 --- a/winsup/cygwin/DevNotes +++ b/winsup/cygwin/DevNotes @@ -1,3 +1,25 @@ +2012-06-12 cgf-000012 + +These changes are the preliminary for redoing the way threads wait for +signals. The problems are shown by the test case mentioned here: + +http://cygwin.com/ml/cygwin/2012-05/msg00434.html + +I've known that the signal handling in threads wasn't quite right for +some time. I lost all of my thread signal tests in the great "rm -r" +debacle of a few years ago and have been less than enthusiastic about +redoing everything (I had PCTS tests and everyting). But it really is +time to redo this signal handling to make it more like it is supposed to +be. + +This change should not introduce any new behavior. Things should +continue to behave as before. The major differences are a change in the +arguments to cancelable_wait and cygwait now uses cancelable_wait and, +so, the returns from cygwait now mirror cancelable_wait. + +The next change will consolidate cygwait and cancelable_wait into one +cygwait function. + 2012-06-02 cgf-000011 The refcnt handling was tricky to get right but I had convinced myself diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index e65b44031..2aedb1c7b 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -133,16 +133,16 @@ MALLOC_OFILES:=@MALLOC_OFILES@ DLL_IMPORTS:=$(w32api_lib)/libkernel32.a $(w32api_lib)/libntdll.a MT_SAFE_OBJECTS:= -# Please maintain this list in sorted order, with maximum files per 86 col line # DLL_OFILES:=advapi32.o assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o \ - cygthread.o cygtls.o cygxdr.o dcrt0.o debug.o devices.o dir.o dlfcn.o \ - dll_init.o dtable.o environ.o errno.o exceptions.o exec.o external.o \ - fcntl.o fenv.o fhandler.o fhandler_clipboard.o fhandler_console.o \ - fhandler_dev.o fhandler_disk_file.o fhandler_dsp.o fhandler_fifo.o \ - fhandler_floppy.o fhandler_mailslot.o fhandler_mem.o fhandler_netdrive.o \ - fhandler_nodevice.o fhandler_proc.o fhandler_process.o fhandler_procnet.o \ - fhandler_procsys.o fhandler_procsysvipc.o fhandler_random.o fhandler_raw.o \ + cygthread.o cygtls.o cygwait.o cygxdr.o dcrt0.o debug.o devices.o \ + dir.o dlfcn.o dll_init.o dtable.o environ.o errno.o exceptions.o \ + exec.o external.o fcntl.o fenv.o fhandler.o fhandler_clipboard.o \ + fhandler_console.o fhandler_dev.o fhandler_disk_file.o fhandler_dsp.o \ + fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.o fhandler_mem.o \ + fhandler_netdrive.o fhandler_nodevice.o fhandler_proc.o \ + fhandler_process.o fhandler_procnet.o fhandler_procsys.o \ + fhandler_procsysvipc.o fhandler_random.o fhandler_raw.o \ fhandler_registry.o fhandler_serial.o fhandler_socket.o fhandler_tape.o \ fhandler_termios.o fhandler_tty.o fhandler_virtual.o fhandler_windows.o \ fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \ diff --git a/winsup/cygwin/cygwait.cc b/winsup/cygwin/cygwait.cc new file mode 100644 index 000000000..6e0610da0 --- /dev/null +++ b/winsup/cygwin/cygwait.cc @@ -0,0 +1,108 @@ +/* cygwait.h + + Copyright 2011, 2012 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include "winsup.h" +#include "sigproc.h" +#include "cygwait.h" +#include "ntdll.h" + +#define is_cw_cancel (mask & cw_cancel) +#define is_cw_cancel_self (mask & cw_cancel_self) +#define is_cw_sig (mask & cw_sig) +#define is_cw_sig_eintr (mask & cw_sig_eintr) +#define is_cw_sig_return (mask & cw_sig_return) + +#define is_cw_sig_handle (mask & (is_cw_sig | is_cw_sig_eintr)) + +DWORD +cancelable_wait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) +{ + DWORD res; + DWORD num = 0; + HANDLE wait_objects[4]; + pthread_t thread = pthread::self (); + + /* Do not change the wait order. + The object must have higher priority than the cancel event, + because WaitForMultipleObjects will return the smallest index + if both objects are signaled. */ + if (object) + wait_objects[num++] = object; + + DWORD sig_n; + if (!is_cw_sig_handle) + sig_n = WAIT_TIMEOUT + 1; + else + { + sig_n = WAIT_OBJECT_0 + num++; + wait_objects[sig_n] = signal_arrived; + } + + DWORD cancel_n; + if (!is_cw_cancel || !pthread::is_good_object (&thread) || + thread->cancelstate == PTHREAD_CANCEL_DISABLE) + cancel_n = WAIT_TIMEOUT + 1; + else + { + cancel_n = WAIT_OBJECT_0 + num++; + wait_objects[cancel_n] = thread->cancel_event; + } + + DWORD timeout_n; + if (!timeout) + timeout_n = WAIT_TIMEOUT + 1; + else + { + timeout_n = WAIT_OBJECT_0 + num++; + if (!_my_tls.locals.cw_timer) + NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL, + NotificationTimer); + NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL); + wait_objects[timeout_n] = _my_tls.locals.cw_timer; + } + + while (1) + { + res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE); + if (res == cancel_n) + { + if (is_cw_cancel_self) + pthread::static_cancel_self (); + res = WAIT_CANCELED; + } + else if (res == timeout_n) + res = WAIT_TIMEOUT; + else if (res != sig_n) + /* all set */; + else if (is_cw_sig_eintr) + res = WAIT_SIGNALED; + else + { + _my_tls.call_signal_handler (); + continue; + } + break; + } + + if (timeout) + { + TIMER_BASIC_INFORMATION tbi; + + NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi, + sizeof tbi, NULL); + /* if timer expired, TimeRemaining is negative and represents the + system uptime when signalled */ + if (timeout->QuadPart < 0LL) + timeout->QuadPart = tbi.SignalState ? 0LL : tbi.TimeRemaining.QuadPart; + NtCancelTimer (_my_tls.locals.cw_timer, NULL); + } + + return res; +} diff --git a/winsup/cygwin/cygwait.h b/winsup/cygwin/cygwait.h new file mode 100644 index 000000000..c2b7f5801 --- /dev/null +++ b/winsup/cygwin/cygwait.h @@ -0,0 +1,47 @@ +/* cygwait.h + + Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#pragma once + +enum cw_wait_mask +{ + cw_cancel = 0x0001, + cw_cancel_self = 0x0002, + cw_sig = 0x0004, + cw_sig_eintr = 0x0008 +}; + +const unsigned cw_std_mask = cw_cancel | cw_cancel_self | cw_sig; + +DWORD cancelable_wait (HANDLE, PLARGE_INTEGER timeout = NULL, + unsigned = cw_std_mask) + __attribute__ ((regparm (3))); + +static inline DWORD __attribute__ ((always_inline)) +cygwait (HANDLE h, DWORD howlong = INFINITE) +{ + PLARGE_INTEGER pli_howlong; + LARGE_INTEGER li_howlong; + if (howlong == INFINITE) + pli_howlong = NULL; + else + { + li_howlong.QuadPart = 10000ULL * howlong; + pli_howlong = &li_howlong; + } + return cancelable_wait (h, pli_howlong, cw_cancel | cw_sig_eintr); +} + +static inline DWORD __attribute__ ((always_inline)) +cygwait (DWORD howlong) +{ + return cygwait ((HANDLE) NULL, howlong); +} diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index f78e8f7b6..3c22e35c3 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -31,6 +31,7 @@ details. */ #include "child_info.h" #include "ntdll.h" #include "exception.h" +#include "cygwait.h" #define CALL_HANDLER_RETRY_OUTER 10 #define CALL_HANDLER_RETRY_INNER 10 @@ -714,7 +715,7 @@ handle_sigsuspend (sigset_t tempmask) sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask); pthread_testcancel (); - cancelable_wait (signal_arrived); + cancelable_wait (signal_arrived, NULL, cw_cancel | cw_cancel_self); set_sig_errno (EINTR); // Per POSIX @@ -1194,6 +1195,7 @@ sigpacket::process () handler = NULL; _cygtls *use_tls = tls ?: _main_tls; + sigproc_printf ("tls %p, use_tls %p", tls, use_tls); if (si.si_signo == SIGKILL) goto exit_sig; diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index a22fe2496..55a73b66e 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -31,6 +31,7 @@ details. */ #include "sigproc.h" #include "shared_info.h" #include +#include "cygwait.h" #define MAX_OVERLAPPED_WRITE_LEN (64 * 1024 * 1024) #define MIN_OVERLAPPED_WRITE_LEN (1 * 1024 * 1024) @@ -1939,7 +1940,7 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte case WAIT_OBJECT_0: err = ERROR_INVALID_HANDLE; break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: err = ERROR_INVALID_AT_INTERRUPT_TIME; break; default: diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index e54f11f2a..0208a4863 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -36,6 +36,7 @@ details. */ #include #include "sync.h" #include "child_info.h" +#include "cygwait.h" /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer is allocated using tmp_pathbuf!!! */ @@ -355,9 +356,9 @@ fhandler_console::read (void *pv, size_t& buflen) { case WAIT_OBJECT_0: break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: goto sig_exit; - case WAIT_OBJECT_0 + 2: + case WAIT_CANCELED: process_state.pop (); pthread::static_cancel_self (); /*NOTREACHED*/ diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc index 1cb3b465e..b16606615 100644 --- a/winsup/cygwin/fhandler_dsp.cc +++ b/winsup/cygwin/fhandler_dsp.cc @@ -21,6 +21,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "sigproc.h" +#include "cygwait.h" /*------------------------------------------------------------------------ Simple encapsulation of the win32 audio device. @@ -544,14 +545,14 @@ fhandler_dev_dsp::Audio_out::waitforspace () debug_printf ("100ms"); switch (cygwait (100)) { - case WAIT_OBJECT_0: + case WAIT_SIGNALED: if (!_my_tls.call_signal_handler ()) { set_errno (EINTR); return false; } break; - case WAIT_OBJECT_0 + 1: + case WAIT_CANCELED: pthread::static_cancel_self (); /*NOTREACHED*/ default: @@ -922,14 +923,14 @@ fhandler_dev_dsp::Audio_in::waitfordata () debug_printf ("100ms"); switch (cygwait (100)) { - case WAIT_OBJECT_0: + case WAIT_SIGNALED: if (!_my_tls.call_signal_handler ()) { set_errno (EINTR); return false; } break; - case WAIT_OBJECT_0 + 1: + case WAIT_CANCELED: pthread::static_cancel_self (); /*NOTREACHED*/ default: diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index 0e2d2bde4..d2b236d5c 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -22,6 +22,7 @@ #include "cygtls.h" #include "shared_info.h" #include "ntdll.h" +#include "cygwait.h" fhandler_fifo::fhandler_fifo (): fhandler_base_overlapped (), @@ -242,6 +243,14 @@ fhandler_fifo::wait (HANDLE h) case WAIT_OBJECT_0: debug_only_printf ("successfully waited for %s", what); return true; + case WAIT_SIGNALED: + debug_only_printf ("interrupted by signal while waiting for %s", what); + set_errno (EINTR); + return false; + case WAIT_CANCELED: + debug_only_printf ("cancellable interruption while waiting for %s", what); + pthread::static_cancel_self (); /* never returns */ + break; case WAIT_TIMEOUT: if (h == write_ready) { @@ -254,14 +263,6 @@ fhandler_fifo::wait (HANDLE h) return false; } break; - case WAIT_OBJECT_0 + 1: - debug_only_printf ("interrupted by signal while waiting for %s", what); - set_errno (EINTR); - return false; - case WAIT_OBJECT_0 + 2: - debug_only_printf ("cancellable interruption while waiting for %s", what); - pthread::static_cancel_self (); /* never returns */ - break; default: debug_only_printf ("unknown error while waiting for %s", what); __seterrno (); diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc index 033498742..c9a18c3d9 100644 --- a/winsup/cygwin/fhandler_serial.cc +++ b/winsup/cygwin/fhandler_serial.cc @@ -20,6 +20,7 @@ details. */ #include "pinfo.h" #include #include +#include "cygwait.h" /**********************************************************************/ /* fhandler_serial */ @@ -94,13 +95,13 @@ fhandler_serial::raw_read (void *ptr, size_t& ulen) goto err; debug_printf ("n %d, ev %x", n, ev); break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: tot = -1; PurgeComm (get_handle (), PURGE_RXABORT); overlapped_armed = 0; set_sig_errno (EINTR); goto out; - case WAIT_OBJECT_0 + 2: + case WAIT_CANCELED: PurgeComm (get_handle (), PURGE_RXABORT); overlapped_armed = 0; pthread::static_cancel_self (); @@ -201,12 +202,12 @@ fhandler_serial::raw_write (const void *ptr, size_t len) { case WAIT_OBJECT_0: break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: PurgeComm (get_handle (), PURGE_TXABORT); set_sig_errno (EINTR); ForceCloseHandle (write_status.hEvent); return -1; - case WAIT_OBJECT_0 + 2: + case WAIT_CANCELED: PurgeComm (get_handle (), PURGE_TXABORT); pthread::static_cancel_self (); /*NOTREACHED*/ diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 38a0571cb..fe7e283a9 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -26,6 +26,7 @@ details. */ #include "cygthread.h" #include "child_info.h" #include +#include "cygwait.h" #define close_maybe(h) \ do { \ @@ -737,14 +738,14 @@ fhandler_pty_slave::read (void *ptr, size_t& len) goto out; } break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: if (totalread > 0) goto out; termios_printf ("wait catched signal"); set_sig_errno (EINTR); totalread = -1; goto out; - case WAIT_OBJECT_0 + 2: + case WAIT_CANCELED: process_state.pop (); pthread::static_cancel_self (); /*NOTREACHED*/ @@ -772,14 +773,14 @@ fhandler_pty_slave::read (void *ptr, size_t& len) case WAIT_OBJECT_0: case WAIT_ABANDONED_0: break; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: if (totalread > 0) goto out; - termios_printf ("wait for mutex catched signal"); + termios_printf ("wait for mutex caught signal"); set_sig_errno (EINTR); totalread = -1; goto out; - case WAIT_OBJECT_0 + 2: + case WAIT_CANCELED: process_state.pop (); pthread::static_cancel_self (); /*NOTREACHED*/ diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 2d00e7c96..0186af733 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -34,6 +34,7 @@ details. */ #include "pinfo.h" #include "sigproc.h" #include "cygtls.h" +#include "cygwait.h" /* * All these defines below should be in sys/types.h @@ -143,7 +144,7 @@ cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, if (sel.start.next == NULL) switch (cygwait (ms)) { - case WAIT_OBJECT_0: + case WAIT_SIGNALED: select_printf ("signal received"); _my_tls.call_signal_handler (); if (!sel.return_on_signal) @@ -154,7 +155,7 @@ cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, res = select_stuff::select_error; } break; - case WAIT_OBJECT_0 + 1: + case WAIT_CANCELED: sel.destroy (); pthread::static_cancel_self (); /*NOTREACHED*/ diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 649cda694..a62c038cd 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -22,6 +22,7 @@ details. */ #include "fhandler.h" #include "dtable.h" #include "cygheap.h" +#include "cygwait.h" #define _SA_NORESTART 0x8000 diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index a86c6bc42..d980f1a6e 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -80,33 +80,6 @@ void __stdcall proc_terminate (); void __stdcall sigproc_init (); #ifdef __INSIDE_CYGWIN__ void __stdcall sigproc_terminate (enum exit_states); - -static inline DWORD __attribute__ ((always_inline)) -cygwait (HANDLE h, DWORD howlong = INFINITE) -{ - HANDLE w4[3]; - DWORD n = 0; - DWORD wait_signal; - if ((w4[n] = h) != NULL) - wait_signal = WAIT_OBJECT_0 + ++n; - else - wait_signal = WAIT_OBJECT_0 + 15; /* Arbitrary. Don't call signal - handler if only waiting for signal */ - w4[n++] = signal_arrived; - if ((w4[n] = pthread::get_cancel_event ()) != NULL) - n++; - DWORD res; - while ((res = WaitForMultipleObjects (n, w4, FALSE, howlong)) == wait_signal - && (_my_tls.call_signal_handler () || &_my_tls != _main_tls)) - continue; - return res; -} - -static inline DWORD __attribute__ ((always_inline)) -cygwait (DWORD wait) -{ - return cygwait ((HANDLE) NULL, wait); -} #endif bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1))); int __stdcall sig_send (_pinfo *, siginfo_t&, class _cygtls *tls = NULL) __attribute__ ((regparm (3))); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index b66bd4835..f3ff336f4 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -32,6 +32,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "ntdll.h" +#include "cygwait.h" extern "C" void __fp_lock_all (); extern "C" void __fp_unlock_all (); @@ -937,92 +938,6 @@ pthread::static_cancel_self () pthread::self ()->cancel_self (); } -DWORD -cancelable_wait (HANDLE object, PLARGE_INTEGER timeout, - const cw_cancel_action cancel_action, - const enum cw_sig_wait sig_wait) -{ - DWORD res; - DWORD num = 0; - HANDLE wait_objects[4]; - pthread_t thread = pthread::self (); - - /* Do not change the wait order. - The object must have higher priority than the cancel event, - because WaitForMultipleObjects will return the smallest index - if both objects are signaled. */ - wait_objects[num++] = object; - DWORD cancel_n; - if (cancel_action == cw_no_cancel || !pthread::is_good_object (&thread) || - thread->cancelstate == PTHREAD_CANCEL_DISABLE) - cancel_n = WAIT_TIMEOUT + 1; - else - { - cancel_n = WAIT_OBJECT_0 + num++; - wait_objects[cancel_n] = thread->cancel_event; - } - - DWORD sig_n; - if (sig_wait == cw_sig_nosig) - sig_n = WAIT_TIMEOUT + 1; - else - { - sig_n = WAIT_OBJECT_0 + num++; - wait_objects[sig_n] = signal_arrived; - } - - DWORD timeout_n; - if (!timeout) - timeout_n = WAIT_TIMEOUT + 1; - else - { - timeout_n = WAIT_OBJECT_0 + num++; - if (!_my_tls.locals.cw_timer) - NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL, - NotificationTimer); - NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL); - wait_objects[timeout_n] = _my_tls.locals.cw_timer; - } - - while (1) - { - res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE); - if (res == cancel_n) - { - if (cancel_action == cw_cancel_self) - pthread::static_cancel_self (); - res = WAIT_CANCELED; - } - else if (res == timeout_n) - res = WAIT_TIMEOUT; - else if (res != sig_n) - /* all set */; - else if (sig_wait == cw_sig_eintr) - res = WAIT_SIGNALED; - else - { - _my_tls.call_signal_handler (); - continue; - } - break; - } - - if (timeout) - { - TIMER_BASIC_INFORMATION tbi; - - NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi, - sizeof tbi, NULL); - /* if timer expired, TimeRemaining is negative and represents the - system uptime when signalled */ - if (timeout->QuadPart < 0LL) - timeout->QuadPart = tbi.SignalState ? 0LL : tbi.TimeRemaining.QuadPart; - NtCancelTimer (_my_tls.locals.cw_timer, NULL); - } - - return res; -} - int pthread::setcancelstate (int state, int *oldstate) { @@ -1313,7 +1228,7 @@ pthread_cond::wait (pthread_mutex_t mutex, PLARGE_INTEGER timeout) ++mutex->condwaits; mutex->unlock (); - rv = cancelable_wait (sem_wait, timeout, cw_no_cancel_self, cw_sig_eintr); + rv = cancelable_wait (sem_wait, timeout, cw_cancel | cw_sig_eintr); mtx_out.lock (); @@ -1828,7 +1743,8 @@ pthread_mutex::lock () else if (type == PTHREAD_MUTEX_NORMAL /* potentially causes deadlock */ || !pthread::equal (owner, self)) { - cancelable_wait (win32_obj_id, NULL, cw_no_cancel, cw_sig_resume); + /* FIXME: no cancel? */ + cancelable_wait (win32_obj_id, NULL, cw_sig); set_owner (self); } else @@ -1968,7 +1884,8 @@ pthread_spinlock::lock () /* Minimal timeout to minimize CPU usage while still spinning. */ LARGE_INTEGER timeout; timeout.QuadPart = -10000LL; - cancelable_wait (win32_obj_id, &timeout, cw_no_cancel, cw_sig_resume); + /* FIXME: no cancel? */ + cancelable_wait (win32_obj_id, &timeout, cw_sig); } } while (result == -1); @@ -2013,6 +1930,7 @@ pthread::thread_init_wrapper (void *arg) _my_tls.sigmask = thread->parent_sigmask; thread->mutex.unlock (); + debug_printf ("tid %p", &_my_tls); thread_printf ("started thread %p %p %p %p %p %p", arg, &_my_tls.local_clib, _impure_ptr, thread, thread->function, thread->arg); @@ -2446,7 +2364,7 @@ pthread::join (pthread_t *thread, void **return_val) (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; (*thread)->mutex.unlock (); - switch (cancelable_wait ((*thread)->win32_obj_id, NULL, cw_no_cancel_self, cw_sig_resume)) + switch (cancelable_wait ((*thread)->win32_obj_id, NULL, cw_sig | cw_cancel)) { case WAIT_OBJECT_0: if (return_val) @@ -3561,7 +3479,7 @@ semaphore::_timedwait (const struct timespec *abstime) timeout.QuadPart = abstime->tv_sec * NSPERSEC + (abstime->tv_nsec + 99) / 100 + FACTOR; - switch (cancelable_wait (win32_obj_id, &timeout, cw_cancel_self, cw_sig_eintr)) + switch (cancelable_wait (win32_obj_id, &timeout, cw_cancel | cw_cancel_self | cw_sig_eintr)) { case WAIT_OBJECT_0: currentvalue--; @@ -3583,7 +3501,7 @@ semaphore::_timedwait (const struct timespec *abstime) int semaphore::_wait () { - switch (cancelable_wait (win32_obj_id, NULL, cw_cancel_self, cw_sig_eintr)) + switch (cancelable_wait (win32_obj_id, NULL, cw_cancel | cw_cancel_self | cw_sig_eintr)) { case WAIT_OBJECT_0: currentvalue--; diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index ec3ca7ebf..0dd9b893b 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -29,25 +29,7 @@ details. */ #include "security.h" #include #include "cygerrno.h" - -enum cw_sig_wait -{ - cw_sig_nosig, - cw_sig_eintr, - cw_sig_resume -}; - -enum cw_cancel_action -{ - cw_cancel_self, - cw_no_cancel_self, - cw_no_cancel -}; - -DWORD cancelable_wait (HANDLE, PLARGE_INTEGER timeout = NULL, - const cw_cancel_action = cw_cancel_self, - const enum cw_sig_wait = cw_sig_nosig) - __attribute__ ((regparm (3))); +#include "cygwait.h" class fast_mutex { @@ -78,7 +60,7 @@ public: void lock () { if (InterlockedIncrement ((long *) &lock_counter) != 1) - cancelable_wait (win32_obj_id, NULL, cw_no_cancel, cw_sig_resume); + cancelable_wait (win32_obj_id, NULL, cw_sig); } void unlock () diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc index 91a76239a..829c123bd 100644 --- a/winsup/cygwin/wait.cc +++ b/winsup/cygwin/wait.cc @@ -1,7 +1,7 @@ /* wait.cc: Posix wait routines. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2009, 2011 Red Hat, Inc. + 2005, 2009, 2011, 2012 Red Hat, Inc. This file is part of Cygwin. @@ -14,6 +14,7 @@ details. */ #include "sigproc.h" #include "thread.h" #include "cygtls.h" +#include "cygwait.h" /* This is called _wait and not wait because the real wait is defined in libc/syscalls/syswait.c. It calls us. */ @@ -79,7 +80,7 @@ wait4 (int intpid, int *status, int options, struct rusage *r) if ((waitfor = w->ev) == NULL) goto nochildren; - res = cancelable_wait (waitfor); + res = cancelable_wait (waitfor, NULL, cw_cancel | cw_cancel_self); sigproc_printf ("%d = cancelable_wait (...)", res);