Rename *_priv.* to *P.*
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / sigaction.c
1 /* Copyright (C) 2008 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <inline-syscall.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <ucontext.h>
26 #include <tls.h>
27 #include <assert.h>
28 #include <bits/libc-lock.h>
29 #include <stdio.h>
30 #include <socketP.h>
31
32 static void (*sighandlers[_NSIG])(int, struct siginfo *, void *) = {0};
33 static sigset_t sigmasks[_NSIG];
34 __libc_lock_define_initialized (, signal_lock);
35
36 /* Solaris expects the ucontext_t to be switched back at the end
37   of signal processing; one cannot simply return from the
38   sighandler. As well, Solaris always calls the 3-param version
39   of the handler (i.e. sa_sigaction).  */
40
41 /* Defined in sighandler.c.  */
42 extern void __sighandler(int, siginfo_t *, void *);
43
44 DECLARE_INLINE_SYSCALL (int, sigaction, int signum,
45     const struct sigaction *act, struct sigaction *oldact);
46
47 DECLARE_INLINE_SYSCALL (int64_t, lwp_sigmask, int how, unsigned int bits0,
48     unsigned int bits1);
49
50 int
51 __libc_sigaction (sig, act, oact)
52      int sig;
53      const struct sigaction *act;
54      struct sigaction *oact;
55 {
56   int result;
57
58   if (sig < 0 || sig >= NSIG)
59     {
60       __set_errno (EINVAL);
61       return -1;
62     }
63
64   if (!act && !oact)
65     {
66       __set_errno (EINVAL);
67       return -1;
68     }
69
70   /* Block all signals and lock. */
71   rval_t oldmask;
72   oldmask.rval64 = INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
73       (unsigned int)-1, (unsigned int)-1);
74   __libc_lock_lock (signal_lock);
75
76   void (*old_sigaction)(int, siginfo_t *, void *) = sighandlers[sig];
77   sigset_t old_sigmask = sigmasks[sig];
78   if (act)
79     {
80       struct sigaction _act = *act;
81       if (act->sa_handler != SIG_DFL && act->sa_handler != SIG_IGN)
82         {
83           _act.sa_sigaction = __sighandler;
84           (void)sigfillset (&_act.sa_mask);
85         }
86       result = INLINE_SYSCALL (sigaction, 3, sig, &_act, oact);
87       if (result == 0)
88         {
89           sighandlers[sig] = act->sa_sigaction;
90           sigmasks[sig] = act->sa_mask;
91         }
92     }
93
94   if (oact)
95     {
96       /* If we called sigaction above don't call it again.  */
97       if (!act)
98         result = INLINE_SYSCALL(sigaction, 3, sig, NULL, oact);
99       if (result == 0)
100         {
101           if (oact->sa_handler != SIG_DFL && oact->sa_handler != SIG_IGN)
102             {
103               oact->sa_sigaction = old_sigaction;
104               oact->sa_mask = old_sigmask;
105             }
106         }
107     }
108
109   /* Unlock and restore signals.  */
110   __libc_lock_unlock (signal_lock);
111   (void)INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
112       (unsigned int)oldmask.rval1, (unsigned int)oldmask.rval2);
113
114   return result;
115 }
116
117 libc_hidden_def (__libc_sigaction)
118 #ifndef LIBC_SIGACTION
119 weak_alias (__libc_sigaction, __sigaction)
120 libc_hidden_weak (__sigaction)
121 weak_alias (__libc_sigaction, sigaction)
122 #endif
123
124
125 void __sighandler (int sig, siginfo_t *sip, void *uvp)
126 {
127   assert (sig >= 0 && sig < NSIG);
128
129   if (sig == SIGPIPE && SIGPIPE_IS_DISABLED)
130     return;
131
132   /* All signals are blocked (we passed a filled sa_mask above).  */
133
134   __libc_lock_lock (signal_lock);
135
136   void (*handler)(int, siginfo_t *, void *) = sighandlers[sig];
137   sigset_t mask = sigmasks[sig];
138   ucontext_t *uctx = (ucontext_t*)uvp;
139
140   __libc_lock_unlock (signal_lock);
141
142   /* Set signals to wait sigaction wants.  */
143   (void)INLINE_SYSCALL (lwp_sigmask, 3, SIG_SETMASK,
144       (unsigned int)mask.__sigbits[0], (unsigned int)mask.__sigbits[1]);
145
146   (*handler)(sig, sip, uvp);
147
148   setcontext (uctx);
149   assert (0); /* never reached */
150 }