diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 08339465c..e0361ea60 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2004-02-25 Christopher Faylor + + * exceptions.cc (setup_handler): Signal event for any sigwaitinfo if it + exists to force signal to be handled. Zero event here to prevent + races. + * signal.cc (sigwaitinfo): Use local handle value for everything since + signal thread could zero event element at any time. Detect when + awaking due to thread not in mask and set return value and errno + accordingly. Don't set signal number to zero unless we've recognized + the signal. + * sigproc.cc (sigq): Rename from sigqueue throughout. + + * thread.cc (pthread::join): Handle signals received while waiting for + thread to terminate. + +2004-02-25 Christopher Faylor + + * cygwin.din: Export sighold, sigqueue. + * exceptions.cc (sighold): Define new function. + * signal.cc (handle_sigprocmask): Set correct errno for invalid signal. + Simplify debugging output. + (sigqueue): Define new function. + * include/cygwin/signal.h (sighold): Declare new function. + (sigqueue): Ditto. + * include/cygwin/version.h: Bump API minor version number. + * include/limits.h (TIMER_MAX): Define. + (_POSIX_TIMER_MAX): Ditto. + 2004-02-25 Brian Ford , Corinna Vinschen diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 1a9e47a64..bb322360b 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1225,6 +1225,8 @@ sigaddset SIGFE sigdelset SIGFE sigemptyset NOSIGFE sigfillset NOSIGFE +sighold SIGFE +sigqueue SIGFE siginterrupt SIGFE sigismember SIGFE signal SIGFE diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index f2aec7731..94163fd52 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -813,6 +813,12 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls) out: if (locked) tls->unlock (); + if (interrupted && tls->event) + { + HANDLE h = tls->event; + tls->event = NULL; + SetEvent (h); + } sigproc_printf ("signal %d %sdelivered", sig, interrupted ? "" : "not "); return interrupted; } @@ -906,6 +912,24 @@ set_process_mask (sigset_t newmask) set_signal_mask (newmask); } +extern "C" int +sighold (int sig) +{ + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("signal %d out of range", sig); + return -1; + } + mask_sync->acquire (INFINITE); + sigset_t mask = myself->getsigmask (); + sigaddset (&mask, sig); + set_signal_mask (mask); + mask_sync->release (); + return 0; +} + /* Set the signal mask for this process. Note that some signals are unmaskable, as in UNIX. */ extern "C" void __stdcall diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h index 864ddff7b..90d8df666 100644 --- a/winsup/cygwin/include/cygwin/signal.h +++ b/winsup/cygwin/include/cygwin/signal.h @@ -206,6 +206,8 @@ struct sigaction int sigwait (const sigset_t *, int *); int sigwaitinfo (const sigset_t *, siginfo_t *); +int sighold (int); +int sigqueue(pid_t, int, const union sigval); #ifdef __cplusplus } #endif diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 7a5ee8881..a4d938427 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -236,12 +236,13 @@ details. */ 109: Oh well. Someone uses reent_data. 110: Export clock_gettime, sigwaitinfo, timer_create, timer_delete, timer_settime + 111: Export sigqueue, sighold. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 110 +#define CYGWIN_VERSION_API_MINOR 111 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h index 5d5244384..f32cf5340 100644 --- a/winsup/cygwin/include/limits.h +++ b/winsup/cygwin/include/limits.h @@ -147,6 +147,10 @@ details. */ #undef PIPE_BUF #define PIPE_BUF 4096 +/* Maximum number of timer expiration overruns. */ +#undef TIMER_MAX +#define TIMER_MAX 32 + /* POSIX values */ /* These should never vary from one system type to another */ /* They represent the minimum values that POSIX systems must support. @@ -165,6 +169,7 @@ details. */ #define _POSIX_STREAM_MAX 8 #define _POSIX_TZNAME_MAX 3 #define _POSIX_RTSIG_MAX 8 +#define _POSIX_TIMER_MAX 32 #define RTSIG_MAX _POSIX_RTSIG_MAX diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index b0ac94a79..52c402c49 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -141,8 +141,8 @@ handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& op /* check that sig is in right range */ if (sig < 0 || sig >= NSIG) { - set_errno (ESRCH); - syscall_printf ("SIG_ERR = sigprocmask signal %d out of range", sig); + set_errno (EINVAL); + syscall_printf ("signal %d out of range", sig); return -1; } @@ -493,30 +493,54 @@ sigwaitinfo (const sigset_t *set, siginfo_t *info) pthread_testcancel (); HANDLE h; h = _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); - if (!_my_tls.event) + if (!h) { __seterrno (); return -1; } _my_tls.sigwait_mask = *set; + sig_dispatch_pending (true); int res; - switch (WaitForSingleObject (_my_tls.event, INFINITE)) + switch (WaitForSingleObject (h, INFINITE)) { case WAIT_OBJECT_0: - res = _my_tls.infodata.si_signo; - sigproc_printf ("returning sig %d", res); - if (info) - *info = _my_tls.infodata; + if (!sigismember (set, _my_tls.infodata.si_signo)) + { + set_errno (EINTR); + res = -1; + } + else + { + if (info) + *info = _my_tls.infodata; + res = _my_tls.infodata.si_signo; + InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0); + } break; default: __seterrno (); res = -1; } - _my_tls.event = NULL; - InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0); CloseHandle (h); - sig_dispatch_pending (); + sigproc_printf ("returning sig %d", res); return res; } + +extern "C" int +sigqueue (pid_t pid, int sig, const union sigval value) +{ + siginfo_t si; + pinfo dest (pid); + if (!dest) + { + set_errno (ESRCH); + return -1; + } + si.si_signo = sig; + si.si_code = SI_USER; + si.si_pid = si.si_uid = si.si_errno = 0; + si.si_value = value; + return sig_send (dest, si); +} diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 993b0ec10..f3f04decc 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -66,7 +66,7 @@ public: friend void __stdcall sig_dispatch_pending (bool); }; -static pending_signals sigqueue; +static pending_signals sigq; struct sigaction *global_sigs; @@ -537,15 +537,15 @@ sig_clear (int target_sig) else { sigpacket *q; - sigpacket *save = sigqueue.save (); - sigqueue.reset (); - while ((q = sigqueue.next ())) + sigpacket *save = sigq.save (); + sigq.reset (); + while ((q = sigq.next ())) if (q->si.si_signo == target_sig) { q->si.si_signo = __SIGDELETE; break; } - sigqueue.restore (save); + sigq.restore (save); } return; } @@ -564,11 +564,11 @@ sigpending (sigset_t *mask) void __stdcall sig_dispatch_pending (bool fast) { - if (exit_state || GetCurrentThreadId () == sigtid || !sigqueue.start.next) + if (exit_state || GetCurrentThreadId () == sigtid || !sigq.start.next) { #ifdef DEBUGGING - sigproc_printf ("exit_state %d, cur thread id %p, sigtid %p, sigqueue.start.next %p", - exit_state, GetCurrentThreadId (), sigtid, sigqueue.start.next); + sigproc_printf ("exit_state %d, cur thread id %p, sigtid %p, sigq.start.next %p", + exit_state, GetCurrentThreadId (), sigtid, sigq.start.next); #endif return; } @@ -1156,17 +1156,17 @@ wait_sig (VOID *self) case __SIGPENDING: *pack.mask = 0; unsigned bit; - sigqueue.reset (); - while ((q = sigqueue.next ())) + sigq.reset (); + while ((q = sigq.next ())) if (myself->getsigmask () & (bit = SIGTOMASK (q->si.si_signo))) *pack.mask |= bit; break; case __SIGFLUSH: case __SIGFLUSHFAST: - sigqueue.reset (); - while ((q = sigqueue.next ())) + sigq.reset (); + while ((q = sigq.next ())) if (q->si.si_signo == __SIGDELETE || q->process () > 0) - sigqueue.del (); + sigq.del (); break; default: if (pack.si.si_signo < 0) @@ -1181,7 +1181,7 @@ wait_sig (VOID *self) if (!sigres) system_printf ("Failed to arm signal %d from pid %d", pack.sig, pack.pid); #endif - sigqueue.add (pack); // FIXME: Shouldn't add this in !sh condition + sigq.add (pack); // FIXME: Shouldn't add this in !sh condition } if (sig == SIGCHLD) proc_subproc (PROC_CLEARWAIT, 0); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 7e102fed8..e119129d1 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2181,24 +2181,31 @@ pthread::join (pthread_t *thread, void **return_val) (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; (*thread)->mutex.unlock (); - switch (cancelable_wait ((*thread)->win32_obj_id, INFINITE, false, false)) - { - case WAIT_OBJECT_0: - if (return_val) - *return_val = (*thread)->return_ptr; - delete (*thread); - break; - case WAIT_CANCELED: - // set joined thread back to joinable since we got canceled - (*thread)->joiner = NULL; - (*thread)->attr.joinable = PTHREAD_CREATE_JOINABLE; - joiner->cancel_self (); - // never reached - break; - default: - // should never happen - return EINVAL; - } + bool loop = false; + do + switch (cancelable_wait ((*thread)->win32_obj_id, INFINITE, false, true)) + { + case WAIT_OBJECT_0: + if (return_val) + *return_val = (*thread)->return_ptr; + delete (*thread); + break; + case WAIT_SIGNALED: + _my_tls.call_signal_handler (); + loop = true; + break; + case WAIT_CANCELED: + // set joined thread back to joinable since we got canceled + (*thread)->joiner = NULL; + (*thread)->attr.joinable = PTHREAD_CREATE_JOINABLE; + joiner->cancel_self (); + // never reached + break; + default: + // should never happen + return EINVAL; + } + while (loop); } return 0;