thr_sig.c revision 117366
113546Sjulian/*
235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
1313546Sjulian * 3. All advertising materials mentioning features or use of this software
1413546Sjulian *    must display the following acknowledgement:
1513546Sjulian *	This product includes software developed by John Birrell.
1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1713546Sjulian *    may be used to endorse or promote products derived from this software
1813546Sjulian *    without specific prior written permission.
1913546Sjulian *
2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013546Sjulian * SUCH DAMAGE.
3113546Sjulian *
3250476Speter * $FreeBSD: head/lib/libkse/thread/thr_sig.c 117366 2003-07-09 22:30:55Z davidxu $
3313546Sjulian */
3451794Smarcel#include <sys/param.h>
3551794Smarcel#include <sys/types.h>
3651794Smarcel#include <sys/signalvar.h>
3713546Sjulian#include <signal.h>
38113658Sdeischen#include <errno.h>
3917706Sjulian#include <fcntl.h>
4017706Sjulian#include <unistd.h>
41113658Sdeischen#include <string.h>
4213546Sjulian#include <pthread.h>
43103388Smini#include "thr_private.h"
44113658Sdeischen#include "pthread_md.h"
4513546Sjulian
4654138Sdeischen/* Prototypes: */
47113658Sdeischenstatic void	build_siginfo(siginfo_t *info, int signo);
48113658Sdeischenstatic void	thr_sig_check_state(struct pthread *pthread, int sig);
49113658Sdeischenstatic struct pthread *thr_sig_find(struct kse *curkse, int sig,
50113658Sdeischen		    siginfo_t *info);
51113658Sdeischenstatic void	handle_special_signals(struct kse *curkse, int sig);
52116977Sdavidxustatic void	thr_sigframe_add(struct pthread *thread);
53113658Sdeischenstatic void	thr_sigframe_restore(struct pthread *thread,
54113658Sdeischen		    struct pthread_sigframe *psf);
55113658Sdeischenstatic void	thr_sigframe_save(struct pthread *thread,
56113658Sdeischen		    struct pthread_sigframe *psf);
57111035Smini
58111035Smini/* #define DEBUG_SIGNAL */
5967097Sdeischen#ifdef DEBUG_SIGNAL
6067097Sdeischen#define DBG_MSG		stdout_debug
6167097Sdeischen#else
6267097Sdeischen#define DBG_MSG(x...)
6367097Sdeischen#endif
6456277Sjasone
65111035Smini/*
66113658Sdeischen * Signal setup and delivery.
67113658Sdeischen *
68113658Sdeischen * 1) Delivering signals to threads in the same KSE.
69113658Sdeischen *    These signals are sent by upcall events and are set in the
70113658Sdeischen *    km_sigscaught field of the KSE mailbox.  Since these signals
71113658Sdeischen *    are received while operating on the KSE stack, they can be
72113658Sdeischen *    delivered either by using signalcontext() to add a stack frame
73113658Sdeischen *    to the target thread's stack, or by adding them in the thread's
74113658Sdeischen *    pending set and having the thread run them down after it
75113658Sdeischen * 2) Delivering signals to threads in other KSEs/KSEGs.
76113658Sdeischen * 3) Delivering signals to threads in critical regions.
77113658Sdeischen * 4) Delivering signals to threads after they change their signal masks.
78113658Sdeischen *
79113658Sdeischen * Methods of delivering signals.
80113658Sdeischen *
81113658Sdeischen *   1) Add a signal frame to the thread's saved context.
82113658Sdeischen *   2) Add the signal to the thread structure, mark the thread as
83113658Sdeischen *  	having signals to handle, and let the thread run them down
84113658Sdeischen *  	after it resumes from the KSE scheduler.
85113658Sdeischen *
86113658Sdeischen * Problem with 1).  You can't do this to a running thread or a
87113658Sdeischen * thread in a critical region.
88113658Sdeischen *
89113658Sdeischen * Problem with 2).  You can't do this to a thread that doesn't
90113658Sdeischen * yield in some way (explicitly enters the scheduler).  A thread
91113658Sdeischen * blocked in the kernel or a CPU hungry thread will not see the
92113658Sdeischen * signal without entering the scheduler.
93113658Sdeischen *
94113658Sdeischen * The solution is to use both 1) and 2) to deliver signals:
95113658Sdeischen *
96113658Sdeischen *   o Thread in critical region - use 2).  When the thread
97113658Sdeischen *     leaves the critical region it will check to see if it
98113658Sdeischen *     has pending signals and run them down.
99113658Sdeischen *
100113658Sdeischen *   o Thread enters scheduler explicitly - use 2).  The thread
101113658Sdeischen *     can check for pending signals after it returns from the
102113658Sdeischen *     the scheduler.
103113658Sdeischen *
104113658Sdeischen *   o Thread is running and not current thread - use 2).  When the
105113658Sdeischen *     thread hits a condition specified by one of the other bullets,
106113658Sdeischen *     the signal will be delivered.
107113658Sdeischen *
108113658Sdeischen *   o Thread is running and is current thread (e.g., the thread
109113658Sdeischen *     has just changed its signal mask and now sees that it has
110113658Sdeischen *     pending signals) - just run down the pending signals.
111113658Sdeischen *
112113658Sdeischen *   o Thread is swapped out due to quantum expiration - use 1)
113113658Sdeischen *
114113658Sdeischen *   o Thread is blocked in kernel - kse_thr_wakeup() and then
115113658Sdeischen *     use 1)
116111035Smini */
117113658Sdeischen
118113658Sdeischen/*
119113658Sdeischen * Rules for selecting threads for signals received:
120113658Sdeischen *
121113658Sdeischen *   1) If the signal is a sychronous signal, it is delivered to
122113658Sdeischen *      the generating (current thread).  If the thread has the
123113658Sdeischen *      signal masked, it is added to the threads pending signal
124113658Sdeischen *      set until the thread unmasks it.
125113658Sdeischen *
126113658Sdeischen *   2) A thread in sigwait() where the signal is in the thread's
127113658Sdeischen *      waitset.
128113658Sdeischen *
129113658Sdeischen *   3) A thread in sigsuspend() where the signal is not in the
130113658Sdeischen *      thread's suspended signal mask.
131113658Sdeischen *
132113658Sdeischen *   4) Any thread (first found/easiest to deliver) that has the
133113658Sdeischen *      signal unmasked.
134113658Sdeischen */
135113658Sdeischen
136116977Sdavidxustatic void *
137116977Sdavidxusig_daemon(void *arg /* Unused */)
138116977Sdavidxu{
139116977Sdavidxu	int i;
140116977Sdavidxu	kse_critical_t crit;
141116977Sdavidxu	struct timespec ts;
142116977Sdavidxu	sigset_t set;
143116977Sdavidxu	struct kse *curkse;
144116977Sdavidxu	struct pthread *curthread = _get_curthread();
145116977Sdavidxu
146117301Sdavidxu	DBG_MSG("signal daemon started\n");
147116977Sdavidxu
148116977Sdavidxu	curthread->name = strdup("signal thread");
149116977Sdavidxu	crit = _kse_critical_enter();
150116977Sdavidxu	curkse = _get_curkse();
151116977Sdavidxu	SIGFILLSET(set);
152116977Sdavidxu	__sys_sigprocmask(SIG_SETMASK, &set, NULL);
153116977Sdavidxu	__sys_sigpending(&set);
154116977Sdavidxu	ts.tv_sec = 0;
155116977Sdavidxu	ts.tv_nsec = 0;
156116977Sdavidxu	while (1) {
157116977Sdavidxu		KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
158116977Sdavidxu		_thr_proc_sigpending = set;
159116977Sdavidxu		KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
160116977Sdavidxu		for (i = 1; i <= _SIG_MAXSIG; i++) {
161116977Sdavidxu			if (SIGISMEMBER(set, i) != 0)
162116977Sdavidxu				_thr_sig_dispatch(curkse, i,
163116977Sdavidxu				    NULL /* no siginfo */);
164116977Sdavidxu		}
165116977Sdavidxu		ts.tv_sec = 30;
166116977Sdavidxu		ts.tv_nsec = 0;
167116977Sdavidxu		curkse->k_mbx.km_flags =
168116977Sdavidxu		    KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
169116977Sdavidxu		kse_release(&ts);
170116977Sdavidxu		curkse->k_mbx.km_flags = 0;
171116977Sdavidxu		set = curkse->k_mbx.km_sigscaught;
172116977Sdavidxu	}
173116977Sdavidxu	return (0);
174116977Sdavidxu}
175116977Sdavidxu
176116977Sdavidxu/* Utility function to create signal daemon thread */
177116977Sdavidxuint
178116977Sdavidxu_thr_start_sig_daemon(void)
179116977Sdavidxu{
180116977Sdavidxu	pthread_attr_t attr;
181116977Sdavidxu	sigset_t sigset, oldset;
182116977Sdavidxu
183116977Sdavidxu	SIGFILLSET(sigset);
184116977Sdavidxu	pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
185116977Sdavidxu	pthread_attr_init(&attr);
186116977Sdavidxu	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
187116977Sdavidxu	/* sigmask will be inherited */
188116977Sdavidxu	if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
189116977Sdavidxu		PANIC("can not create signal daemon thread!\n");
190116977Sdavidxu	pthread_attr_destroy(&attr);
191116977Sdavidxu	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
192116977Sdavidxu	return (0);
193116977Sdavidxu}
194116977Sdavidxu
195113658Sdeischen/*
196113658Sdeischen * This signal handler only delivers asynchronous signals.
197113658Sdeischen * This must be called with upcalls disabled and without
198113658Sdeischen * holding any locks.
199113658Sdeischen */
20013546Sjulianvoid
201113658Sdeischen_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
20235509Sjb{
203113658Sdeischen	struct pthread *thread;
20435509Sjb
205113658Sdeischen	DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
20635509Sjb
207113658Sdeischen	/* Some signals need special handling: */
208113658Sdeischen	handle_special_signals(curkse, sig);
209115278Sdeischen	while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
210113658Sdeischen		/*
211113658Sdeischen		 * Setup the target thread to receive the signal:
212113658Sdeischen		 */
213113658Sdeischen		DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread);
214113658Sdeischen		KSE_SCHED_LOCK(curkse, thread->kseg);
215115278Sdeischen		if ((thread->state == PS_DEAD) ||
216115278Sdeischen		    (thread->state == PS_DEADLOCK) ||
217115278Sdeischen		    THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
218115278Sdeischen			KSE_SCHED_UNLOCK(curkse, thread->kseg);
219115278Sdeischen			_thr_ref_delete(NULL, thread);
220117353Sdavidxu		} else if ((thread->state == PS_SIGWAIT &&
221117353Sdavidxu			    SIGISMEMBER(thread->oldsigmask, sig)) ||
222117353Sdavidxu			   (thread->state != PS_SIGWAIT &&
223117353Sdavidxu			    SIGISMEMBER(thread->sigmask, sig))) {
224116061Sdeischen			KSE_SCHED_UNLOCK(curkse, thread->kseg);
225116061Sdeischen			_thr_ref_delete(NULL, thread);
226116977Sdavidxu		} else {
227115278Sdeischen			_thr_sig_add(thread, sig, info);
228115278Sdeischen			KSE_SCHED_UNLOCK(curkse, thread->kseg);
229115278Sdeischen			_thr_ref_delete(NULL, thread);
230115278Sdeischen			break;
231115278Sdeischen		}
232113658Sdeischen	}
233116977Sdavidxu	DBG_MSG("<<< _thr_sig_dispatch\n");
234113658Sdeischen}
235113658Sdeischen
236113658Sdeischenvoid
237113658Sdeischen_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
238113658Sdeischen{
239115381Sdeischen	__siginfohandler_t *sigfunc;
240113658Sdeischen	struct kse *curkse;
241113658Sdeischen
242113658Sdeischen	curkse = _get_curkse();
243113658Sdeischen	if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) {
244113658Sdeischen		/* Upcalls are not yet started; just call the handler. */
245113658Sdeischen		sigfunc = _thread_sigact[sig - 1].sa_sigaction;
246113658Sdeischen		if (((__sighandler_t *)sigfunc != SIG_DFL) &&
247115381Sdeischen		    ((__sighandler_t *)sigfunc != SIG_IGN) &&
248115381Sdeischen		    (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
249113658Sdeischen			if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO)
250113658Sdeischen			    != 0) || (info == NULL))
251113658Sdeischen				(*(sigfunc))(sig, info, ucp);
252113658Sdeischen			else
253116773Smarcel				(*(sigfunc))(sig,
254116773Smarcel				    (siginfo_t*)(intptr_t)info->si_code, ucp);
255113658Sdeischen		}
256113658Sdeischen	}
257113658Sdeischen	else {
258113658Sdeischen		/* Nothing. */
259113658Sdeischen		DBG_MSG("Got signal %d\n", sig);
260116977Sdavidxu		/* XXX Bound thread will fall into this... */
261113658Sdeischen	}
262113658Sdeischen}
263113658Sdeischen
264116977Sdavidxu/* Must be called with signal lock and schedule lock held in order */
265113658Sdeischenstatic void
266113658Sdeischenthr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
267113658Sdeischen    ucontext_t *ucp)
268113658Sdeischen{
269113658Sdeischen	void (*sigfunc)(int, siginfo_t *, void *);
270116977Sdavidxu	sigset_t sigmask;
271116977Sdavidxu	int sa_flags;
272116977Sdavidxu	struct sigaction act;
273116977Sdavidxu	struct kse *curkse;
274113658Sdeischen
275116977Sdavidxu	/*
276116977Sdavidxu	 * Invoke the signal handler without going through the scheduler:
277113658Sdeischen	 */
278113658Sdeischen	DBG_MSG("Got signal %d, calling handler for current thread %p\n",
279113658Sdeischen	    sig, curthread);
280113658Sdeischen
281116977Sdavidxu	if (!_kse_in_critical())
282116977Sdavidxu		PANIC("thr_sig_invoke_handler without in critical\n");
283116977Sdavidxu	curkse = _get_curkse();
28448046Sjb	/*
285113658Sdeischen	 * Check that a custom handler is installed and if
286113658Sdeischen	 * the signal is not blocked:
287113658Sdeischen	 */
288113658Sdeischen	sigfunc = _thread_sigact[sig - 1].sa_sigaction;
289116977Sdavidxu	sa_flags = _thread_sigact[sig - 1].sa_flags & SA_SIGINFO;
290116977Sdavidxu	sigmask = curthread->sigmask;
291116977Sdavidxu	SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
292116977Sdavidxu	if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
293116977Sdavidxu		SIGADDSET(curthread->sigmask, sig);
294116977Sdavidxu	if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
295116977Sdavidxu		if (_thread_dfl_count[sig - 1] == 0) {
296116977Sdavidxu			act.sa_handler = SIG_DFL;
297116977Sdavidxu			act.sa_flags = SA_RESTART;
298116977Sdavidxu			SIGEMPTYSET(act.sa_mask);
299116977Sdavidxu			__sys_sigaction(sig, &act, NULL);
300116977Sdavidxu			__sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
301116977Sdavidxu		}
302116977Sdavidxu	}
303116977Sdavidxu	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
304116977Sdavidxu	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
305116977Sdavidxu	_kse_critical_leave(&curthread->tmbx);
306116977Sdavidxu	ucp->uc_sigmask = sigmask;
307116977Sdavidxu
308113658Sdeischen	if (((__sighandler_t *)sigfunc != SIG_DFL) &&
309113658Sdeischen	    ((__sighandler_t *)sigfunc != SIG_IGN)) {
310116977Sdavidxu		if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
311113658Sdeischen			(*(sigfunc))(sig, info, ucp);
312113658Sdeischen		else
313116773Smarcel			(*(sigfunc))(sig, (siginfo_t*)(intptr_t)info->si_code,
314116773Smarcel			    ucp);
315116977Sdavidxu	} else {
316116977Sdavidxu		/* XXX
317116977Sdavidxu		 * TODO: exit process if signal would kill it.
318116977Sdavidxu		 */
319116977Sdavidxu#ifdef NOTYET
320116977Sdavidxu			if (sigprop(sig) & SA_KILL)
321116977Sdavidxu				kse_sigexit(sig);
322116977Sdavidxu#endif
32367097Sdeischen	}
324116977Sdavidxu	_kse_critical_enter();
325116977Sdavidxu	/* Don't trust after critical leave/enter */
326116977Sdavidxu	curkse = _get_curkse();
327116977Sdavidxu	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
328116977Sdavidxu	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
329113658Sdeischen	/*
330113658Sdeischen	 * Restore the thread's signal mask.
331113658Sdeischen	 */
332116977Sdavidxu	curthread->sigmask = ucp->uc_sigmask;
333116977Sdavidxu
334116977Sdavidxu	DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
33548046Sjb}
33648046Sjb
337116977Sdavidxuint
338116977Sdavidxu_thr_getprocsig(int sig, siginfo_t *siginfo)
339116977Sdavidxu{
340116977Sdavidxu	kse_critical_t crit;
341116977Sdavidxu	struct kse *curkse;
342116977Sdavidxu	int ret;
343116977Sdavidxu
344116977Sdavidxu	DBG_MSG(">>> _thr_getprocsig\n");
345116977Sdavidxu
346116977Sdavidxu	crit = _kse_critical_enter();
347116977Sdavidxu	curkse = _get_curkse();
348116977Sdavidxu	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
349116977Sdavidxu	ret = _thr_getprocsig_unlocked(sig, siginfo);
350116977Sdavidxu	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
351116977Sdavidxu	_kse_critical_leave(crit);
352116977Sdavidxu
353116977Sdavidxu	DBG_MSG("<<< _thr_getprocsig\n");
354116977Sdavidxu	return (ret);
355116977Sdavidxu}
356116977Sdavidxu
357116977Sdavidxuint
358116977Sdavidxu_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
359116977Sdavidxu{
360116977Sdavidxu	sigset_t sigset;
361116977Sdavidxu	struct timespec ts;
362116977Sdavidxu
363116977Sdavidxu	/* try to retrieve signal from kernel */
364116977Sdavidxu	SIGEMPTYSET(sigset);
365116977Sdavidxu	SIGADDSET(sigset, sig);
366116977Sdavidxu	ts.tv_sec = 0;
367116977Sdavidxu	ts.tv_nsec = 0;
368116977Sdavidxu	if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) {
369116977Sdavidxu		SIGDELSET(_thr_proc_sigpending, sig);
370116977Sdavidxu		return (sig);
371116977Sdavidxu	}
372116977Sdavidxu	return (0);
373116977Sdavidxu}
374116977Sdavidxu
37567097Sdeischen/*
376113658Sdeischen * Find a thread that can handle the signal.  This must be called
377113658Sdeischen * with upcalls disabled.
37867097Sdeischen */
379113658Sdeischenstruct pthread *
380113658Sdeischenthr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
38148046Sjb{
382114180Sdeischen	struct pthread	*pthread;
38390431Sdeischen	struct pthread	*suspended_thread, *signaled_thread;
384116977Sdavidxu	siginfo_t si;
38548046Sjb
38667097Sdeischen	DBG_MSG("Looking for thread to handle signal %d\n", sig);
387113658Sdeischen
38848046Sjb	/* Check if the signal requires a dump of thread information: */
38968516Sdeischen	if (sig == SIGINFO) {
39048046Sjb		/* Dump thread information to file: */
39148046Sjb		_thread_dump_info();
39268516Sdeischen	}
393111035Smini	/*
394111035Smini	 * Enter a loop to look for threads that have the signal
395111035Smini	 * unmasked.  POSIX specifies that a thread in a sigwait
396111035Smini	 * will get the signal over any other threads.  Second
397111035Smini	 * preference will be threads in in a sigsuspend.  Third
398111035Smini	 * preference will be the current thread.  If none of the
399111035Smini	 * above, then the signal is delivered to the first thread
400111035Smini	 * that is found.  Note that if a custom handler is not
401111035Smini	 * installed, the signal only affects threads in sigwait.
402111035Smini	 */
403111035Smini	suspended_thread = NULL;
404113658Sdeischen	signaled_thread = NULL;
405111035Smini
406113658Sdeischen	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
407114180Sdeischen	TAILQ_FOREACH(pthread, &_thread_list, tle) {
408116977Sdavidxu		if (pthread == _thr_sig_daemon)
409116977Sdavidxu			continue;
410116977Sdavidxu#ifdef NOTYET
411116977Sdavidxu		/* Signal delivering to bound thread is done by kernel */
412116977Sdavidxu		if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
413116977Sdavidxu			continue;
414116977Sdavidxu#endif
415116977Sdavidxu
416114254Sdeischen		/* Take the scheduling lock. */
417114254Sdeischen		KSE_SCHED_LOCK(curkse, pthread->kseg);
418116977Sdavidxu		if ((pthread->state == PS_DEAD)		||
419116977Sdavidxu		    (pthread->state == PS_DEADLOCK)	||
420116977Sdavidxu		    THR_IS_EXITING(pthread)		||
421117353Sdavidxu		    THR_IS_SUSPENDED(pthread)) {
422116977Sdavidxu			; /* Skip this thread. */
423117353Sdavidxu		} else if (pthread->state == PS_SIGWAIT &&
424117353Sdavidxu			   !SIGISMEMBER(pthread->sigmask, sig)) {
42548046Sjb			/*
426116977Sdavidxu			 * retrieve signal from kernel, if it is job control
427116977Sdavidxu			 * signal, and sigaction is SIG_DFL, then we will
428116977Sdavidxu			 * be stopped in kernel, we hold lock here, but that
429116977Sdavidxu			 * does not matter, because that's job control, and
430116977Sdavidxu			 * whole process should be stopped.
43148046Sjb			 */
432116977Sdavidxu			if (_thr_getprocsig(sig, &si)) {
433116977Sdavidxu				DBG_MSG("Waking thread %p in sigwait"
434116977Sdavidxu					" with signal %d\n", pthread, sig);
435116977Sdavidxu				/*  where to put siginfo ? */
436116977Sdavidxu				*(pthread->data.sigwaitinfo) = si;
437116977Sdavidxu				pthread->sigmask = pthread->oldsigmask;
438116977Sdavidxu				_thr_setrunnable_unlocked(pthread);
439116977Sdavidxu			}
440113658Sdeischen			KSE_SCHED_UNLOCK(curkse, pthread->kseg);
441111035Smini			/*
442111035Smini			 * POSIX doesn't doesn't specify which thread
443111035Smini			 * will get the signal if there are multiple
444111035Smini			 * waiters, so we give it to the first thread
445111035Smini			 * we find.
446111035Smini			 *
447111035Smini			 * Do not attempt to deliver this signal
448111035Smini			 * to other threads and do not add the signal
449111035Smini			 * to the process pending set.
450111035Smini			 */
451113658Sdeischen			KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
452111035Smini			return (NULL);
453117353Sdavidxu		} else if (!SIGISMEMBER(pthread->sigmask, sig) ||
454117353Sdavidxu			(!SIGISMEMBER(pthread->oldsigmask, sig) &&
455117353Sdavidxu			 pthread->state == PS_SIGWAIT)) {
456111035Smini			if (pthread->state == PS_SIGSUSPEND) {
457115278Sdeischen				if (suspended_thread == NULL) {
458111035Smini					suspended_thread = pthread;
459115278Sdeischen					suspended_thread->refcount++;
460115278Sdeischen				}
461115278Sdeischen			} else if (signaled_thread == NULL) {
462111035Smini				signaled_thread = pthread;
463115278Sdeischen				signaled_thread->refcount++;
464116977Sdavidxu			}
465111035Smini		}
466114254Sdeischen		KSE_SCHED_UNLOCK(curkse, pthread->kseg);
467111035Smini	}
468113658Sdeischen	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
46939805Sjb
470116977Sdavidxu	if (suspended_thread != NULL) {
471116977Sdavidxu		pthread = suspended_thread;
472116977Sdavidxu		if (signaled_thread)
473116977Sdavidxu			_thr_ref_delete(NULL, signaled_thread);
474116977Sdavidxu	} else if (signaled_thread) {
475116977Sdavidxu		pthread = signaled_thread;
476113658Sdeischen	} else {
477116977Sdavidxu		pthread = NULL;
478111035Smini	}
479116977Sdavidxu	return (pthread);
48035509Sjb}
48135509Sjb
482113658Sdeischenstatic void
483113658Sdeischenbuild_siginfo(siginfo_t *info, int signo)
484113658Sdeischen{
485113658Sdeischen	bzero(info, sizeof(*info));
486113658Sdeischen	info->si_signo = signo;
487113658Sdeischen	info->si_pid = _thr_pid;
488113658Sdeischen}
489113658Sdeischen
490113658Sdeischen/*
491113658Sdeischen * This is called by a thread when it has pending signals to deliver.
492113658Sdeischen * It should only be called from the context of the thread.
493113658Sdeischen */
49467097Sdeischenvoid
495113658Sdeischen_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
496113658Sdeischen    struct pthread_sigframe *psf)
49756277Sjasone{
498117353Sdavidxu	int interrupted = curthread->interrupted;
499117353Sdavidxu	int timeout = curthread->timeout;
500116977Sdavidxu	siginfo_t siginfo;
501113658Sdeischen	int i;
502116977Sdavidxu	kse_critical_t crit;
503116977Sdavidxu	struct kse *curkse;
50467097Sdeischen
505116977Sdavidxu	DBG_MSG(">>> thr_sig_rundown %p\n", curthread);
506113658Sdeischen	/* Check the threads previous state: */
507116977Sdavidxu	if ((psf != NULL) && (psf->psf_valid != 0)) {
508113658Sdeischen		/*
509113658Sdeischen		 * Do a little cleanup handling for those threads in
510113658Sdeischen		 * queues before calling the signal handler.  Signals
511113658Sdeischen		 * for these threads are temporarily blocked until
512113658Sdeischen		 * after cleanup handling.
513113658Sdeischen		 */
514116977Sdavidxu		switch (psf->psf_state) {
515113658Sdeischen		case PS_COND_WAIT:
516113658Sdeischen			_cond_wait_backout(curthread);
517116977Sdavidxu			psf->psf_state = PS_RUNNING;
518113658Sdeischen			break;
519113658Sdeischen
520113658Sdeischen		case PS_MUTEX_WAIT:
521113658Sdeischen			_mutex_lock_backout(curthread);
522116977Sdavidxu			psf->psf_state = PS_RUNNING;
523113658Sdeischen			break;
524113658Sdeischen
525116977Sdavidxu		case PS_RUNNING:
526116977Sdavidxu			break;
527116977Sdavidxu
528113658Sdeischen		default:
529116977Sdavidxu			psf->psf_state = PS_RUNNING;
530113658Sdeischen			break;
531113658Sdeischen		}
532116977Sdavidxu		/* XXX see comment in thr_sched_switch_unlocked */
533116977Sdavidxu		curthread->critical_count--;
534113658Sdeischen	}
535116977Sdavidxu
53656277Sjasone	/*
537113658Sdeischen	 * Lower the priority before calling the handler in case
538113658Sdeischen	 * it never returns (longjmps back):
53956277Sjasone	 */
540116977Sdavidxu	crit = _kse_critical_enter();
541116977Sdavidxu	curkse = _get_curkse();
542116977Sdavidxu	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
543116977Sdavidxu	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
544113658Sdeischen	curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
545113658Sdeischen
546116977Sdavidxu	while (1) {
547116977Sdavidxu		for (i = 1; i <= _SIG_MAXSIG; i++) {
548116977Sdavidxu			if (SIGISMEMBER(curthread->sigmask, i))
549116977Sdavidxu				continue;
550116977Sdavidxu			if (SIGISMEMBER(curthread->sigpend, i)) {
551116977Sdavidxu				SIGDELSET(curthread->sigpend, i);
552117066Sdavidxu				siginfo = curthread->siginfo[i-1];
553116977Sdavidxu				break;
554116977Sdavidxu			}
555116977Sdavidxu			if (SIGISMEMBER(_thr_proc_sigpending, i)) {
556116977Sdavidxu				if (_thr_getprocsig_unlocked(i, &siginfo))
557116977Sdavidxu					break;
558116977Sdavidxu			}
55967097Sdeischen		}
560116977Sdavidxu		if (i <= _SIG_MAXSIG)
561116977Sdavidxu			thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
562116977Sdavidxu		else
563116977Sdavidxu			break;
56456277Sjasone	}
565113658Sdeischen
566116977Sdavidxu	if (psf != NULL && psf->psf_valid != 0)
567116977Sdavidxu		thr_sigframe_restore(curthread, psf);
568116977Sdavidxu	curkse = _get_curkse();
569116977Sdavidxu	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
570116977Sdavidxu	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
571116977Sdavidxu	_kse_critical_leave(&curthread->tmbx);
572116977Sdavidxu
573117353Sdavidxu	curthread->interrupted = interrupted;
574117353Sdavidxu	curthread->timeout = timeout;
575117353Sdavidxu
576116977Sdavidxu	DBG_MSG("<<< thr_sig_rundown %p\n", curthread);
57767097Sdeischen}
57867097Sdeischen
57967097Sdeischen/*
580113658Sdeischen * This checks pending signals for the current thread.  It should be
581113658Sdeischen * called whenever a thread changes its signal mask.  Note that this
582113658Sdeischen * is called from a thread (using its stack).
583113658Sdeischen *
584113658Sdeischen * XXX - We might want to just check to see if there are pending
585113658Sdeischen *       signals for the thread here, but enter the UTS scheduler
586113658Sdeischen *       to actually install the signal handler(s).
58767097Sdeischen */
58867097Sdeischenvoid
589113658Sdeischen_thr_sig_check_pending(struct pthread *curthread)
59067097Sdeischen{
591116977Sdavidxu	ucontext_t uc;
592116977Sdavidxu	volatile int once;
59367097Sdeischen
594116977Sdavidxu	if (THR_IN_CRITICAL(curthread))
595116977Sdavidxu		return;
596113658Sdeischen
597116977Sdavidxu	once = 0;
598116977Sdavidxu	THR_GETCONTEXT(&uc);
599116977Sdavidxu	if (once == 0) {
600116977Sdavidxu		once = 1;
601113658Sdeischen		curthread->check_pending = 0;
602116977Sdavidxu		_thr_sig_rundown(curthread, &uc, NULL);
60356277Sjasone	}
60456277Sjasone}
60556277Sjasone
606111035Smini/*
607113658Sdeischen * This must be called with upcalls disabled.
608111035Smini */
60956277Sjasonestatic void
610113658Sdeischenhandle_special_signals(struct kse *curkse, int sig)
61156277Sjasone{
61267097Sdeischen	switch (sig) {
61367097Sdeischen	/*
61467097Sdeischen	 * POSIX says that pending SIGCONT signals are
61567097Sdeischen	 * discarded when one of these signals occurs.
61667097Sdeischen	 */
61767097Sdeischen	case SIGTSTP:
61867097Sdeischen	case SIGTTIN:
61967097Sdeischen	case SIGTTOU:
620113658Sdeischen		KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
621116977Sdavidxu		SIGDELSET(_thr_proc_sigpending, SIGCONT);
622113658Sdeischen		KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
62367097Sdeischen		break;
624116977Sdavidxu	case SIGCONT:
625116977Sdavidxu		KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
626116977Sdavidxu		SIGDELSET(_thr_proc_sigpending, SIGTSTP);
627116977Sdavidxu		SIGDELSET(_thr_proc_sigpending, SIGTTIN);
628116977Sdavidxu		SIGDELSET(_thr_proc_sigpending, SIGTTOU);
629116977Sdavidxu		KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
63067097Sdeischen	default:
63167097Sdeischen		break;
63256277Sjasone	}
63356277Sjasone}
63456277Sjasone
63567097Sdeischen/*
63667097Sdeischen * Perform thread specific actions in response to a signal.
63767097Sdeischen * This function is only called if there is a handler installed
63867097Sdeischen * for the signal, and if the target thread has the signal
63967097Sdeischen * unmasked.
640113658Sdeischen *
641113658Sdeischen * This must be called with the thread's scheduling lock held.
64267097Sdeischen */
643115080Sdeischenvoid
644115080Sdeischen_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
64535509Sjb{
646113658Sdeischen	int	restart;
64767097Sdeischen	int	suppress_handler = 0;
648116977Sdavidxu	int	fromproc = 0;
649116977Sdavidxu	struct  pthread *curthread = _get_curthread();
650116977Sdavidxu	struct	kse *curkse;
651116977Sdavidxu	siginfo_t siginfo;
65267097Sdeischen
653116977Sdavidxu	DBG_MSG(">>> _thr_sig_add\n");
654116977Sdavidxu
655116977Sdavidxu	curkse = _get_curkse();
656116977Sdavidxu	restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
657116977Sdavidxu	fromproc = (curthread == _thr_sig_daemon);
658116977Sdavidxu
659116977Sdavidxu	if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
660116977Sdavidxu	    pthread->state == PS_STATE_MAX)
661116977Sdavidxu	    	return; /* return false */
662116977Sdavidxu
663116977Sdavidxu#ifdef NOTYET
664116977Sdavidxu	if ((pthread->attrs.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
665116977Sdavidxu		if (!fromproc)
666116977Sdavidxu			kse_thr_interrupt(&pthread->tmbx, 0, sig);
667116977Sdavidxu		return;
668115080Sdeischen	}
669116977Sdavidxu#endif
670116977Sdavidxu
671116977Sdavidxu	if (pthread->curframe == NULL ||
672117353Sdavidxu	    (pthread->state != PS_SIGWAIT &&
673117353Sdavidxu	    SIGISMEMBER(pthread->sigmask, sig)) ||
674116977Sdavidxu	    THR_IN_CRITICAL(pthread)) {
675116977Sdavidxu		/* thread is running or signal was being masked */
676116977Sdavidxu		if (!fromproc) {
677116977Sdavidxu			SIGADDSET(pthread->sigpend, sig);
678116977Sdavidxu			if (info == NULL)
679117066Sdavidxu				build_siginfo(&pthread->siginfo[sig-1], sig);
680117066Sdavidxu			else if (info != &pthread->siginfo[sig-1])
681117066Sdavidxu				memcpy(&pthread->siginfo[sig-1], info,
682116977Sdavidxu					 sizeof(*info));
683116977Sdavidxu		} else {
684117066Sdavidxu			if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1]))
685116977Sdavidxu				return;
686116977Sdavidxu			SIGADDSET(pthread->sigpend, sig);
687116977Sdavidxu		}
688116977Sdavidxu		if (!SIGISMEMBER(pthread->sigmask, sig)) {
689116977Sdavidxu			pthread->check_pending = 1;
690116977Sdavidxu			if (pthread->blocked != 0 && !THR_IN_CRITICAL(pthread))
691116977Sdavidxu				kse_thr_interrupt(&pthread->tmbx,
692116977Sdavidxu					 restart ? -2 : -1);
693116977Sdavidxu		}
694116977Sdavidxu	}
695115080Sdeischen	else {
696116977Sdavidxu		/* if process signal not exists, just return */
697116977Sdavidxu		if (fromproc) {
698116977Sdavidxu			if (!_thr_getprocsig(sig, &siginfo))
699116977Sdavidxu				return;
700116977Sdavidxu			info = &siginfo;
701116977Sdavidxu		}
70267097Sdeischen		/*
703115080Sdeischen		 * Process according to thread state:
70467097Sdeischen		 */
705115080Sdeischen		switch (pthread->state) {
706115080Sdeischen		case PS_DEAD:
707115080Sdeischen		case PS_DEADLOCK:
708116977Sdavidxu		case PS_STATE_MAX:
709116977Sdavidxu			return;	/* XXX return false */
710115080Sdeischen		case PS_LOCKWAIT:
711115080Sdeischen		case PS_SUSPENDED:
71267097Sdeischen			/*
713115080Sdeischen			 * You can't call a signal handler for threads in these
714115080Sdeischen			 * states.
71567097Sdeischen			 */
716113658Sdeischen			suppress_handler = 1;
717115080Sdeischen			break;
718115080Sdeischen		case PS_RUNNING:
719116977Sdavidxu			if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
720115080Sdeischen				THR_RUNQ_REMOVE(pthread);
721116977Sdavidxu				pthread->active_priority |= THR_SIGNAL_PRIORITY;
722116977Sdavidxu				THR_RUNQ_INSERT_TAIL(pthread);
723116977Sdavidxu			} else {
724116977Sdavidxu				/* Possible not in RUNQ and has curframe ? */
725116977Sdavidxu				pthread->active_priority |= THR_SIGNAL_PRIORITY;
726116977Sdavidxu			}
727116977Sdavidxu			suppress_handler = 1;
728115080Sdeischen			break;
72939805Sjb		/*
730115080Sdeischen		 * States which cannot be interrupted but still require the
731115080Sdeischen		 * signal handler to run:
73239805Sjb		 */
733115080Sdeischen		case PS_COND_WAIT:
734115080Sdeischen		case PS_MUTEX_WAIT:
735115080Sdeischen			break;
73639805Sjb
737115080Sdeischen		case PS_SLEEP_WAIT:
738115080Sdeischen			/*
739115080Sdeischen			 * Unmasked signals always cause sleep to terminate
740115080Sdeischen			 * early regardless of SA_RESTART:
741115080Sdeischen			 */
742115080Sdeischen			pthread->interrupted = 1;
743115080Sdeischen			break;
744113658Sdeischen
745115080Sdeischen		case PS_JOIN:
746116977Sdavidxu			break;
747116977Sdavidxu
748115080Sdeischen		case PS_SIGSUSPEND:
749116977Sdavidxu			pthread->interrupted = 1;
750115080Sdeischen			break;
751113658Sdeischen
752115080Sdeischen		case PS_SIGWAIT:
753116977Sdavidxu			if (info == NULL)
754117066Sdavidxu				build_siginfo(&pthread->siginfo[sig-1], sig);
755117066Sdavidxu			else if (info != &pthread->siginfo[sig-1])
756117066Sdavidxu				memcpy(&pthread->siginfo[sig-1], info,
757116977Sdavidxu					sizeof(*info));
758113658Sdeischen			/*
759115080Sdeischen			 * The signal handler is not called for threads in
760115080Sdeischen			 * SIGWAIT.
761113658Sdeischen			 */
762115080Sdeischen			suppress_handler = 1;
763116977Sdavidxu			/* Wake up the thread if the signal is not blocked. */
764116977Sdavidxu			if (!SIGISMEMBER(pthread->sigmask, sig)) {
765115080Sdeischen				/* Return the signal number: */
766117066Sdavidxu				*(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1];
767116977Sdavidxu				pthread->sigmask = pthread->oldsigmask;
768115080Sdeischen				/* Make the thread runnable: */
769115080Sdeischen				_thr_setrunnable_unlocked(pthread);
770116977Sdavidxu			} else {
771115080Sdeischen				/* Increment the pending signal count. */
772116977Sdavidxu				SIGADDSET(pthread->sigpend, sig);
773117366Sdavidxu				if (!SIGISMEMBER(pthread->oldsigmask, sig)) {
774117366Sdavidxu					pthread->check_pending = 1;
775117366Sdavidxu					pthread->interrupted = 1;
776117366Sdavidxu					pthread->sigmask = pthread->oldsigmask;
777117366Sdavidxu					_thr_setrunnable_unlocked(pthread);
778117366Sdavidxu				}
779116977Sdavidxu			}
780116977Sdavidxu
781116977Sdavidxu			return;
782115080Sdeischen		}
783115080Sdeischen
784116977Sdavidxu		SIGADDSET(pthread->sigpend, sig);
785116977Sdavidxu		if (info == NULL)
786117066Sdavidxu			build_siginfo(&pthread->siginfo[sig-1], sig);
787117066Sdavidxu		else if (info != &pthread->siginfo[sig-1])
788117066Sdavidxu			memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
789116977Sdavidxu
790115080Sdeischen		if (suppress_handler == 0) {
791113658Sdeischen			/*
792113658Sdeischen			 * Setup a signal frame and save the current threads
793113658Sdeischen			 * state:
794113658Sdeischen			 */
795116977Sdavidxu			thr_sigframe_add(pthread);
796116977Sdavidxu			if (pthread->flags & THR_FLAGS_IN_RUNQ)
797116977Sdavidxu				THR_RUNQ_REMOVE(pthread);
798115080Sdeischen			pthread->active_priority |= THR_SIGNAL_PRIORITY;
799116977Sdavidxu			_thr_setrunnable_unlocked(pthread);
800116977Sdavidxu		} else {
801116977Sdavidxu			pthread->check_pending = 1;
802115080Sdeischen		}
80367097Sdeischen	}
804116977Sdavidxu
805116977Sdavidxu	DBG_MSG("<<< _thr_sig_add\n");
80635509Sjb}
80713546Sjulian
80867566Sdeischenstatic void
809113658Sdeischenthr_sig_check_state(struct pthread *pthread, int sig)
81067566Sdeischen{
81167566Sdeischen	/*
81267566Sdeischen	 * Process according to thread state:
81367566Sdeischen	 */
81467566Sdeischen	switch (pthread->state) {
81567566Sdeischen	/*
81667566Sdeischen	 * States which do not change when a signal is trapped:
81767566Sdeischen	 */
818113658Sdeischen	case PS_RUNNING:
819113658Sdeischen	case PS_LOCKWAIT:
820113658Sdeischen	case PS_MUTEX_WAIT:
821113658Sdeischen	case PS_COND_WAIT:
822113658Sdeischen	case PS_JOIN:
823113658Sdeischen	case PS_SUSPENDED:
82467566Sdeischen	case PS_DEAD:
82567566Sdeischen	case PS_DEADLOCK:
82667566Sdeischen	case PS_STATE_MAX:
82767566Sdeischen		break;
82867566Sdeischen
82967566Sdeischen	case PS_SIGWAIT:
830117066Sdavidxu		build_siginfo(&pthread->siginfo[sig-1], sig);
83167566Sdeischen		/* Wake up the thread if the signal is blocked. */
832116977Sdavidxu		if (!SIGISMEMBER(pthread->sigmask, sig)) {
83367566Sdeischen			/* Return the signal number: */
834117066Sdavidxu			*(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1];
835116977Sdavidxu			pthread->sigmask = pthread->oldsigmask;
836113658Sdeischen			/* Change the state of the thread to run: */
837113658Sdeischen			_thr_setrunnable_unlocked(pthread);
838116977Sdavidxu		} else {
83967566Sdeischen			/* Increment the pending signal count. */
840116977Sdavidxu			SIGADDSET(pthread->sigpend, sig);
841117366Sdavidxu			if (!SIGISMEMBER(pthread->oldsigmask, sig)) {
842117366Sdavidxu				pthread->check_pending = 1;
843117366Sdavidxu				pthread->interrupted = 1;
844117366Sdavidxu				pthread->sigmask = pthread->oldsigmask;
845117366Sdavidxu				_thr_setrunnable_unlocked(pthread);
846117366Sdavidxu			}
847116977Sdavidxu		}
84867566Sdeischen		break;
84967566Sdeischen
85067566Sdeischen	case PS_SIGSUSPEND:
85167566Sdeischen	case PS_SLEEP_WAIT:
85267566Sdeischen		/*
85367566Sdeischen		 * Remove the thread from the wait queue and make it
85467566Sdeischen		 * runnable:
85567566Sdeischen		 */
856113658Sdeischen		_thr_setrunnable_unlocked(pthread);
85767566Sdeischen
85867566Sdeischen		/* Flag the operation as interrupted: */
85967566Sdeischen		pthread->interrupted = 1;
86067566Sdeischen		break;
86167566Sdeischen	}
86267566Sdeischen}
86367566Sdeischen
86467097Sdeischen/*
86567097Sdeischen * Send a signal to a specific thread (ala pthread_kill):
86667097Sdeischen */
86754707Sdeischenvoid
868113658Sdeischen_thr_sig_send(struct pthread *pthread, int sig)
86954707Sdeischen{
870113658Sdeischen	struct pthread *curthread = _get_curthread();
87171581Sdeischen
872116977Sdavidxu#ifdef NOTYET
873116977Sdavidxu	if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
874116977Sdavidxu		kse_thr_interrupt(&pthread->tmbx, sig);
875116977Sdavidxu		return;
876116977Sdavidxu	}
877116977Sdavidxu#endif
878113658Sdeischen	/* Lock the scheduling queue of the target thread. */
879113658Sdeischen	THR_SCHED_LOCK(curthread, pthread);
880113658Sdeischen
88167566Sdeischen	/* Check for signals whose actions are SIG_DFL: */
88267566Sdeischen	if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) {
88367566Sdeischen		/*
88467566Sdeischen		 * Check to see if a temporary signal handler is
88567566Sdeischen		 * installed for sigwaiters:
88667566Sdeischen		 */
887116977Sdavidxu		if (_thread_dfl_count[sig - 1] == 0) {
88867566Sdeischen			/*
88967566Sdeischen			 * Deliver the signal to the process if a handler
89067566Sdeischen			 * is not installed:
89167566Sdeischen			 */
892113658Sdeischen			THR_SCHED_UNLOCK(curthread, pthread);
89367566Sdeischen			kill(getpid(), sig);
894113658Sdeischen			THR_SCHED_LOCK(curthread, pthread);
895113658Sdeischen		}
89667566Sdeischen		/*
89767566Sdeischen		 * Assuming we're still running after the above kill(),
89867566Sdeischen		 * make any necessary state changes to the thread:
89967566Sdeischen		 */
900113658Sdeischen		thr_sig_check_state(pthread, sig);
901113658Sdeischen		THR_SCHED_UNLOCK(curthread, pthread);
90267566Sdeischen	}
90354707Sdeischen	/*
90454707Sdeischen	 * Check that the signal is not being ignored:
90554707Sdeischen	 */
90667566Sdeischen	else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
907116977Sdavidxu		_thr_sig_add(pthread, sig, NULL);
908116977Sdavidxu		THR_SCHED_UNLOCK(curthread, pthread);
909116977Sdavidxu		/* XXX
910116977Sdavidxu		 * If thread sent signal to itself, check signals now.
911116977Sdavidxu		 * It is not really needed, _kse_critical_leave should
912116977Sdavidxu		 * have already checked signals.
913116977Sdavidxu		 */
914116977Sdavidxu		if (pthread == curthread && curthread->check_pending)
915116977Sdavidxu			_thr_sig_check_pending(curthread);
916116977Sdavidxu	} else  {
917116977Sdavidxu		THR_SCHED_UNLOCK(curthread, pthread);
91854707Sdeischen	}
91954707Sdeischen}
92054707Sdeischen
921113658Sdeischenstatic void
922116977Sdavidxuthr_sigframe_add(struct pthread *thread)
92335509Sjb{
924113658Sdeischen	if (thread->curframe == NULL)
925113658Sdeischen		PANIC("Thread doesn't have signal frame ");
92613546Sjulian
927116977Sdavidxu	if (thread->curframe->psf_valid == 0) {
928116977Sdavidxu		thread->curframe->psf_valid = 1;
92967097Sdeischen		/*
930113658Sdeischen		 * Multiple signals can be added to the same signal
931113658Sdeischen		 * frame.  Only save the thread's state the first time.
93267097Sdeischen		 */
933113658Sdeischen		thr_sigframe_save(thread, thread->curframe);
93467097Sdeischen	}
93567097Sdeischen}
93654707Sdeischen
937116977Sdavidxustatic void
938113658Sdeischenthr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
93967097Sdeischen{
940116977Sdavidxu	if (psf->psf_valid == 0)
941116977Sdavidxu		PANIC("invalid pthread_sigframe\n");
942113658Sdeischen	thread->flags = psf->psf_flags;
943113658Sdeischen	thread->interrupted = psf->psf_interrupted;
944113658Sdeischen	thread->signo = psf->psf_signo;
945113658Sdeischen	thread->state = psf->psf_state;
946113658Sdeischen	thread->data = psf->psf_wait_data;
947113658Sdeischen	thread->wakeup_time = psf->psf_wakeup_time;
94867097Sdeischen}
94967097Sdeischen
95067097Sdeischenstatic void
951113658Sdeischenthr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
95267097Sdeischen{
953113658Sdeischen	/* This has to initialize all members of the sigframe. */
954115413Sdavidxu	psf->psf_flags =
955116061Sdeischen	    thread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_IN_TDLIST);
956113658Sdeischen	psf->psf_interrupted = thread->interrupted;
957113658Sdeischen	psf->psf_signo = thread->signo;
958113658Sdeischen	psf->psf_state = thread->state;
959113658Sdeischen	psf->psf_wait_data = thread->data;
960113658Sdeischen	psf->psf_wakeup_time = thread->wakeup_time;
96167097Sdeischen}
962116977Sdavidxu
963116977Sdavidxuvoid
964116977Sdavidxu_thr_signal_init(void)
965116977Sdavidxu{
966116977Sdavidxu	sigset_t sigset;
967116977Sdavidxu	struct sigaction act;
968116977Sdavidxu	int i;
969116977Sdavidxu
970116977Sdavidxu	SIGFILLSET(sigset);
971116977Sdavidxu	__sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
972116977Sdavidxu	/* Enter a loop to get the existing signal status: */
973116977Sdavidxu	for (i = 1; i <= _SIG_MAXSIG; i++) {
974116977Sdavidxu		/* Check for signals which cannot be trapped: */
975116977Sdavidxu		if (i == SIGKILL || i == SIGSTOP) {
976116977Sdavidxu		}
977116977Sdavidxu
978116977Sdavidxu		/* Get the signal handler details: */
979116977Sdavidxu		else if (__sys_sigaction(i, NULL,
980116977Sdavidxu			    &_thread_sigact[i - 1]) != 0) {
981116977Sdavidxu			/*
982116977Sdavidxu			 * Abort this process if signal
983116977Sdavidxu			 * initialisation fails:
984116977Sdavidxu			 */
985116977Sdavidxu			PANIC("Cannot read signal handler info");
986116977Sdavidxu		}
987116977Sdavidxu	}
988116977Sdavidxu	/*
989116977Sdavidxu	 * Install the signal handler for SIGINFO.  It isn't
990116977Sdavidxu	 * really needed, but it is nice to have for debugging
991116977Sdavidxu	 * purposes.
992116977Sdavidxu	 */
993116977Sdavidxu	_thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
994116977Sdavidxu	SIGEMPTYSET(act.sa_mask);
995116977Sdavidxu	act.sa_flags = SA_SIGINFO | SA_RESTART;
996116977Sdavidxu	act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
997116977Sdavidxu	if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
998116977Sdavidxu		/*
999116977Sdavidxu		 * Abort this process if signal initialisation fails:
1000116977Sdavidxu		 */
1001116977Sdavidxu		PANIC("Cannot initialize signal handler");
1002116977Sdavidxu	}
1003116977Sdavidxu}
1004116977Sdavidxu
1005116977Sdavidxuvoid
1006116977Sdavidxu_thr_signal_deinit(void)
1007116977Sdavidxu{
1008117345Sdavidxu	struct pthread *curthread = _get_curthread();
1009117345Sdavidxu	sigset_t tmpmask;
1010116977Sdavidxu	int i;
1011116977Sdavidxu
1012116977Sdavidxu	SIGFILLSET(tmpmask);
1013116977Sdavidxu	SIG_CANTMASK(tmpmask);
1014117345Sdavidxu	__sys_sigprocmask(SIG_SETMASK, &tmpmask, NULL);
1015116977Sdavidxu	/* Enter a loop to get the existing signal status: */
1016116977Sdavidxu	for (i = 1; i <= _SIG_MAXSIG; i++) {
1017116977Sdavidxu		/* Check for signals which cannot be trapped: */
1018116977Sdavidxu		if (i == SIGKILL || i == SIGSTOP) {
1019116977Sdavidxu		}
1020116977Sdavidxu
1021116977Sdavidxu		/* Set the signal handler details: */
1022116977Sdavidxu		else if (__sys_sigaction(i, &_thread_sigact[i - 1], NULL) != 0) {
1023116977Sdavidxu			/*
1024116977Sdavidxu			 * Abort this process if signal
1025116977Sdavidxu			 * initialisation fails:
1026116977Sdavidxu			 */
1027116977Sdavidxu			PANIC("Cannot set signal handler info");
1028116977Sdavidxu		}
1029116977Sdavidxu	}
1030117345Sdavidxu	__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
1031116977Sdavidxu}
1032116977Sdavidxu
1033