From dccd2abec6c33e0b020ac6ca73f4a74c35833838 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 23 Mar 2006 15:55:59 +0000 Subject: [PATCH] * sigproc.cc (sigalloc): Don't set SA_RESTART here. * signal.cc (_SA_NORESTART): New flag. (sigaction_worker): New function, derived from sigaction. Don't set internal flags unless called internally. (sigaction): Use sigaction_worker. (signal): Honor new _SA_NORESTART flag. (siginterrupt): Set _SA_NORESTART flag appropriately. Use sigaction_worker to set flags. * include/cygwin/signal.h: Define _SA_INTERNAL_MASK here. --- winsup/cygwin/ChangeLog | 12 +++++ winsup/cygwin/include/cygwin/signal.h | 4 ++ winsup/cygwin/signal.cc | 64 ++++++++++++++++++++------- winsup/cygwin/sigproc.cc | 4 -- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c1a7e084d..8ec6f3e1f 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2006-03-23 Christopher Faylor + + * sigproc.cc (sigalloc): Don't set SA_RESTART here. + * signal.cc (_SA_NORESTART): New flag. + (sigaction_worker): New function, derived from sigaction. Don't set + internal flags unless called internally. + (sigaction): Use sigaction_worker. + (signal): Honor new _SA_NORESTART flag. + (siginterrupt): Set _SA_NORESTART flag appropriately. Use + sigaction_worker to set flags. + * include/cygwin/signal.h: Define _SA_INTERNAL_MASK here. + 2006-03-22 Corinna Vinschen * thread.cc (pthread_mutex::is_good_initializer_or_bad_object): Delete. diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h index 0e0aab7d3..1061a7ab1 100644 --- a/winsup/cygwin/include/cygwin/signal.h +++ b/winsup/cygwin/include/cygwin/signal.h @@ -215,6 +215,10 @@ struct sigaction #define SA_ONESHOT SA_RESETHAND /* Historical linux name */ #define SA_NOMASK SA_NODEFER /* Historical linux name */ +/* Used internally by cygwin. Included here to group everything in one place. + Do not use. */ +#define _SA_INTERNAL_MASK 0xf000 /* bits in this range are internal */ + #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt */ #define SIGQUIT 3 /* quit */ diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 6a7edd914..bcaf6edb2 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -28,6 +28,11 @@ details. */ int sigcatchers; /* FIXME: Not thread safe. */ +#define _SA_NORESTART 0x8000 + +static int sigaction_worker (int, const struct sigaction *, struct sigaction *, bool) + __attribute__ ((regparm (3))); + #define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL) static inline void @@ -62,9 +67,16 @@ signal (int sig, _sig_func_ptr func) } prev = global_sigs[sig].sa_handler; - global_sigs[sig].sa_handler = func; - global_sigs[sig].sa_mask = 0; - global_sigs[sig].sa_flags &= ~SA_SIGINFO; + struct sigaction& gs = global_sigs[sig]; + if (gs.sa_flags & _SA_NORESTART) + gs.sa_flags &= ~SA_RESTART; + else + gs.sa_flags |= SA_RESTART; + + gs.sa_mask = 0; + gs.sa_handler = func; + gs.sa_flags &= ~SA_SIGINFO; + set_sigcatchers (prev, func); syscall_printf ("%p = signal (%d, %p)", prev, sig, func); @@ -336,8 +348,8 @@ abort (void) do_exit (SIGABRT); /* signal handler didn't exit. Goodbye. */ } -extern "C" int -sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact) +static int +sigaction_worker (int sig, const struct sigaction *newact, struct sigaction *oldact, bool isinternal) { sig_dispatch_pending (); /* check that sig is in right range */ @@ -361,29 +373,41 @@ sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact) set_errno (EINVAL); return -1; } - struct sigaction& na = global_sigs[sig]; - na = *newact; - if (!(na.sa_flags & SA_NODEFER)) - na.sa_mask |= SIGTOMASK(sig); - if (na.sa_handler == SIG_IGN) + struct sigaction na = *newact; + struct sigaction& gs = global_sigs[sig]; + if (!isinternal) + na.sa_flags &= ~_SA_INTERNAL_MASK; + gs = na; + if (!(gs.sa_flags & SA_NODEFER)) + gs.sa_mask |= SIGTOMASK(sig); + if (gs.sa_handler == SIG_IGN) sig_clear (sig); - if (na.sa_handler == SIG_DFL && sig == SIGCHLD) + if (gs.sa_handler == SIG_DFL && sig == SIGCHLD) sig_clear (sig); - set_sigcatchers (oa.sa_handler, na.sa_handler); + set_sigcatchers (oa.sa_handler, gs.sa_handler); if (sig == SIGCHLD) { myself->process_state &= ~PID_NOCLDSTOP; - if (na.sa_flags & SA_NOCLDSTOP) + if (gs.sa_flags & SA_NOCLDSTOP) myself->process_state |= PID_NOCLDSTOP; } } if (oldact) - *oldact = oa; + { + *oldact = oa; + oa.sa_flags &= ~_SA_INTERNAL_MASK; + } return 0; } +extern "C" int +sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact) +{ + return sigaction_worker (sig, newact, oldact, false); +} + extern "C" int sigaddset (sigset_t *set, const int sig) { @@ -469,10 +493,16 @@ siginterrupt (int sig, int flag) struct sigaction act; sigaction (sig, NULL, &act); if (flag) - act.sa_flags &= ~SA_RESTART; + { + act.sa_flags &= ~SA_RESTART; + act.sa_flags |= _SA_NORESTART; + } else - act.sa_flags |= SA_RESTART; - return sigaction (sig, &act, NULL); + { + act.sa_flags &= ~_SA_NORESTART; + act.sa_flags |= SA_RESTART; + } + return sigaction_worker (sig, &act, NULL, true); } extern "C" int diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 0f927fe89..8de1ff8b9 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -115,10 +115,6 @@ sigalloc () cygheap->sigs = global_sigs = (struct sigaction *) ccalloc (HEAP_SIGS, NSIG, sizeof (struct sigaction)); global_sigs[SIGSTOP].sa_flags = SA_RESTART | SA_NODEFER; - for (int i = 0; i < NSIG; i++) - /* SA_RESTART is set to maintain BSD compatible signal behaviour by default. - This is also compatible with the behaviour of signal(2) in Linux. */ - global_sigs[i].sa_flags = SA_RESTART; } void __stdcall