xref: /freebsd/lib/libthr/thread/thr_sig.c (revision e858faa9bb929e040dfa2ee6f9e4806cec4d685d)
1 /*
2  * Copyright (c) 2003 Jeffrey Roberson <jeff@freebsd.org>
3  * Copyright (c) 2003 Jonathan Mini <mini@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/signalvar.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <setjmp.h>
37 #include <errno.h>
38 #include <pthread.h>
39 #include <stdlib.h>
40 
41 #include "thr_private.h"
42 
43 /* #define DEBUG_SIGNAL */
44 #ifdef DEBUG_SIGNAL
45 #define DBG_MSG		stdout_debug
46 #else
47 #define DBG_MSG(x...)
48 #endif
49 
50 __weak_reference(_sigprocmask, sigprocmask);
51 
52 int
53 _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
54 {
55 	sigset_t new;
56 
57 	/*
58 	 * Make sure applications can't unblock our synchronization
59 	 * signal. We always want to take this with sigwait().
60 	 */
61 	if (set != NULL) {
62 		new = *set;
63 		switch (how) {
64 		case SIG_BLOCK:
65 		case SIG_SETMASK:
66 			SIGADDSET(new, SIGTHR);
67 			break;
68 		case SIG_UNBLOCK:
69 			SIGDELSET(new, SIGTHR);
70 			break;
71 		default:
72 			break;
73 		}
74 		set = &new;
75 	}
76 
77 	return (__sys_sigprocmask(how, set, oset));
78 }
79 
80 __weak_reference(_pthread_sigmask, pthread_sigmask);
81 
82 int
83 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
84 {
85 	int error;
86 
87 	/*
88 	 * This always sets the mask on the current thread.
89 	 */
90 	error = sigprocmask(how, set, oset);
91 
92 	/*
93 	 * pthread_sigmask returns errno or success while sigprocmask returns
94 	 * -1 and sets errno.
95 	 */
96 	if (error == -1)
97 		error = errno;
98 
99 	return (error);
100 }
101 
102 
103 __weak_reference(_pthread_kill, pthread_kill);
104 
105 int
106 _pthread_kill(pthread_t pthread, int sig)
107 {
108 
109 	if (_thread_initial == NULL)
110 		_thread_init();
111 	return (thr_kill(pthread->thr_id, sig));
112 }
113 
114 /*
115  * User thread signal handler wrapper.
116  */
117 void
118 _thread_sig_wrapper(int sig, siginfo_t *info, void *context)
119 {
120 	struct pthread_state_data psd;
121 	struct sigaction *actp;
122 	__siginfohandler_t *handler;
123 	struct umtx *up;
124 	spinlock_t *sp;
125 
126 	/*
127 	 * Do a little cleanup handling for those threads in
128 	 * queues before calling the signal handler.  Signals
129 	 * for these threads are temporarily blocked until
130 	 * after cleanup handling.
131 	 */
132 	switch (curthread->state) {
133 	case PS_BARRIER_WAIT:
134 		/*
135 		 * XXX - The thread has reached the barrier. We can't
136 		 *	 "back it away" from the barrier.
137 		 */
138 		_thread_critical_enter(curthread);
139 		break;
140 	case PS_COND_WAIT:
141 		/*
142 		 * Cache the address, since it will not be available
143 		 * after it has been backed out.
144 		 */
145 		up = &curthread->data.cond->c_lock;
146 
147 		UMTX_LOCK(up);
148 		_thread_critical_enter(curthread);
149 		_cond_wait_backout(curthread);
150 		UMTX_UNLOCK(up);
151 		break;
152 	case PS_MUTEX_WAIT:
153 		/*
154 		 * Cache the address, since it will not be available
155 		 * after it has been backed out.
156 		 */
157 		sp = &curthread->data.mutex->lock;
158 
159 		_SPINLOCK(sp);
160 		_thread_critical_enter(curthread);
161 		_mutex_lock_backout(curthread);
162 		_SPINUNLOCK(sp);
163 		break;
164 	default:
165 		/*
166 		 * We need to lock the thread to read it's flags.
167 		 */
168 		_thread_critical_enter(curthread);
169 		break;
170 	}
171 
172 	/*
173 	 * We save the flags now so that any modifications done as part
174 	 * of the backout are reflected when the flags are restored.
175 	 */
176 	psd.psd_flags = curthread->flags;
177 
178 	PTHREAD_SET_STATE(curthread, PS_RUNNING);
179 	_thread_critical_exit(curthread);
180 	actp = proc_sigact_sigaction(sig);
181 	handler = (__siginfohandler_t *)actp->sa_handler;
182 	handler(sig, info, (ucontext_t *)context);
183 
184         /* Restore the thread's flags, and make it runnable */
185 	_thread_critical_enter(curthread);
186 	curthread->flags = psd.psd_flags;
187 	PTHREAD_SET_STATE(curthread, PS_RUNNING);
188 	_thread_critical_exit(curthread);
189 }
190