summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c')
-rw-r--r--sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c
new file mode 100644
index 0000000000..06fbeb93ea
--- /dev/null
+++ b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/sigaction.c
@@ -0,0 +1,155 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <errno.h>
+#include <stddef.h>
+#include <signal.h>
+#include <string.h>
+#include <ucontext.h>
+#include <tls.h>
+#include <assert.h>
+#include <bits/libc-lock.h>
+#include <stdio.h>
+#include <socketP.h>
+
+static void (*sighandlers[_NSIG])(int, struct siginfo *, void *) = {0};
+static sigset_t sigmasks[_NSIG];
+__libc_lock_define_initialized (, signal_lock);
+
+/* Solaris expects the ucontext_t to be switched back at the end
+ of signal processing; one cannot simply return from the
+ sighandler. As well, Solaris always calls the 3-param version
+ of the handler (i.e. sa_sigaction). */
+
+/* Defined in sighandler.c. */
+extern void __sighandler(int, siginfo_t *, void *);
+
+DECLARE_INLINE_SYSCALL (int, sigaction, int signum,
+ const struct sigaction *act, struct sigaction *oldact);
+
+DECLARE_INLINE_SYSCALL (int64_t, lwp_sigmask, int how, unsigned int bits0,
+ unsigned int bits1);
+
+int
+__libc_sigaction (sig, act, oact)
+ int sig;
+ const struct sigaction *act;
+ struct sigaction *oact;
+{
+ int result = -1;
+
+ if (sig < 0 || sig >= NSIG)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ if (!act && !oact)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* Block all signals and lock. */
+ rval_t oldmask;
+ oldmask.rval64 = INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
+ (unsigned int)-1, (unsigned int)-1);
+ __libc_lock_lock (signal_lock);
+
+ void (*old_sigaction)(int, siginfo_t *, void *) = sighandlers[sig];
+ sigset_t old_sigmask = sigmasks[sig];
+ if (act)
+ {
+ struct sigaction _act = *act;
+ if (act->sa_handler != SIG_DFL && act->sa_handler != SIG_IGN)
+ {
+ _act.sa_sigaction = __sighandler;
+ (void)sigfillset (&_act.sa_mask);
+ }
+ result = INLINE_SYSCALL (sigaction, 3, sig, &_act, oact);
+ if (result == 0)
+ {
+ sighandlers[sig] = act->sa_sigaction;
+ sigmasks[sig] = act->sa_mask;
+ }
+ }
+
+ if (oact)
+ {
+ /* If we called sigaction above don't call it again. */
+ if (!act)
+ result = INLINE_SYSCALL(sigaction, 3, sig, NULL, oact);
+ if (result == 0)
+ {
+ if (oact->sa_handler != SIG_DFL && oact->sa_handler != SIG_IGN)
+ {
+ oact->sa_sigaction = old_sigaction;
+ oact->sa_mask = old_sigmask;
+ }
+ }
+ }
+
+ /* Unlock and restore signals. */
+ __libc_lock_unlock (signal_lock);
+ (void)INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
+ (unsigned int)oldmask.rval1, (unsigned int)oldmask.rval2);
+
+ return result;
+}
+
+libc_hidden_def (__libc_sigaction)
+#ifndef LIBC_SIGACTION
+weak_alias (__libc_sigaction, __sigaction)
+libc_hidden_weak (__sigaction)
+weak_alias (__libc_sigaction, sigaction)
+#endif
+
+
+asm (".globl __sighandler_end");
+void __sighandler (int sig, siginfo_t *sip, void *uvp)
+{
+ assert (sig >= 0 && sig < NSIG);
+ ucontext_t *uctx = (ucontext_t*)uvp;
+
+ if (sig == SIGPIPE && SIGPIPE_IS_DISABLED)
+ {
+ setcontext (uctx);
+ assert (0); /* never reached */
+ }
+
+ /* All signals are blocked (we passed a filled sa_mask above). */
+
+ __libc_lock_lock (signal_lock);
+
+ void (*handler)(int, siginfo_t *, void *) = sighandlers[sig];
+ sigset_t mask = sigmasks[sig];
+
+ __libc_lock_unlock (signal_lock);
+
+ /* Set signals to wait sigaction wants. */
+ (void)INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
+ (unsigned int)mask.__sigbits[0], (unsigned int)mask.__sigbits[1]);
+
+ (*handler)(sig, sip, uvp);
+
+ setcontext (uctx);
+ assert (0); /* never reached */
+}
+asm ("__sighandler_end:");