summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
authorraf <none@none>2007-08-06 13:50:45 -0700
committerraf <none@none>2007-08-06 13:50:45 -0700
commitf48068addb8865f9338d23ffbe1043e369df37a1 (patch)
tree4491fa42ed4f6bc8843d62a840b682b769407e96 /usr/src/lib/libc
parentee834aa8ed0c4cc43a04342fe22402b3db18a906 (diff)
downloadillumos-joyent-f48068addb8865f9338d23ffbe1043e369df37a1.tar.gz
6586967 Signal is sometimes not delivered on the alternate stack (although it should)
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/common/sys/__signotify.s19
-rw-r--r--usr/src/lib/libc/port/threads/sigaction.c45
2 files changed, 31 insertions, 33 deletions
diff --git a/usr/src/lib/libc/common/sys/__signotify.s b/usr/src/lib/libc/common/sys/__signotify.s
index 057a00ad45..c46122d074 100644
--- a/usr/src/lib/libc/common/sys/__signotify.s
+++ b/usr/src/lib/libc/common/sys/__signotify.s
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,11 +28,22 @@
.file "%M%"
-/* unpublished system call for POSIX message queues -- __signotify */
-/* int __signotify (int cmd, siginfo_t *siginfo, signotify_id_t *sn_id); */
-
#include "SYS.h"
+/*
+ * Unpublished system call for POSIX message queues.
+ * int __signotify(int cmd, siginfo_t *siginfo, signotify_id_t *sn_id);
+ */
SYSCALL2_RVAL1(__signotify,signotify)
RET
SET_SIZE(__signotify)
+
+/*
+ * Unpublished system call to support deferred signals in libc.
+ * int __sigresend(int sig, siginfo_t *siginfo, sigset_t *mask);
+ */
+ ENTRY(__sigresend)
+ SYSTRAP_RVAL1(sigresend)
+ SYSLWPERR
+ RET
+ SET_SIZE(__sigresend)
diff --git a/usr/src/lib/libc/port/threads/sigaction.c b/usr/src/lib/libc/port/threads/sigaction.c
index 3d8f747100..31cd052c00 100644
--- a/usr/src/lib/libc/port/threads/sigaction.c
+++ b/usr/src/lib/libc/port/threads/sigaction.c
@@ -214,45 +214,32 @@ out:
* We are out of the critical region and are ready to take a signal.
* The kernel has all signals blocked on this lwp, but our value of
* ul_sigmask is the correct signal mask for the previous context.
+ *
+ * We call __sigresend() to atomically restore the signal mask and
+ * cause the signal to be sent again with the remembered siginfo.
+ * We will not return successfully from __sigresend() until the
+ * application's signal handler has been run via sigacthandler().
*/
void
take_deferred_signal(int sig)
{
+ extern int __sigresend(int, siginfo_t *, sigset_t *);
ulwp_t *self = curthread;
- siginfo_t siginfo;
siginfo_t *sip;
- ucontext_t uc;
- volatile int returning;
+ int error;
- ASSERT(self->ul_critical == 0);
- ASSERT(self->ul_sigdefer == 0);
- ASSERT(self->ul_cursig == 0);
+ ASSERT((self->ul_critical | self->ul_sigdefer | self->ul_cursig) == 0);
- returning = 0;
- uc.uc_flags = UC_ALL;
- /*
- * We call _private_getcontext (a libc-private synonym for
- * _getcontext) rather than _getcontext because we need to
- * avoid the dynamic linker and link auditing problems here.
- */
- (void) _private_getcontext(&uc);
- /*
- * If the application signal handler calls setcontext() on
- * the ucontext we give it, it returns here, then we return.
- */
- if (returning)
- return;
- returning = 1;
- ASSERT(sigequalset(&uc.uc_sigmask, &maskset));
if (self->ul_siginfo.si_signo == 0)
sip = NULL;
- else {
- (void) _private_memcpy(&siginfo,
- &self->ul_siginfo, sizeof (siginfo));
- sip = &siginfo;
- }
- uc.uc_sigmask = self->ul_sigmask;
- call_user_handler(sig, sip, &uc);
+ else
+ sip = &self->ul_siginfo;
+
+ /* EAGAIN can happen only for a pending SIGSTOP signal */
+ while ((error = __sigresend(sig, sip, &self->ul_sigmask)) == EAGAIN)
+ continue;
+ if (error)
+ thr_panic("take_deferred_signal(): __sigresend() failed");
}
void