]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libthr/thread/thr_sig.c
MFV r316875: 7336 vfork and O_CLOEXEC causes zfs_mount EBUSY
[FreeBSD/FreeBSD.git] / lib / libthr / thread / thr_sig.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "namespace.h"
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/signalvar.h>
36 #include <sys/syscall.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <pthread.h>
42 #include "un-namespace.h"
43 #include "libc_private.h"
44
45 #include "libc_private.h"
46 #include "thr_private.h"
47
48 /* #define DEBUG_SIGNAL */
49 #ifdef DEBUG_SIGNAL
50 #define DBG_MSG         stdout_debug
51 #else
52 #define DBG_MSG(x...)
53 #endif
54
55 struct usigaction {
56         struct sigaction sigact;
57         struct urwlock   lock;
58 };
59
60 static struct usigaction _thr_sigact[_SIG_MAXSIG];
61
62 static inline struct usigaction *
63 __libc_sigaction_slot(int signo)
64 {
65
66         return (&_thr_sigact[signo - 1]);
67 }
68
69 static void thr_sighandler(int, siginfo_t *, void *);
70 static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *);
71 static void check_deferred_signal(struct pthread *);
72 static void check_suspend(struct pthread *);
73 static void check_cancel(struct pthread *curthread, ucontext_t *ucp);
74
75 int     _sigtimedwait(const sigset_t *set, siginfo_t *info,
76         const struct timespec * timeout);
77 int     _sigwaitinfo(const sigset_t *set, siginfo_t *info);
78 int     _sigwait(const sigset_t *set, int *sig);
79 int     _setcontext(const ucontext_t *);
80 int     _swapcontext(ucontext_t *, const ucontext_t *);
81
82 static const sigset_t _thr_deferset={{
83         0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)|
84         _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)),
85         0xffffffff,
86         0xffffffff,
87         0xffffffff}};
88
89 static const sigset_t _thr_maskset={{
90         0xffffffff,
91         0xffffffff,
92         0xffffffff,
93         0xffffffff}};
94
95 void
96 _thr_signal_block(struct pthread *curthread)
97 {
98         
99         if (curthread->sigblock > 0) {
100                 curthread->sigblock++;
101                 return;
102         }
103         __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask);
104         curthread->sigblock++;
105 }
106
107 void
108 _thr_signal_unblock(struct pthread *curthread)
109 {
110         if (--curthread->sigblock == 0)
111                 __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
112 }
113
114 int
115 _thr_send_sig(struct pthread *thread, int sig)
116 {
117         return thr_kill(thread->tid, sig);
118 }
119
120 static inline void
121 remove_thr_signals(sigset_t *set)
122 {
123         if (SIGISMEMBER(*set, SIGCANCEL))
124                 SIGDELSET(*set, SIGCANCEL);
125 }
126
127 static const sigset_t *
128 thr_remove_thr_signals(const sigset_t *set, sigset_t *newset)
129 {
130         *newset = *set;
131         remove_thr_signals(newset);
132         return (newset);
133 }
134
135 static void
136 sigcancel_handler(int sig __unused,
137         siginfo_t *info __unused, ucontext_t *ucp)
138 {
139         struct pthread *curthread = _get_curthread();
140         int err;
141
142         if (THR_IN_CRITICAL(curthread))
143                 return;
144         err = errno;
145         check_suspend(curthread);
146         check_cancel(curthread, ucp);
147         errno = err;
148 }
149
150 typedef void (*ohandler)(int sig, int code, struct sigcontext *scp,
151     char *addr, __sighandler_t *catcher);
152
153 /*
154  * The signal handler wrapper is entered with all signal masked.
155  */
156 static void
157 thr_sighandler(int sig, siginfo_t *info, void *_ucp)
158 {
159         struct pthread *curthread;
160         ucontext_t *ucp;
161         struct sigaction act;
162         struct usigaction *usa;
163         int err;
164
165         err = errno;
166         curthread = _get_curthread();
167         ucp = _ucp;
168         usa = __libc_sigaction_slot(sig);
169         _thr_rwl_rdlock(&usa->lock);
170         act = usa->sigact;
171         _thr_rwl_unlock(&usa->lock);
172         errno = err;
173         curthread->deferred_run = 0;
174
175         /*
176          * if a thread is in critical region, for example it holds low level locks,
177          * try to defer the signal processing, however if the signal is synchronous
178          * signal, it means a bad thing has happened, this is a programming error,
179          * resuming fault point can not help anything (normally causes deadloop),
180          * so here we let user code handle it immediately.
181          */
182         if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) {
183                 memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction));
184                 memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t));
185                 curthread->deferred_sigmask = ucp->uc_sigmask;
186                 /* mask all signals, we will restore it later. */
187                 ucp->uc_sigmask = _thr_deferset;
188                 return;
189         }
190
191         handle_signal(&act, sig, info, ucp);
192 }
193
194 static void
195 handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
196 {
197         struct pthread *curthread = _get_curthread();
198         ucontext_t uc2;
199         __siginfohandler_t *sigfunc;
200         int cancel_point;
201         int cancel_async;
202         int cancel_enable;
203         int in_sigsuspend;
204         int err;
205
206         /* add previous level mask */
207         SIGSETOR(actp->sa_mask, ucp->uc_sigmask);
208
209         /* add this signal's mask */
210         if (!(actp->sa_flags & SA_NODEFER))
211                 SIGADDSET(actp->sa_mask, sig);
212
213         in_sigsuspend = curthread->in_sigsuspend;
214         curthread->in_sigsuspend = 0;
215
216         /*
217          * If thread is in deferred cancellation mode, disable cancellation
218          * in signal handler.
219          * If user signal handler calls a cancellation point function, e.g,
220          * it calls write() to write data to file, because write() is a
221          * cancellation point, the thread is immediately cancelled if 
222          * cancellation is pending, to avoid this problem while thread is in
223          * deferring mode, cancellation is temporarily disabled.
224          */
225         cancel_point = curthread->cancel_point;
226         cancel_async = curthread->cancel_async;
227         cancel_enable = curthread->cancel_enable;
228         curthread->cancel_point = 0;
229         if (!cancel_async)
230                 curthread->cancel_enable = 0;
231
232         /* restore correct mask before calling user handler */
233         __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL);
234
235         sigfunc = actp->sa_sigaction;
236
237         /*
238          * We have already reset cancellation point flags, so if user's code
239          * longjmp()s out of its signal handler, wish its jmpbuf was set
240          * outside of a cancellation point, in most cases, this would be
241          * true.  However, there is no way to save cancel_enable in jmpbuf,
242          * so after setjmps() returns once more, the user code may need to
243          * re-set cancel_enable flag by calling pthread_setcancelstate().
244          */
245         if ((actp->sa_flags & SA_SIGINFO) != 0) {
246                 sigfunc(sig, info, ucp);
247         } else {
248                 ((ohandler)sigfunc)(sig, info->si_code,
249                     (struct sigcontext *)ucp, info->si_addr,
250                     (__sighandler_t *)sigfunc);
251         }
252         err = errno;
253
254         curthread->in_sigsuspend = in_sigsuspend;
255         curthread->cancel_point = cancel_point;
256         curthread->cancel_enable = cancel_enable;
257
258         memcpy(&uc2, ucp, sizeof(uc2));
259         SIGDELSET(uc2.uc_sigmask, SIGCANCEL);
260
261         /* reschedule cancellation */
262         check_cancel(curthread, &uc2);
263         errno = err;
264         syscall(SYS_sigreturn, &uc2);
265 }
266
267 void
268 _thr_ast(struct pthread *curthread)
269 {
270
271         if (!THR_IN_CRITICAL(curthread)) {
272                 check_deferred_signal(curthread);
273                 check_suspend(curthread);
274                 check_cancel(curthread, NULL);
275         }
276 }
277
278 /* reschedule cancellation */
279 static void
280 check_cancel(struct pthread *curthread, ucontext_t *ucp)
281 {
282
283         if (__predict_true(!curthread->cancel_pending ||
284             !curthread->cancel_enable || curthread->no_cancel))
285                 return;
286
287         /*
288          * Otherwise, we are in defer mode, and we are at
289          * cancel point, tell kernel to not block the current
290          * thread on next cancelable system call.
291          * 
292          * There are three cases we should call thr_wake() to
293          * turn on TDP_WAKEUP or send SIGCANCEL in kernel:
294          * 1) we are going to call a cancelable system call,
295          *    non-zero cancel_point means we are already in
296          *    cancelable state, next system call is cancelable.
297          * 2) because _thr_ast() may be called by
298          *    THR_CRITICAL_LEAVE() which is used by rtld rwlock
299          *    and any libthr internal locks, when rtld rwlock
300          *    is used, it is mostly caused by an unresolved PLT.
301          *    Those routines may clear the TDP_WAKEUP flag by
302          *    invoking some system calls, in those cases, we
303          *    also should reenable the flag.
304          * 3) thread is in sigsuspend(), and the syscall insists
305          *    on getting a signal before it agrees to return.
306          */
307         if (curthread->cancel_point) {
308                 if (curthread->in_sigsuspend && ucp) {
309                         SIGADDSET(ucp->uc_sigmask, SIGCANCEL);
310                         curthread->unblock_sigcancel = 1;
311                         _thr_send_sig(curthread, SIGCANCEL);
312                 } else
313                         thr_wake(curthread->tid);
314         } else if (curthread->cancel_async) {
315                 /*
316                  * asynchronous cancellation mode, act upon
317                  * immediately.
318                  */
319                 _pthread_exit_mask(PTHREAD_CANCELED,
320                     ucp? &ucp->uc_sigmask : NULL);
321         }
322 }
323
324 static void
325 check_deferred_signal(struct pthread *curthread)
326 {
327         ucontext_t *uc;
328         struct sigaction act;
329         siginfo_t info;
330         int uc_len;
331
332         if (__predict_true(curthread->deferred_siginfo.si_signo == 0 ||
333             curthread->deferred_run))
334                 return;
335
336         curthread->deferred_run = 1;
337         uc_len = __getcontextx_size();
338         uc = alloca(uc_len);
339         getcontext(uc);
340         if (curthread->deferred_siginfo.si_signo == 0) {
341                 curthread->deferred_run = 0;
342                 return;
343         }
344         __fillcontextx2((char *)uc);
345         act = curthread->deferred_sigact;
346         uc->uc_sigmask = curthread->deferred_sigmask;
347         memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t));
348         /* remove signal */
349         curthread->deferred_siginfo.si_signo = 0;
350         handle_signal(&act, info.si_signo, &info, uc);
351 }
352
353 static void
354 check_suspend(struct pthread *curthread)
355 {
356         uint32_t cycle;
357
358         if (__predict_true((curthread->flags &
359                 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
360                 != THR_FLAGS_NEED_SUSPEND))
361                 return;
362         if (curthread == _single_thread)
363                 return;
364         if (curthread->force_exit)
365                 return;
366
367         /* 
368          * Blocks SIGCANCEL which other threads must send.
369          */
370         _thr_signal_block(curthread);
371
372         /*
373          * Increase critical_count, here we don't use THR_LOCK/UNLOCK
374          * because we are leaf code, we don't want to recursively call
375          * ourself.
376          */
377         curthread->critical_count++;
378         THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
379         while ((curthread->flags & THR_FLAGS_NEED_SUSPEND) != 0) {
380                 curthread->cycle++;
381                 cycle = curthread->cycle;
382
383                 /* Wake the thread suspending us. */
384                 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0);
385
386                 /*
387                  * if we are from pthread_exit, we don't want to
388                  * suspend, just go and die.
389                  */
390                 if (curthread->state == PS_DEAD)
391                         break;
392                 curthread->flags |= THR_FLAGS_SUSPENDED;
393                 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
394                 _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0);
395                 THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
396         }
397         THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
398         curthread->critical_count--;
399
400         _thr_signal_unblock(curthread);
401 }
402
403 void
404 _thr_signal_init(int dlopened)
405 {
406         struct sigaction act, nact, oact;
407         struct usigaction *usa;
408         sigset_t oldset;
409         int sig, error;
410
411         if (dlopened) {
412                 __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset);
413                 for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
414                         if (sig == SIGCANCEL)
415                                 continue;
416                         error = __sys_sigaction(sig, NULL, &oact);
417                         if (error == -1 || oact.sa_handler == SIG_DFL ||
418                             oact.sa_handler == SIG_IGN)
419                                 continue;
420                         usa = __libc_sigaction_slot(sig);
421                         usa->sigact = oact;
422                         nact = oact;
423                         remove_thr_signals(&usa->sigact.sa_mask);
424                         nact.sa_flags &= ~SA_NODEFER;
425                         nact.sa_flags |= SA_SIGINFO;
426                         nact.sa_sigaction = thr_sighandler;
427                         nact.sa_mask = _thr_maskset;
428                         (void)__sys_sigaction(sig, &nact, NULL);
429                 }
430                 __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
431         }
432
433         /* Install SIGCANCEL handler. */
434         SIGFILLSET(act.sa_mask);
435         act.sa_flags = SA_SIGINFO;
436         act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
437         __sys_sigaction(SIGCANCEL, &act, NULL);
438
439         /* Unblock SIGCANCEL */
440         SIGEMPTYSET(act.sa_mask);
441         SIGADDSET(act.sa_mask, SIGCANCEL);
442         __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
443 }
444
445 void
446 _thr_sigact_unload(struct dl_phdr_info *phdr_info __unused)
447 {
448 #if 0
449         struct pthread *curthread = _get_curthread();
450         struct urwlock *rwlp;
451         struct sigaction *actp;
452         struct usigaction *usa;
453         struct sigaction kact;
454         void (*handler)(int);
455         int sig;
456  
457         _thr_signal_block(curthread);
458         for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
459                 usa = __libc_sigaction_slot(sig);
460                 actp = &usa->sigact;
461 retry:
462                 handler = actp->sa_handler;
463                 if (handler != SIG_DFL && handler != SIG_IGN &&
464                     __elf_phdr_match_addr(phdr_info, handler)) {
465                         rwlp = &usa->lock;
466                         _thr_rwl_wrlock(rwlp);
467                         if (handler != actp->sa_handler) {
468                                 _thr_rwl_unlock(rwlp);
469                                 goto retry;
470                         }
471                         actp->sa_handler = SIG_DFL;
472                         actp->sa_flags = SA_SIGINFO;
473                         SIGEMPTYSET(actp->sa_mask);
474                         if (__sys_sigaction(sig, NULL, &kact) == 0 &&
475                                 kact.sa_handler != SIG_DFL &&
476                                 kact.sa_handler != SIG_IGN)
477                                 __sys_sigaction(sig, actp, NULL);
478                         _thr_rwl_unlock(rwlp);
479                 }
480         }
481         _thr_signal_unblock(curthread);
482 #endif
483 }
484
485 void
486 _thr_signal_prefork(void)
487 {
488         int i;
489
490         for (i = 1; i <= _SIG_MAXSIG; ++i)
491                 _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock);
492 }
493
494 void
495 _thr_signal_postfork(void)
496 {
497         int i;
498
499         for (i = 1; i <= _SIG_MAXSIG; ++i)
500                 _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock);
501 }
502
503 void
504 _thr_signal_postfork_child(void)
505 {
506         int i;
507
508         for (i = 1; i <= _SIG_MAXSIG; ++i) {
509                 bzero(&__libc_sigaction_slot(i) -> lock,
510                     sizeof(struct urwlock));
511         }
512 }
513
514 void
515 _thr_signal_deinit(void)
516 {
517 }
518
519 int
520 __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
521 {
522         struct sigaction newact, oldact, oldact2;
523         sigset_t oldset;
524         struct usigaction *usa;
525         int ret, err;
526
527         if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
528                 errno = EINVAL;
529                 return (-1);
530         }
531
532         ret = 0;
533         err = 0;
534         usa = __libc_sigaction_slot(sig);
535
536         __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset);
537         _thr_rwl_wrlock(&usa->lock);
538  
539         if (act != NULL) {
540                 oldact2 = usa->sigact;
541                 newact = *act;
542
543                 /*
544                  * if a new sig handler is SIG_DFL or SIG_IGN,
545                  * don't remove old handler from __libc_sigact[],
546                  * so deferred signals still can use the handlers,
547                  * multiple threads invoking sigaction itself is
548                  * a race condition, so it is not a problem.
549                  */
550                 if (newact.sa_handler != SIG_DFL &&
551                     newact.sa_handler != SIG_IGN) {
552                         usa->sigact = newact;
553                         remove_thr_signals(&usa->sigact.sa_mask);
554                         newact.sa_flags &= ~SA_NODEFER;
555                         newact.sa_flags |= SA_SIGINFO;
556                         newact.sa_sigaction = thr_sighandler;
557                         newact.sa_mask = _thr_maskset; /* mask all signals */
558                 }
559                 ret = __sys_sigaction(sig, &newact, &oldact);
560                 if (ret == -1) {
561                         err = errno;
562                         usa->sigact = oldact2;
563                 }
564         } else if (oact != NULL) {
565                 ret = __sys_sigaction(sig, NULL, &oldact);
566                 err = errno;
567         }
568
569         if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) {
570                 if (act != NULL)
571                         oldact = oldact2;
572                 else if (oact != NULL)
573                         oldact = usa->sigact;
574         }
575
576         _thr_rwl_unlock(&usa->lock);
577         __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
578
579         if (ret == 0) {
580                 if (oact != NULL)
581                         *oact = oldact;
582         } else {
583                 errno = err;
584         }
585         return (ret);
586 }
587
588 int
589 __thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
590 {
591         const sigset_t *p = set;
592         sigset_t newset;
593
594         if (how != SIG_UNBLOCK) {
595                 if (set != NULL) {
596                         newset = *set;
597                         SIGDELSET(newset, SIGCANCEL);
598                         p = &newset;
599                 }
600         }
601         return (__sys_sigprocmask(how, p, oset));
602 }
603
604 __weak_reference(_pthread_sigmask, pthread_sigmask);
605
606 int
607 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
608 {
609
610         if (__thr_sigprocmask(how, set, oset))
611                 return (errno);
612         return (0);
613 }
614
615 int
616 _sigsuspend(const sigset_t * set)
617 {
618         sigset_t newset;
619
620         return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset)));
621 }
622
623 int
624 __thr_sigsuspend(const sigset_t * set)
625 {
626         struct pthread *curthread;
627         sigset_t newset;
628         int ret, old;
629
630         curthread = _get_curthread();
631
632         old = curthread->in_sigsuspend;
633         curthread->in_sigsuspend = 1;
634         _thr_cancel_enter(curthread);
635         ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset));
636         _thr_cancel_leave(curthread, 1);
637         curthread->in_sigsuspend = old;
638         if (curthread->unblock_sigcancel) {
639                 curthread->unblock_sigcancel = 0;
640                 SIGEMPTYSET(newset);
641                 SIGADDSET(newset, SIGCANCEL);
642                 __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL);
643         }
644
645         return (ret);
646 }
647
648 int
649 _sigtimedwait(const sigset_t *set, siginfo_t *info,
650         const struct timespec * timeout)
651 {
652         sigset_t newset;
653
654         return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
655             timeout));
656 }
657
658 /*
659  * Cancellation behavior:
660  *   Thread may be canceled at start, if thread got signal,
661  *   it is not canceled.
662  */
663 int
664 __thr_sigtimedwait(const sigset_t *set, siginfo_t *info,
665     const struct timespec * timeout)
666 {
667         struct pthread  *curthread = _get_curthread();
668         sigset_t newset;
669         int ret;
670
671         _thr_cancel_enter(curthread);
672         ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
673             timeout);
674         _thr_cancel_leave(curthread, (ret == -1));
675         return (ret);
676 }
677
678 int
679 _sigwaitinfo(const sigset_t *set, siginfo_t *info)
680 {
681         sigset_t newset;
682
683         return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info));
684 }
685
686 /*
687  * Cancellation behavior:
688  *   Thread may be canceled at start, if thread got signal,
689  *   it is not canceled.
690  */ 
691 int
692 __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info)
693 {
694         struct pthread  *curthread = _get_curthread();
695         sigset_t newset;
696         int ret;
697
698         _thr_cancel_enter(curthread);
699         ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info);
700         _thr_cancel_leave(curthread, ret == -1);
701         return (ret);
702 }
703
704 int
705 _sigwait(const sigset_t *set, int *sig)
706 {
707         sigset_t newset;
708
709         return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig));
710 }
711
712 /*
713  * Cancellation behavior:
714  *   Thread may be canceled at start, if thread got signal,
715  *   it is not canceled.
716  */ 
717 int
718 __thr_sigwait(const sigset_t *set, int *sig)
719 {
720         struct pthread  *curthread = _get_curthread();
721         sigset_t newset;
722         int ret;
723
724         do {
725                 _thr_cancel_enter(curthread);
726                 ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig);
727                 _thr_cancel_leave(curthread, (ret != 0));
728         } while (ret == EINTR);
729         return (ret);
730 }
731
732 int
733 __thr_setcontext(const ucontext_t *ucp)
734 {
735         ucontext_t uc;
736
737         if (ucp == NULL) {
738                 errno = EINVAL;
739                 return (-1);
740         }
741         if (!SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL))
742                 return (__sys_setcontext(ucp));
743         (void) memcpy(&uc, ucp, sizeof(uc));
744         SIGDELSET(uc.uc_sigmask, SIGCANCEL);
745         return (__sys_setcontext(&uc));
746 }
747
748 int
749 __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
750 {
751         ucontext_t uc;
752
753         if (oucp == NULL || ucp == NULL) {
754                 errno = EINVAL;
755                 return (-1);
756         }
757         if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) {
758                 (void) memcpy(&uc, ucp, sizeof(uc));
759                 SIGDELSET(uc.uc_sigmask, SIGCANCEL);
760                 ucp = &uc;
761         }
762         return (__sys_swapcontext(oucp, ucp));
763 }