]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpthread/thread/thr_kill.c
This commit was generated by cvs2svn to compensate for changes in r53696,
[FreeBSD/FreeBSD.git] / lib / libpthread / thread / thr_kill.c
1 /*
2  * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by John Birrell.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 #include <errno.h>
35 #include <signal.h>
36 #ifdef _THREAD_SAFE
37 #include <pthread.h>
38 #include "pthread_private.h"
39
40 int
41 pthread_kill(pthread_t pthread, int sig)
42 {
43         int ret;
44
45         /* Check for invalid signal numbers: */
46         if (sig < 0 || sig >= NSIG)
47                 /* Invalid signal: */
48                 ret = EINVAL;
49
50         /*
51          * Ensure the thread is in the list of active threads, and the
52          * signal is valid (signal 0 specifies error checking only) and
53          * not being ignored:
54          */
55         else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
56             (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
57                 /*
58                  * Defer signals to protect the scheduling queues from
59                  * access by the signal handler:
60                  */
61                 _thread_kern_sig_defer();
62
63                 switch (pthread->state) {
64                 case PS_SIGSUSPEND:
65                         /*
66                          * Only wake up the thread if the signal is unblocked
67                          * and there is a handler installed for the signal.
68                          */
69                         if (!sigismember(&pthread->sigmask, sig) &&
70                             _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
71                                 /* Change the state of the thread to run: */
72                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
73
74                                 /* Return the signal number: */
75                                 pthread->signo = sig;
76                         }
77                         /* Increment the pending signal count: */
78                         sigaddset(&pthread->sigpend,sig);
79                         break;
80
81                 case PS_SIGWAIT:
82                         /* Wake up the thread if the signal is blocked. */
83                         if (sigismember(pthread->data.sigwait, sig)) {
84                                 /* Change the state of the thread to run: */
85                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
86
87                                 /* Return the signal number: */
88                                 pthread->signo = sig;
89                         } else
90                                 /* Increment the pending signal count. */
91                                 sigaddset(&pthread->sigpend,sig);
92                         break;
93
94                 case PS_FDR_WAIT:
95                 case PS_FDW_WAIT:
96                 case PS_POLL_WAIT:
97                 case PS_SLEEP_WAIT:
98                 case PS_SELECT_WAIT:
99                         if (!sigismember(&pthread->sigmask, sig) &&
100                             (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
101                                 /* Flag the operation as interrupted: */
102                                 pthread->interrupted = 1;
103
104                                 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
105                                         PTHREAD_WORKQ_REMOVE(pthread);
106
107                                 /* Change the state of the thread to run: */
108                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
109
110                                 /* Return the signal number: */
111                                 pthread->signo = sig;
112                         } else {
113                                 /* Increment the pending signal count: */
114                                 sigaddset(&pthread->sigpend,sig);
115                         }
116                         break;
117
118                 default:
119                         /* Increment the pending signal count: */
120                         sigaddset(&pthread->sigpend,sig);
121                         break;
122                 }
123
124
125                 /*
126                  * Check that a custom handler is installed
127                  * and if the signal is not blocked:
128                  */
129                 if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
130                     _thread_sigact[sig - 1].sa_handler != SIG_IGN &&
131                     sigismember(&pthread->sigpend, sig) &&
132                     !sigismember(&pthread->sigmask, sig)) {
133                         pthread_t pthread_saved = _thread_run;
134
135                         /* Current thread inside critical region? */
136                         if (_thread_run->sig_defer_count > 0)
137                                 pthread->sig_defer_count++;
138
139                         _thread_run = pthread;
140
141                         /* Clear the pending signal: */
142                         sigdelset(&pthread->sigpend, sig);
143
144                         /*
145                          * Dispatch the signal via the custom signal
146                          * handler:
147                          */
148                         (*(_thread_sigact[sig - 1].sa_handler))(sig);
149
150                         _thread_run = pthread_saved;
151
152                         if (_thread_run->sig_defer_count > 0)
153                                 pthread->sig_defer_count--;
154                 }
155
156                 /*
157                  * Undefer and handle pending signals, yielding if
158                  * necessary:
159                  */
160                 _thread_kern_sig_undefer();
161         }
162
163         /* Return the completion status: */
164         return (ret);
165 }
166 #endif