Update.
[glibc.git] / linuxthreads / signals.c
blob4a83b14d831c960719030b008ce8d78dd737dfb6
1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
4 /* */
5 /* This program is free software; you can redistribute it and/or */
6 /* modify it under the terms of the GNU Library General Public License */
7 /* as published by the Free Software Foundation; either version 2 */
8 /* of the License, or (at your option) any later version. */
9 /* */
10 /* This program 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 */
13 /* GNU Library General Public License for more details. */
15 /* Handling of signals */
17 #include <errno.h>
18 #include <signal.h>
19 #include "pthread.h"
20 #include "internals.h"
21 #include "spinlock.h"
23 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
25 sigset_t mask;
27 if (newmask != NULL) {
28 mask = *newmask;
29 /* Don't allow PTHREAD_SIG_RESTART to be unmasked.
30 Don't allow PTHREAD_SIG_CANCEL to be masked. */
31 switch(how) {
32 case SIG_SETMASK:
33 sigaddset(&mask, PTHREAD_SIG_RESTART);
34 sigdelset(&mask, PTHREAD_SIG_CANCEL);
35 break;
36 case SIG_BLOCK:
37 sigdelset(&mask, PTHREAD_SIG_CANCEL);
38 break;
39 case SIG_UNBLOCK:
40 sigdelset(&mask, PTHREAD_SIG_RESTART);
41 break;
43 newmask = &mask;
45 if (sigprocmask(how, newmask, oldmask) == -1)
46 return errno;
47 else
48 return 0;
51 int pthread_kill(pthread_t thread, int signo)
53 pthread_handle handle = thread_handle(thread);
54 int pid;
56 __pthread_lock(&handle->h_lock);
57 if (invalid_handle(handle, thread)) {
58 __pthread_unlock(&handle->h_lock);
59 return ESRCH;
61 pid = handle->h_descr->p_pid;
62 __pthread_unlock(&handle->h_lock);
63 if (kill(pid, signo) == -1)
64 return errno;
65 else
66 return 0;
69 /* User-provided signal handlers */
70 static __sighandler_t sighandler[NSIG];
72 /* The wrapper around user-provided signal handlers */
73 static void pthread_sighandler(int signo)
75 pthread_descr self = thread_self();
76 char * in_sighandler;
77 /* If we're in a sigwait operation, just record the signal received
78 and return without calling the user's handler */
79 if (self->p_sigwaiting) {
80 self->p_sigwaiting = 0;
81 self->p_signal = signo;
82 return;
84 /* Record that we're in a signal handler and call the user's
85 handler function */
86 in_sighandler = self->p_in_sighandler;
87 if (in_sighandler == NULL) self->p_in_sighandler = CURRENT_STACK_FRAME;
88 sighandler[signo](signo);
89 if (in_sighandler == NULL) self->p_in_sighandler = NULL;
92 int sigaction(int sig, const struct sigaction * act,
93 struct sigaction * oact)
95 struct sigaction newact;
97 if (sig == PTHREAD_SIG_RESTART || sig == PTHREAD_SIG_CANCEL)
98 return EINVAL;
99 newact = *act;
100 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL)
101 newact.sa_handler = pthread_sighandler;
102 if (__sigaction(sig, &newact, oact) == -1)
103 return -1;
104 if (oact != NULL) oact->sa_handler = sighandler[sig];
105 sighandler[sig] = act->sa_handler;
106 return 0;
109 int sigwait(const sigset_t * set, int * sig)
111 volatile pthread_descr self = thread_self();
112 sigset_t mask;
113 int s;
114 sigjmp_buf jmpbuf;
116 /* Get ready to block all signals except those in set
117 and the cancellation signal */
118 sigfillset(&mask);
119 sigdelset(&mask, PTHREAD_SIG_CANCEL);
120 for (s = 1; s <= NSIG; s++) {
121 if (sigismember(set, s) && s != PTHREAD_SIG_CANCEL)
122 sigdelset(&mask, s);
124 /* Test for cancellation */
125 if (sigsetjmp(jmpbuf, 1) == 0) {
126 self->p_cancel_jmp = &jmpbuf;
127 if (! (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)) {
128 /* Reset the signal count */
129 self->p_signal = 0;
130 /* Say we're in sigwait */
131 self->p_sigwaiting = 1;
132 /* Unblock the signals and wait for them */
133 sigsuspend(&mask);
136 self->p_cancel_jmp = NULL;
137 /* The signals are now reblocked. Check for cancellation */
138 pthread_testcancel();
139 /* We should have self->p_signal != 0 and equal to the signal received */
140 *sig = self->p_signal;
141 return 0;
144 int raise (int sig)
146 int retcode = pthread_kill(pthread_self(), sig);
147 if (retcode == 0)
148 return 0;
149 else {
150 errno = retcode;
151 return -1;