thr_sig.c revision 284493
1222900Snp/*
2296471Snp * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
3296471Snp * All rights reserved.
4222900Snp *
5222900Snp * Redistribution and use in source and binary forms, with or without
6222900Snp * modification, are permitted provided that the following conditions
7222900Snp * are met:
8222900Snp * 1. Redistributions of source code must retain the above copyright
9222900Snp *    notice unmodified, this list of conditions, and the following
10222900Snp *    disclaimer.
11222900Snp * 2. Redistributions in binary form must reproduce the above copyright
12222900Snp *    notice, this list of conditions and the following disclaimer in the
13222900Snp *    documentation and/or other materials provided with the distribution.
14222900Snp *
15222900Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16222900Snp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17222900Snp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18222900Snp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19222900Snp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20222900Snp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21222900Snp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22222900Snp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23222900Snp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24222900Snp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25222900Snp *
26222900Snp * $FreeBSD: stable/10/lib/libthr/thread/thr_sig.c 284493 2015-06-17 04:18:30Z kib $
27222900Snp */
28222900Snp
29222900Snp#include "namespace.h"
30222900Snp#include <sys/param.h>
31222900Snp#include <sys/types.h>
32222900Snp#include <sys/signalvar.h>
33222900Snp#include <signal.h>
34222900Snp#include <errno.h>
35222900Snp#include <stdlib.h>
36222900Snp#include <string.h>
37222900Snp#include <pthread.h>
38222900Snp#include "un-namespace.h"
39222900Snp#include "libc_private.h"
40222900Snp
41222900Snp#include "libc_private.h"
42222900Snp#include "thr_private.h"
43222900Snp
44222900Snp/* #define DEBUG_SIGNAL */
45222900Snp#ifdef DEBUG_SIGNAL
46222900Snp#define DBG_MSG		stdout_debug
47222900Snp#else
48222900Snp#define DBG_MSG(x...)
49222900Snp#endif
50222900Snp
51222900Snpstruct usigaction {
52222900Snp	struct sigaction sigact;
53222900Snp	struct urwlock   lock;
54222900Snp};
55222900Snp
56222900Snpstatic struct usigaction _thr_sigact[_SIG_MAXSIG];
57222900Snp
58222900Snpstatic inline struct usigaction *
59222900Snp__libc_sigaction_slot(int signo)
60222900Snp{
61222900Snp
62222900Snp	return (&_thr_sigact[signo - 1]);
63222900Snp}
64222900Snp
65222900Snpstatic void thr_sighandler(int, siginfo_t *, void *);
66222900Snpstatic void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *);
67222900Snpstatic void check_deferred_signal(struct pthread *);
68222900Snpstatic void check_suspend(struct pthread *);
69222900Snpstatic void check_cancel(struct pthread *curthread, ucontext_t *ucp);
70222900Snp
71222900Snpint	_sigtimedwait(const sigset_t *set, siginfo_t *info,
72222900Snp	const struct timespec * timeout);
73222900Snpint	_sigwaitinfo(const sigset_t *set, siginfo_t *info);
74222900Snpint	_sigwait(const sigset_t *set, int *sig);
75222900Snpint	_setcontext(const ucontext_t *);
76222900Snpint	_swapcontext(ucontext_t *, const ucontext_t *);
77222900Snp
78222900Snpstatic const sigset_t _thr_deferset={{
79222900Snp	0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)|
80222900Snp	_SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)),
81222900Snp	0xffffffff,
82222900Snp	0xffffffff,
83222900Snp	0xffffffff}};
84222900Snp
85222900Snpstatic const sigset_t _thr_maskset={{
86222900Snp	0xffffffff,
87222900Snp	0xffffffff,
88222900Snp	0xffffffff,
89222900Snp	0xffffffff}};
90222900Snp
91222900Snpvoid
92222900Snp_thr_signal_block(struct pthread *curthread)
93222900Snp{
94222900Snp
95222900Snp	if (curthread->sigblock > 0) {
96222900Snp		curthread->sigblock++;
97222900Snp		return;
98222900Snp	}
99222900Snp	__sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask);
100222900Snp	curthread->sigblock++;
101222900Snp}
102222900Snp
103222900Snpvoid
104222900Snp_thr_signal_unblock(struct pthread *curthread)
105222900Snp{
106222900Snp	if (--curthread->sigblock == 0)
107222900Snp		__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
108222900Snp}
109222900Snp
110222900Snpint
111222900Snp_thr_send_sig(struct pthread *thread, int sig)
112222900Snp{
113222900Snp	return thr_kill(thread->tid, sig);
114222900Snp}
115222900Snp
116222900Snpstatic inline void
117222900Snpremove_thr_signals(sigset_t *set)
118222900Snp{
119222900Snp	if (SIGISMEMBER(*set, SIGCANCEL))
120222900Snp		SIGDELSET(*set, SIGCANCEL);
121222900Snp}
122222900Snp
123222900Snpstatic const sigset_t *
124222900Snpthr_remove_thr_signals(const sigset_t *set, sigset_t *newset)
125222900Snp{
126222900Snp	*newset = *set;
127222900Snp	remove_thr_signals(newset);
128222900Snp	return (newset);
129222900Snp}
130222900Snp
131222900Snpstatic void
132222900Snpsigcancel_handler(int sig __unused,
133222900Snp	siginfo_t *info __unused, ucontext_t *ucp)
134222900Snp{
135222900Snp	struct pthread *curthread = _get_curthread();
136222900Snp	int err;
137222900Snp
138222900Snp	if (THR_IN_CRITICAL(curthread))
139222900Snp		return;
140222900Snp	err = errno;
141222900Snp	check_suspend(curthread);
142222900Snp	check_cancel(curthread, ucp);
143222900Snp	errno = err;
144222900Snp}
145222900Snp
146222900Snptypedef void (*ohandler)(int sig, int code, struct sigcontext *scp,
147222900Snp    char *addr, __sighandler_t *catcher);
148222900Snp
149222900Snp/*
150222900Snp * The signal handler wrapper is entered with all signal masked.
151222900Snp */
152222900Snpstatic void
153222900Snpthr_sighandler(int sig, siginfo_t *info, void *_ucp)
154222900Snp{
155222900Snp	struct pthread *curthread;
156222900Snp	ucontext_t *ucp;
157222900Snp	struct sigaction act;
158222900Snp	struct usigaction *usa;
159222900Snp	int err;
160222900Snp
161222900Snp	err = errno;
162222900Snp	curthread = _get_curthread();
163222900Snp	ucp = _ucp;
164222900Snp	usa = __libc_sigaction_slot(sig);
165222900Snp	_thr_rwl_rdlock(&usa->lock);
166222900Snp	act = usa->sigact;
167222900Snp	_thr_rwl_unlock(&usa->lock);
168222900Snp	errno = err;
169222900Snp	curthread->deferred_run = 0;
170222900Snp
171222900Snp	/*
172222900Snp	 * if a thread is in critical region, for example it holds low level locks,
173222900Snp	 * try to defer the signal processing, however if the signal is synchronous
174222900Snp	 * signal, it means a bad thing has happened, this is a programming error,
175222900Snp	 * resuming fault point can not help anything (normally causes deadloop),
176222900Snp	 * so here we let user code handle it immediately.
177222900Snp	 */
178222900Snp	if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) {
179222900Snp		memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction));
180222900Snp		memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t));
181222900Snp		curthread->deferred_sigmask = ucp->uc_sigmask;
182222900Snp		/* mask all signals, we will restore it later. */
183222900Snp		ucp->uc_sigmask = _thr_deferset;
184222900Snp		return;
185222900Snp	}
186222900Snp
187222900Snp	handle_signal(&act, sig, info, ucp);
188222900Snp}
189222900Snp
190222900Snpstatic void
191222900Snphandle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
192222900Snp{
193222900Snp	struct pthread *curthread = _get_curthread();
194222900Snp	ucontext_t uc2;
195222900Snp	__siginfohandler_t *sigfunc;
196222900Snp	int cancel_point;
197222900Snp	int cancel_async;
198222900Snp	int cancel_enable;
199222900Snp	int in_sigsuspend;
200222900Snp	int err;
201222900Snp
202222900Snp	/* add previous level mask */
203222900Snp	SIGSETOR(actp->sa_mask, ucp->uc_sigmask);
204222900Snp
205222900Snp	/* add this signal's mask */
206222900Snp	if (!(actp->sa_flags & SA_NODEFER))
207222900Snp		SIGADDSET(actp->sa_mask, sig);
208222900Snp
209222900Snp	in_sigsuspend = curthread->in_sigsuspend;
210222900Snp	curthread->in_sigsuspend = 0;
211222900Snp
212222900Snp	/*
213222900Snp	 * If thread is in deferred cancellation mode, disable cancellation
214222900Snp	 * in signal handler.
215222900Snp	 * If user signal handler calls a cancellation point function, e.g,
216222900Snp	 * it calls write() to write data to file, because write() is a
217222900Snp	 * cancellation point, the thread is immediately cancelled if
218222900Snp	 * cancellation is pending, to avoid this problem while thread is in
219222900Snp	 * deferring mode, cancellation is temporarily disabled.
220222900Snp	 */
221222900Snp	cancel_point = curthread->cancel_point;
222222900Snp	cancel_async = curthread->cancel_async;
223222900Snp	cancel_enable = curthread->cancel_enable;
224222900Snp	curthread->cancel_point = 0;
225222900Snp	if (!cancel_async)
226222900Snp		curthread->cancel_enable = 0;
227222900Snp
228222900Snp	/* restore correct mask before calling user handler */
229222900Snp	__sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL);
230222900Snp
231222900Snp	sigfunc = actp->sa_sigaction;
232222900Snp
233222900Snp	/*
234222900Snp	 * We have already reset cancellation point flags, so if user's code
235222900Snp	 * longjmp()s out of its signal handler, wish its jmpbuf was set
236222900Snp	 * outside of a cancellation point, in most cases, this would be
237222900Snp	 * true.  However, there is no way to save cancel_enable in jmpbuf,
238222900Snp	 * so after setjmps() returns once more, the user code may need to
239222900Snp	 * re-set cancel_enable flag by calling pthread_setcancelstate().
240222900Snp	 */
241222900Snp	if ((actp->sa_flags & SA_SIGINFO) != 0) {
242222900Snp		sigfunc(sig, info, ucp);
243222900Snp	} else {
244222900Snp		((ohandler)sigfunc)(sig, info->si_code,
245222900Snp		    (struct sigcontext *)ucp, info->si_addr,
246222900Snp		    (__sighandler_t *)sigfunc);
247222900Snp	}
248222900Snp	err = errno;
249222900Snp
250222900Snp	curthread->in_sigsuspend = in_sigsuspend;
251222900Snp	curthread->cancel_point = cancel_point;
252222900Snp	curthread->cancel_enable = cancel_enable;
253222900Snp
254222900Snp	memcpy(&uc2, ucp, sizeof(uc2));
255222900Snp	SIGDELSET(uc2.uc_sigmask, SIGCANCEL);
256222900Snp
257222900Snp	/* reschedule cancellation */
258222900Snp	check_cancel(curthread, &uc2);
259222900Snp	errno = err;
260222900Snp	__sys_sigreturn(&uc2);
261222900Snp}
262222900Snp
263222900Snpvoid
264222900Snp_thr_ast(struct pthread *curthread)
265222900Snp{
266222900Snp
267222900Snp	if (!THR_IN_CRITICAL(curthread)) {
268222900Snp		check_deferred_signal(curthread);
269222900Snp		check_suspend(curthread);
270222900Snp		check_cancel(curthread, NULL);
271222900Snp	}
272222900Snp}
273222900Snp
274222900Snp/* reschedule cancellation */
275222900Snpstatic void
276222900Snpcheck_cancel(struct pthread *curthread, ucontext_t *ucp)
277222900Snp{
278222900Snp
279222900Snp	if (__predict_true(!curthread->cancel_pending ||
280222900Snp	    !curthread->cancel_enable || curthread->no_cancel))
281222900Snp		return;
282222900Snp
283222900Snp	/*
284222900Snp 	 * Otherwise, we are in defer mode, and we are at
285222900Snp	 * cancel point, tell kernel to not block the current
286222900Snp	 * thread on next cancelable system call.
287222900Snp	 *
288222900Snp	 * There are three cases we should call thr_wake() to
289222900Snp	 * turn on TDP_WAKEUP or send SIGCANCEL in kernel:
290222900Snp	 * 1) we are going to call a cancelable system call,
291222900Snp	 *    non-zero cancel_point means we are already in
292222900Snp	 *    cancelable state, next system call is cancelable.
293222900Snp	 * 2) because _thr_ast() may be called by
294222900Snp	 *    THR_CRITICAL_LEAVE() which is used by rtld rwlock
295222900Snp	 *    and any libthr internal locks, when rtld rwlock
296222900Snp	 *    is used, it is mostly caused by an unresolved PLT.
297222900Snp	 *    Those routines may clear the TDP_WAKEUP flag by
298222900Snp	 *    invoking some system calls, in those cases, we
299222900Snp	 *    also should reenable the flag.
300222900Snp	 * 3) thread is in sigsuspend(), and the syscall insists
301222900Snp	 *    on getting a signal before it agrees to return.
302222900Snp 	 */
303222900Snp	if (curthread->cancel_point) {
304222900Snp		if (curthread->in_sigsuspend && ucp) {
305222900Snp			SIGADDSET(ucp->uc_sigmask, SIGCANCEL);
306222900Snp			curthread->unblock_sigcancel = 1;
307222900Snp			_thr_send_sig(curthread, SIGCANCEL);
308222900Snp		} else
309222900Snp			thr_wake(curthread->tid);
310222900Snp	} else if (curthread->cancel_async) {
311222900Snp		/*
312222900Snp		 * asynchronous cancellation mode, act upon
313222900Snp		 * immediately.
314222900Snp		 */
315222900Snp		_pthread_exit_mask(PTHREAD_CANCELED,
316222900Snp		    ucp? &ucp->uc_sigmask : NULL);
317222900Snp	}
318222900Snp}
319222900Snp
320222900Snpstatic void
321222900Snpcheck_deferred_signal(struct pthread *curthread)
322222900Snp{
323222900Snp	ucontext_t *uc;
324222900Snp	struct sigaction act;
325222900Snp	siginfo_t info;
326222900Snp	int uc_len;
327222900Snp
328222900Snp	if (__predict_true(curthread->deferred_siginfo.si_signo == 0 ||
329222900Snp	    curthread->deferred_run))
330222900Snp		return;
331222900Snp
332222900Snp	curthread->deferred_run = 1;
333222900Snp	uc_len = __getcontextx_size();
334222900Snp	uc = alloca(uc_len);
335222900Snp	getcontext(uc);
336222900Snp	if (curthread->deferred_siginfo.si_signo == 0) {
337222900Snp		curthread->deferred_run = 0;
338222900Snp		return;
339222900Snp	}
340222900Snp	__fillcontextx2((char *)uc);
341222900Snp	act = curthread->deferred_sigact;
342222900Snp	uc->uc_sigmask = curthread->deferred_sigmask;
343222900Snp	memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t));
344222900Snp	/* remove signal */
345222900Snp	curthread->deferred_siginfo.si_signo = 0;
346222900Snp	handle_signal(&act, info.si_signo, &info, uc);
347222900Snp}
348222900Snp
349222900Snpstatic void
350222900Snpcheck_suspend(struct pthread *curthread)
351222900Snp{
352222900Snp	uint32_t cycle;
353222900Snp
354222900Snp	if (__predict_true((curthread->flags &
355222900Snp		(THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
356222900Snp		!= THR_FLAGS_NEED_SUSPEND))
357222900Snp		return;
358222900Snp	if (curthread == _single_thread)
359222900Snp		return;
360222900Snp	if (curthread->force_exit)
361222900Snp		return;
362222900Snp
363222900Snp	/*
364222900Snp	 * Blocks SIGCANCEL which other threads must send.
365222900Snp	 */
366222900Snp	_thr_signal_block(curthread);
367222900Snp
368222900Snp	/*
369222900Snp	 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
370222900Snp	 * because we are leaf code, we don't want to recursively call
371222900Snp	 * ourself.
372222900Snp	 */
373222900Snp	curthread->critical_count++;
374222900Snp	THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
375222900Snp	while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
376222900Snp		THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
377222900Snp		curthread->cycle++;
378222900Snp		cycle = curthread->cycle;
379222900Snp
380222900Snp		/* Wake the thread suspending us. */
381222900Snp		_thr_umtx_wake(&curthread->cycle, INT_MAX, 0);
382222900Snp
383222900Snp		/*
384222900Snp		 * if we are from pthread_exit, we don't want to
385222900Snp		 * suspend, just go and die.
386222900Snp		 */
387222900Snp		if (curthread->state == PS_DEAD)
388222900Snp			break;
389222900Snp		curthread->flags |= THR_FLAGS_SUSPENDED;
390222900Snp		THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
391222900Snp		_thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0);
392222900Snp		THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
393222900Snp		curthread->flags &= ~THR_FLAGS_SUSPENDED;
394222900Snp	}
395222900Snp	THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
396222900Snp	curthread->critical_count--;
397222900Snp
398222900Snp	_thr_signal_unblock(curthread);
399222900Snp}
400222900Snp
401222900Snpvoid
402222900Snp_thr_signal_init(int dlopened)
403222900Snp{
404222900Snp	struct sigaction act, nact, oact;
405222900Snp	struct usigaction *usa;
406222900Snp	sigset_t oldset;
407222900Snp	int sig, error;
408222900Snp
409222900Snp	if (dlopened) {
410222900Snp		__sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset);
411222900Snp		for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
412222900Snp			if (sig == SIGCANCEL)
413222900Snp				continue;
414222900Snp			error = __sys_sigaction(sig, NULL, &oact);
415222900Snp			if (error == -1 || oact.sa_handler == SIG_DFL ||
416222900Snp			    oact.sa_handler == SIG_IGN)
417222900Snp				continue;
418222900Snp			usa = __libc_sigaction_slot(sig);
419222900Snp			usa->sigact = oact;
420222900Snp			nact = oact;
421222900Snp			remove_thr_signals(&usa->sigact.sa_mask);
422222900Snp			nact.sa_flags &= ~SA_NODEFER;
423222900Snp			nact.sa_flags |= SA_SIGINFO;
424222900Snp			nact.sa_sigaction = thr_sighandler;
425222900Snp			nact.sa_mask = _thr_maskset;
426222900Snp			(void)__sys_sigaction(sig, &nact, NULL);
427222900Snp		}
428222900Snp		__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
429222900Snp	}
430222900Snp
431222900Snp	/* Install SIGCANCEL handler. */
432222900Snp	SIGFILLSET(act.sa_mask);
433222900Snp	act.sa_flags = SA_SIGINFO;
434222900Snp	act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
435222900Snp	__sys_sigaction(SIGCANCEL, &act, NULL);
436222900Snp
437222900Snp	/* Unblock SIGCANCEL */
438222900Snp	SIGEMPTYSET(act.sa_mask);
439222900Snp	SIGADDSET(act.sa_mask, SIGCANCEL);
440222900Snp	__sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
441222900Snp}
442222900Snp
443222900Snpvoid
444222900Snp_thr_sigact_unload(struct dl_phdr_info *phdr_info)
445222900Snp{
446222900Snp#if 0
447222900Snp	struct pthread *curthread = _get_curthread();
448222900Snp	struct urwlock *rwlp;
449222900Snp	struct sigaction *actp;
450222900Snp	struct usigaction *usa;
451222900Snp	struct sigaction kact;
452222900Snp	void (*handler)(int);
453222900Snp	int sig;
454222900Snp
455222900Snp	_thr_signal_block(curthread);
456222900Snp	for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
457222900Snp		usa = __libc_sigaction_slot(sig);
458222900Snp		actp = &usa->sigact;
459222900Snpretry:
460222900Snp		handler = actp->sa_handler;
461222900Snp		if (handler != SIG_DFL && handler != SIG_IGN &&
462222900Snp		    __elf_phdr_match_addr(phdr_info, handler)) {
463222900Snp			rwlp = &usa->lock;
464222900Snp			_thr_rwl_wrlock(rwlp);
465222900Snp			if (handler != actp->sa_handler) {
466222900Snp				_thr_rwl_unlock(rwlp);
467222900Snp				goto retry;
468222900Snp			}
469222900Snp			actp->sa_handler = SIG_DFL;
470222900Snp			actp->sa_flags = SA_SIGINFO;
471222900Snp			SIGEMPTYSET(actp->sa_mask);
472222900Snp			if (__sys_sigaction(sig, NULL, &kact) == 0 &&
473222900Snp				kact.sa_handler != SIG_DFL &&
474222900Snp				kact.sa_handler != SIG_IGN)
475222900Snp				__sys_sigaction(sig, actp, NULL);
476222900Snp			_thr_rwl_unlock(rwlp);
477222900Snp		}
478222900Snp	}
479222900Snp	_thr_signal_unblock(curthread);
480222900Snp#endif
481222900Snp}
482222900Snp
483222900Snpvoid
484222900Snp_thr_signal_prefork(void)
485222900Snp{
486222900Snp	int i;
487222900Snp
488222900Snp	for (i = 1; i <= _SIG_MAXSIG; ++i)
489222900Snp		_thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock);
490222900Snp}
491222900Snp
492222900Snpvoid
493222900Snp_thr_signal_postfork(void)
494222900Snp{
495222900Snp	int i;
496222900Snp
497222900Snp	for (i = 1; i <= _SIG_MAXSIG; ++i)
498222900Snp		_thr_rwl_unlock(&__libc_sigaction_slot(i)->lock);
499222900Snp}
500222900Snp
501222900Snpvoid
502222900Snp_thr_signal_postfork_child(void)
503222900Snp{
504222900Snp	int i;
505222900Snp
506222900Snp	for (i = 1; i <= _SIG_MAXSIG; ++i) {
507222900Snp		bzero(&__libc_sigaction_slot(i) -> lock,
508222900Snp		    sizeof(struct urwlock));
509222900Snp	}
510222900Snp}
511222900Snp
512222900Snpvoid
513222900Snp_thr_signal_deinit(void)
514222900Snp{
515222900Snp}
516222900Snp
517222900Snpint
518222900Snp__thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
519222900Snp{
520222900Snp	struct sigaction newact, oldact, oldact2;
521222900Snp	sigset_t oldset;
522222900Snp	struct usigaction *usa;
523222900Snp	int ret, err;
524222900Snp
525222900Snp	if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
526222900Snp		errno = EINVAL;
527222900Snp		return (-1);
528222900Snp	}
529222900Snp
530222900Snp	ret = 0;
531222900Snp	err = 0;
532222900Snp	usa = __libc_sigaction_slot(sig);
533222900Snp
534222900Snp	__sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset);
535222900Snp	_thr_rwl_wrlock(&usa->lock);
536222900Snp
537222900Snp	if (act != NULL) {
538222900Snp		oldact2 = usa->sigact;
539222900Snp		newact = *act;
540222900Snp
541222900Snp 		/*
542222900Snp		 * if a new sig handler is SIG_DFL or SIG_IGN,
543222900Snp		 * don't remove old handler from __libc_sigact[],
544222900Snp		 * so deferred signals still can use the handlers,
545222900Snp		 * multiple threads invoking sigaction itself is
546222900Snp		 * a race condition, so it is not a problem.
547222900Snp		 */
548222900Snp		if (newact.sa_handler != SIG_DFL &&
549222900Snp		    newact.sa_handler != SIG_IGN) {
550222900Snp			usa->sigact = newact;
551222900Snp			remove_thr_signals(&usa->sigact.sa_mask);
552222900Snp			newact.sa_flags &= ~SA_NODEFER;
553222900Snp			newact.sa_flags |= SA_SIGINFO;
554222900Snp			newact.sa_sigaction = thr_sighandler;
555222900Snp			newact.sa_mask = _thr_maskset; /* mask all signals */
556222900Snp		}
557222900Snp		ret = __sys_sigaction(sig, &newact, &oldact);
558222900Snp		if (ret == -1) {
559222900Snp			err = errno;
560222900Snp			usa->sigact = oldact2;
561222900Snp		}
562222900Snp	} else if (oact != NULL) {
563222900Snp		ret = __sys_sigaction(sig, NULL, &oldact);
564222900Snp		err = errno;
565222900Snp	}
566222900Snp
567222900Snp	if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) {
568222900Snp		if (act != NULL)
569222900Snp			oldact = oldact2;
570222900Snp		else if (oact != NULL)
571222900Snp			oldact = usa->sigact;
572222900Snp	}
573222900Snp
574222900Snp	_thr_rwl_unlock(&usa->lock);
575222900Snp	__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
576222900Snp
577222900Snp	if (ret == 0) {
578222900Snp		if (oact != NULL)
579222900Snp			*oact = oldact;
580222900Snp	} else {
581222900Snp		errno = err;
582222900Snp	}
583222900Snp	return (ret);
584222900Snp}
585222900Snp
586222900Snpint
587222900Snp__thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
588222900Snp{
589222900Snp	const sigset_t *p = set;
590222900Snp	sigset_t newset;
591222900Snp
592222900Snp	if (how != SIG_UNBLOCK) {
593222900Snp		if (set != NULL) {
594222900Snp			newset = *set;
595222900Snp			SIGDELSET(newset, SIGCANCEL);
596222900Snp			p = &newset;
597222900Snp		}
598222900Snp	}
599222900Snp	return (__sys_sigprocmask(how, p, oset));
600222900Snp}
601222900Snp
602222900Snp__weak_reference(_pthread_sigmask, pthread_sigmask);
603222900Snp
604222900Snpint
605222900Snp_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
606222900Snp{
607222900Snp
608222900Snp	if (__thr_sigprocmask(how, set, oset))
609222900Snp		return (errno);
610222900Snp	return (0);
611222900Snp}
612222900Snp
613222900Snpint
614222900Snp_sigsuspend(const sigset_t * set)
615222900Snp{
616222900Snp	sigset_t newset;
617222900Snp
618222900Snp	return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset)));
619222900Snp}
620222900Snp
621222900Snpint
622222900Snp__thr_sigsuspend(const sigset_t * set)
623222900Snp{
624222900Snp	struct pthread *curthread;
625222900Snp	sigset_t newset;
626222900Snp	int ret, old;
627222900Snp
628222900Snp	curthread = _get_curthread();
629222900Snp
630222900Snp	old = curthread->in_sigsuspend;
631222900Snp	curthread->in_sigsuspend = 1;
632222900Snp	_thr_cancel_enter(curthread);
633222900Snp	ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset));
634222900Snp	_thr_cancel_leave(curthread, 1);
635222900Snp	curthread->in_sigsuspend = old;
636222900Snp	if (curthread->unblock_sigcancel) {
637222900Snp		curthread->unblock_sigcancel = 0;
638222900Snp		SIGEMPTYSET(newset);
639222900Snp		SIGADDSET(newset, SIGCANCEL);
640222900Snp		__sys_sigprocmask(SIG_UNBLOCK, &newset, NULL);
641222900Snp	}
642222900Snp
643222900Snp	return (ret);
644222900Snp}
645222900Snp
646222900Snpint
647222900Snp_sigtimedwait(const sigset_t *set, siginfo_t *info,
648222900Snp	const struct timespec * timeout)
649222900Snp{
650222900Snp	sigset_t newset;
651222900Snp
652222900Snp	return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
653222900Snp	    timeout));
654222900Snp}
655222900Snp
656222900Snp/*
657222900Snp * Cancellation behavior:
658222900Snp *   Thread may be canceled at start, if thread got signal,
659222900Snp *   it is not canceled.
660222900Snp */
661222900Snpint
662222900Snp__thr_sigtimedwait(const sigset_t *set, siginfo_t *info,
663222900Snp    const struct timespec * timeout)
664222900Snp{
665222900Snp	struct pthread	*curthread = _get_curthread();
666222900Snp	sigset_t newset;
667222900Snp	int ret;
668222900Snp
669222900Snp	_thr_cancel_enter(curthread);
670222900Snp	ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
671222900Snp	    timeout);
672222900Snp	_thr_cancel_leave(curthread, (ret == -1));
673222900Snp	return (ret);
674222900Snp}
675222900Snp
676222900Snpint
677222900Snp_sigwaitinfo(const sigset_t *set, siginfo_t *info)
678222900Snp{
679222900Snp	sigset_t newset;
680222900Snp
681222900Snp	return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info));
682222900Snp}
683222900Snp
684222900Snp/*
685222900Snp * Cancellation behavior:
686222900Snp *   Thread may be canceled at start, if thread got signal,
687222900Snp *   it is not canceled.
688222900Snp */
689222900Snpint
690222900Snp__thr_sigwaitinfo(const sigset_t *set, siginfo_t *info)
691222900Snp{
692222900Snp	struct pthread	*curthread = _get_curthread();
693222900Snp	sigset_t newset;
694222900Snp	int ret;
695222900Snp
696222900Snp	_thr_cancel_enter(curthread);
697222900Snp	ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info);
698222900Snp	_thr_cancel_leave(curthread, ret == -1);
699222900Snp	return (ret);
700222900Snp}
701222900Snp
702222900Snpint
703222900Snp_sigwait(const sigset_t *set, int *sig)
704222900Snp{
705222900Snp	sigset_t newset;
706222900Snp
707222900Snp	return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig));
708222900Snp}
709222900Snp
710222900Snp/*
711222900Snp * Cancellation behavior:
712222900Snp *   Thread may be canceled at start, if thread got signal,
713222900Snp *   it is not canceled.
714222900Snp */
715222900Snpint
716222900Snp__thr_sigwait(const sigset_t *set, int *sig)
717222900Snp{
718222900Snp	struct pthread	*curthread = _get_curthread();
719222900Snp	sigset_t newset;
720222900Snp	int ret;
721222900Snp
722222900Snp	do {
723222900Snp		_thr_cancel_enter(curthread);
724222900Snp		ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig);
725222900Snp		_thr_cancel_leave(curthread, (ret != 0));
726222900Snp	} while (ret == EINTR);
727222900Snp	return (ret);
728222900Snp}
729222900Snp
730222900Snpint
731222900Snp__thr_setcontext(const ucontext_t *ucp)
732222900Snp{
733222900Snp	ucontext_t uc;
734222900Snp
735222900Snp	if (ucp == NULL) {
736222900Snp		errno = EINVAL;
737222900Snp		return (-1);
738222900Snp	}
739222900Snp	if (!SIGISMEMBER(uc.uc_sigmask, SIGCANCEL))
740222900Snp		return __sys_setcontext(ucp);
741222900Snp	(void) memcpy(&uc, ucp, sizeof(uc));
742222900Snp	SIGDELSET(uc.uc_sigmask, SIGCANCEL);
743222900Snp	return (__sys_setcontext(&uc));
744222900Snp}
745222900Snp
746222900Snpint
747222900Snp__thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
748222900Snp{
749222900Snp	ucontext_t uc;
750222900Snp
751222900Snp	if (oucp == NULL || ucp == NULL) {
752222900Snp		errno = EINVAL;
753222900Snp		return (-1);
754222900Snp	}
755222900Snp	if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) {
756222900Snp		(void) memcpy(&uc, ucp, sizeof(uc));
757222900Snp		SIGDELSET(uc.uc_sigmask, SIGCANCEL);
758222900Snp		ucp = &uc;
759222900Snp	}
760222900Snp	return (__sys_swapcontext(oucp, ucp));
761222900Snp}
762222900Snp