]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libthr/thread/thr_sig.c
This commit was generated by cvs2svn to compensate for changes in r171577,
[FreeBSD/FreeBSD.git] / lib / libthr / thread / thr_sig.c
1 /*
2  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
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 unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include "namespace.h"
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/signalvar.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <pthread.h>
39 #include "un-namespace.h"
40
41 #include "thr_private.h"
42
43 /* #define DEBUG_SIGNAL */
44 #ifdef DEBUG_SIGNAL
45 #define DBG_MSG         stdout_debug
46 #else
47 #define DBG_MSG(x...)
48 #endif
49
50 extern int      __pause(void);
51 int     ___pause(void);
52 int     _raise(int);
53 int     __sigtimedwait(const sigset_t *set, siginfo_t *info,
54         const struct timespec * timeout);
55 int     __sigwaitinfo(const sigset_t *set, siginfo_t *info);
56 int     __sigwait(const sigset_t *set, int *sig);
57
58 static void
59 sigcancel_handler(int sig __unused,
60         siginfo_t *info __unused, ucontext_t *ucp __unused)
61 {
62         struct pthread *curthread = _get_curthread();
63
64         if (curthread->cancel_defer && curthread->cancel_pending)
65                 thr_wake(curthread->tid);
66         _thr_ast(curthread);
67 }
68
69 void
70 _thr_ast(struct pthread *curthread)
71 {
72         if (!THR_IN_CRITICAL(curthread)) {
73                 _thr_testcancel(curthread);
74                 if (__predict_false((curthread->flags &
75                     (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
76                         == THR_FLAGS_NEED_SUSPEND))
77                         _thr_suspend_check(curthread);
78         }
79 }
80
81 void
82 _thr_suspend_check(struct pthread *curthread)
83 {
84         umtx_t cycle;
85         int err;
86
87         err = errno;
88         /* 
89          * Blocks SIGCANCEL which other threads must send.
90          */
91         _thr_signal_block(curthread);
92
93         /*
94          * Increase critical_count, here we don't use THR_LOCK/UNLOCK
95          * because we are leaf code, we don't want to recursively call
96          * ourself.
97          */
98         curthread->critical_count++;
99         THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
100         while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
101                 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
102                 curthread->cycle++;
103                 cycle = curthread->cycle;
104
105                 /* Wake the thread suspending us. */
106                 _thr_umtx_wake(&curthread->cycle, INT_MAX);
107
108                 /*
109                  * if we are from pthread_exit, we don't want to
110                  * suspend, just go and die.
111                  */
112                 if (curthread->state == PS_DEAD)
113                         break;
114                 curthread->flags |= THR_FLAGS_SUSPENDED;
115                 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
116                 _thr_umtx_wait(&curthread->cycle, cycle, NULL);
117                 THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
118                 curthread->flags &= ~THR_FLAGS_SUSPENDED;
119         }
120         THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
121         curthread->critical_count--;
122
123         /* 
124          * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
125          * a new signal frame will nest us, this seems a problem because 
126          * stack will grow and overflow, but because kernel will automatically
127          * mask the SIGCANCEL when delivering the signal, so we at most only
128          * have one nesting signal frame, this should be fine.
129          */
130         _thr_signal_unblock(curthread);
131         errno = err;
132 }
133
134 void
135 _thr_signal_init(void)
136 {
137         struct sigaction act;
138
139         /* Install cancel handler. */
140         SIGEMPTYSET(act.sa_mask);
141         act.sa_flags = SA_SIGINFO | SA_RESTART;
142         act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
143         __sys_sigaction(SIGCANCEL, &act, NULL);
144 }
145
146 void
147 _thr_signal_deinit(void)
148 {
149 }
150
151 __weak_reference(___pause, pause);
152
153 int
154 ___pause(void)
155 {
156         struct pthread *curthread = _get_curthread();
157         int     ret;
158
159         _thr_cancel_enter(curthread);
160         ret = __pause();
161         _thr_cancel_leave(curthread);
162         
163         return ret;
164 }
165
166 __weak_reference(_raise, raise);
167
168 int
169 _raise(int sig)
170 {
171         int ret;
172
173         if (!_thr_isthreaded())
174                 ret = kill(getpid(), sig);
175         else
176                 ret = _thr_send_sig(_get_curthread(), sig);
177         return (ret);
178 }
179
180 __weak_reference(_sigaction, sigaction);
181
182 int
183 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
184 {
185         /* Check if the signal number is out of range: */
186         if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
187                 /* Return an invalid argument: */
188                 errno = EINVAL;
189                 return (-1);
190         }
191
192         return __sys_sigaction(sig, act, oact);
193 }
194
195 __weak_reference(_sigprocmask, sigprocmask);
196
197 int
198 _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
199 {
200         const sigset_t *p = set;
201         sigset_t newset;
202
203         if (how != SIG_UNBLOCK) {
204                 if (set != NULL) {
205                         newset = *set;
206                         SIGDELSET(newset, SIGCANCEL);
207                         p = &newset;
208                 }
209         }
210         return (__sys_sigprocmask(how, p, oset));
211 }
212
213 __weak_reference(_pthread_sigmask, pthread_sigmask);
214
215 int
216 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
217 {
218         if (_sigprocmask(how, set, oset))
219                 return (errno);
220         return (0);
221 }
222
223 __weak_reference(__sigsuspend, sigsuspend);
224
225 int
226 _sigsuspend(const sigset_t * set)
227 {
228         sigset_t newset;
229         const sigset_t *pset;
230         int ret;
231
232         if (SIGISMEMBER(*set, SIGCANCEL)) {
233                 newset = *set;
234                 SIGDELSET(newset, SIGCANCEL);
235                 pset = &newset;
236         } else
237                 pset = set;
238
239         ret = __sys_sigsuspend(pset);
240
241         return (ret);
242 }
243
244 int
245 __sigsuspend(const sigset_t * set)
246 {
247         struct pthread *curthread = _get_curthread();
248         sigset_t newset;
249         const sigset_t *pset;
250         int ret;
251
252         if (SIGISMEMBER(*set, SIGCANCEL)) {
253                 newset = *set;
254                 SIGDELSET(newset, SIGCANCEL);
255                 pset = &newset;
256         } else
257                 pset = set;
258
259         _thr_cancel_enter(curthread);
260         ret = __sys_sigsuspend(pset);
261         _thr_cancel_leave(curthread);
262
263         return (ret);
264 }
265
266 __weak_reference(__sigwait, sigwait);
267 __weak_reference(__sigtimedwait, sigtimedwait);
268 __weak_reference(__sigwaitinfo, sigwaitinfo);
269
270 int
271 _sigtimedwait(const sigset_t *set, siginfo_t *info,
272         const struct timespec * timeout)
273 {
274         sigset_t newset;
275         const sigset_t *pset;
276         int ret;
277
278         if (SIGISMEMBER(*set, SIGCANCEL)) {
279                 newset = *set;
280                 SIGDELSET(newset, SIGCANCEL);
281                 pset = &newset;
282         } else
283                 pset = set;
284         ret = __sys_sigtimedwait(pset, info, timeout);
285         return (ret);
286 }
287
288 int
289 __sigtimedwait(const sigset_t *set, siginfo_t *info,
290         const struct timespec * timeout)
291 {
292         struct pthread  *curthread = _get_curthread();
293         sigset_t newset;
294         const sigset_t *pset;
295         int ret;
296
297         if (SIGISMEMBER(*set, SIGCANCEL)) {
298                 newset = *set;
299                 SIGDELSET(newset, SIGCANCEL);
300                 pset = &newset;
301         } else
302                 pset = set;
303         _thr_cancel_enter(curthread);
304         ret = __sys_sigtimedwait(pset, info, timeout);
305         _thr_cancel_leave(curthread);
306         return (ret);
307 }
308
309 int
310 _sigwaitinfo(const sigset_t *set, siginfo_t *info)
311 {
312         sigset_t newset;
313         const sigset_t *pset;
314         int ret;
315
316         if (SIGISMEMBER(*set, SIGCANCEL)) {
317                 newset = *set;
318                 SIGDELSET(newset, SIGCANCEL);
319                 pset = &newset;
320         } else
321                 pset = set;
322
323         ret = __sys_sigwaitinfo(pset, info);
324         return (ret);
325 }
326
327 int
328 __sigwaitinfo(const sigset_t *set, siginfo_t *info)
329 {
330         struct pthread  *curthread = _get_curthread();
331         sigset_t newset;
332         const sigset_t *pset;
333         int ret;
334
335         if (SIGISMEMBER(*set, SIGCANCEL)) {
336                 newset = *set;
337                 SIGDELSET(newset, SIGCANCEL);
338                 pset = &newset;
339         } else
340                 pset = set;
341
342         _thr_cancel_enter(curthread);
343         ret = __sys_sigwaitinfo(pset, info);
344         _thr_cancel_leave(curthread);
345         return (ret);
346 }
347
348 int
349 _sigwait(const sigset_t *set, int *sig)
350 {
351         sigset_t newset;
352         const sigset_t *pset;
353         int ret;
354
355         if (SIGISMEMBER(*set, SIGCANCEL)) {
356                 newset = *set;
357                 SIGDELSET(newset, SIGCANCEL);
358                 pset = &newset;
359         } else 
360                 pset = set;
361
362         ret = __sys_sigwait(pset, sig);
363         return (ret);
364 }
365
366 int
367 __sigwait(const sigset_t *set, int *sig)
368 {
369         struct pthread  *curthread = _get_curthread();
370         sigset_t newset;
371         const sigset_t *pset;
372         int ret;
373
374         if (SIGISMEMBER(*set, SIGCANCEL)) {
375                 newset = *set;
376                 SIGDELSET(newset, SIGCANCEL);
377                 pset = &newset;
378         } else 
379                 pset = set;
380
381         _thr_cancel_enter(curthread);
382         ret = __sys_sigwait(pset, sig);
383         _thr_cancel_leave(curthread);
384         return (ret);
385 }