xref: /dragonfly/lib/libthread_xu/thread/thr_sig.c (revision 940be950)
1 /*
2  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 #include "namespace.h"
28 #include <sys/signalvar.h>
29 #include <machine/tls.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <pthread.h>
34 #include "un-namespace.h"
35 
36 #include "thr_private.h"
37 
38 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
39 #include <sys/file.h>
40 #include <stdio.h>
41 #endif
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 int	__sigwait(const sigset_t *set, int *sig);
51 int	__sigwaitinfo(const sigset_t *set, siginfo_t *info);
52 int	__sigtimedwait(const sigset_t *set, siginfo_t *info,
53 		const struct timespec * timeout);
54 
55 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
56 static void _thr_debug_sig(int signo);
57 #endif
58 
59 static void
sigcancel_handler(int sig __unused,siginfo_t * info __unused,ucontext_t * ucp __unused)60 sigcancel_handler(int sig __unused, siginfo_t *info __unused,
61 	ucontext_t *ucp __unused)
62 {
63 	pthread_t curthread = tls_get_curthread();
64 
65 	if (curthread->cancelflags & THR_CANCEL_AT_POINT)
66 		_pthread_testcancel();
67 	_thr_ast(curthread);
68 }
69 
70 void
_thr_ast(pthread_t curthread)71 _thr_ast(pthread_t curthread)
72 {
73 	if (!THR_IN_CRITICAL(curthread)) {
74 		if (__predict_false((curthread->flags &
75 		    (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
76 			== THR_FLAGS_NEED_SUSPEND))
77 			_thr_suspend_check(curthread);
78 	}
79 }
80 
81 void
_thr_suspend_check(pthread_t curthread)82 _thr_suspend_check(pthread_t curthread)
83 {
84 	umtx_t cycle;
85 
86 	/*
87 	 * Blocks SIGCANCEL which other threads must send.
88 	 */
89 	_thr_signal_block(curthread);
90 
91 	/*
92 	 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
93 	 * because we are leaf code, we don't want to recursively call
94 	 * ourself.
95 	 */
96 	curthread->critical_count++;
97 	THR_UMTX_LOCK(curthread, &(curthread)->lock);
98 	while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
99 		THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
100 		curthread->cycle++;
101 		cycle = curthread->cycle;
102 
103 		/* Wake the thread suspending us. */
104 		_thr_umtx_wake(&curthread->cycle, 0);
105 
106 		/*
107 		 * if we are from pthread_exit, we don't want to
108 		 * suspend, just go and die.
109 		 */
110 		if (curthread->state == PS_DEAD)
111 			break;
112 		curthread->flags |= THR_FLAGS_SUSPENDED;
113 		THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
114 		_thr_umtx_wait(&curthread->cycle, cycle, NULL, 0);
115 		THR_UMTX_LOCK(curthread, &(curthread)->lock);
116 		curthread->flags &= ~THR_FLAGS_SUSPENDED;
117 	}
118 	THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
119 	curthread->critical_count--;
120 
121 	_thr_signal_unblock(curthread);
122 }
123 
124 void
_thr_signal_init(void)125 _thr_signal_init(void)
126 {
127 	struct sigaction act;
128 
129 	/* Install cancel handler. */
130 	SIGEMPTYSET(act.sa_mask);
131 	act.sa_flags = SA_SIGINFO | SA_RESTART;
132 	act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
133 	__sys_sigaction(SIGCANCEL, &act, NULL);
134 
135 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
136 	/*
137 	 * If enabled, rwlock, mutex, and condition variable operations
138 	 * are recorded in a text buffer and signal 63 dumps the buffer
139 	 * to /tmp/cond${pid}.log.
140 	 */
141 	act.sa_flags = SA_RESTART;
142 	act.sa_handler = _thr_debug_sig;
143 	__sys_sigaction(63, &act, NULL);
144 #endif
145 }
146 
147 void
_thr_signal_deinit(void)148 _thr_signal_deinit(void)
149 {
150 }
151 
152 int
_sigaction(int sig,const struct sigaction * act,struct sigaction * oact)153 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
154 {
155 	/* Check if the signal number is out of range: */
156 	if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
157 		/* Return an invalid argument: */
158 		errno = EINVAL;
159 		return (-1);
160 	}
161 
162 	return __sys_sigaction(sig, act, oact);
163 }
164 
165 __strong_reference(_sigaction, sigaction);
166 
167 int
_sigprocmask(int how,const sigset_t * set,sigset_t * oset)168 _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
169 {
170 	const sigset_t *p = set;
171 	sigset_t newset;
172 
173 	if (how != SIG_UNBLOCK) {
174 		if (set != NULL) {
175 			newset = *set;
176 			SIGDELSET(newset, SIGCANCEL);
177 			p = &newset;
178 		}
179 	}
180 	return (__sys_sigprocmask(how, p, oset));
181 }
182 
183 __strong_reference(_sigprocmask, sigprocmask);
184 
185 int
_pthread_sigmask(int how,const sigset_t * set,sigset_t * oset)186 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
187 {
188 	if (_sigprocmask(how, set, oset))
189 		return (errno);
190 	return (0);
191 }
192 
193 __strong_reference(_pthread_sigmask, pthread_sigmask);
194 
195 int
_sigsuspend(const sigset_t * set)196 _sigsuspend(const sigset_t * set)
197 {
198 	pthread_t curthread = tls_get_curthread();
199 	sigset_t newset;
200 	const sigset_t *pset;
201 	int oldcancel;
202 	int ret;
203 
204 	if (SIGISMEMBER(*set, SIGCANCEL)) {
205 		newset = *set;
206 		SIGDELSET(newset, SIGCANCEL);
207 		pset = &newset;
208 	} else
209 		pset = set;
210 
211 	oldcancel = _thr_cancel_enter(curthread);
212 	ret = __sys_sigsuspend(pset);
213 	_thr_cancel_leave(curthread, oldcancel);
214 
215 	return (ret);
216 }
217 
218 __strong_reference(_sigsuspend, sigsuspend);
219 
220 int
__sigtimedwait(const sigset_t * set,siginfo_t * info,const struct timespec * timeout)221 __sigtimedwait(const sigset_t *set, siginfo_t *info,
222 	const struct timespec * timeout)
223 {
224 	pthread_t curthread = tls_get_curthread();
225 	sigset_t newset;
226 	const sigset_t *pset;
227 	int oldcancel;
228 	int ret;
229 
230 	if (SIGISMEMBER(*set, SIGCANCEL)) {
231 		newset = *set;
232 		SIGDELSET(newset, SIGCANCEL);
233 		pset = &newset;
234 	} else
235 		pset = set;
236 	oldcancel = _thr_cancel_enter(curthread);
237 	ret = __sys_sigtimedwait(pset, info, timeout);
238 	_thr_cancel_leave(curthread, oldcancel);
239 	return (ret);
240 }
241 
242 __strong_reference(__sigtimedwait, sigtimedwait);
243 
244 int
__sigwaitinfo(const sigset_t * set,siginfo_t * info)245 __sigwaitinfo(const sigset_t *set, siginfo_t *info)
246 {
247 	pthread_t curthread = tls_get_curthread();
248 	sigset_t newset;
249 	const sigset_t *pset;
250 	int oldcancel;
251 	int ret;
252 
253 	if (SIGISMEMBER(*set, SIGCANCEL)) {
254 		newset = *set;
255 		SIGDELSET(newset, SIGCANCEL);
256 		pset = &newset;
257 	} else
258 		pset = set;
259 
260 	oldcancel = _thr_cancel_enter(curthread);
261 	ret = __sys_sigwaitinfo(pset, info);
262 	_thr_cancel_leave(curthread, oldcancel);
263 	return (ret);
264 }
265 
266 __strong_reference(__sigwaitinfo, sigwaitinfo);
267 
268 int
__sigwait(const sigset_t * set,int * sig)269 __sigwait(const sigset_t *set, int *sig)
270 {
271 	int s;
272 
273 	s = __sigwaitinfo(set, NULL);
274 	if (s > 0) {
275 		*sig = s;
276 		return (0);
277 	}
278 	return (errno);
279 }
280 
281 __strong_reference(__sigwait, sigwait);
282 
283 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
284 
285 #define LOGBUF_SIZE	(4 * 1024 * 1024)
286 #define LOGBUF_MASK	(LOGBUF_SIZE - 1)
287 
288 char LogBuf[LOGBUF_SIZE];
289 unsigned long LogWIndex;
290 
291 void
_thr_log(const char * buf,size_t bytes)292 _thr_log(const char *buf, size_t bytes)
293 {
294 	pthread_t curthread;
295 	unsigned long i;
296 	char prefix[32];
297 	size_t plen;
298 
299 	curthread = tls_get_curthread();
300 	if (curthread) {
301 		plen = snprintf(prefix, sizeof(prefix), "%d.%d: ",
302 				(int)__sys_getpid(),
303 				curthread->tid);
304 	} else {
305 		plen = snprintf(prefix, sizeof(prefix), "unknown: ");
306 	}
307 
308 	if (bytes == 0)
309 		bytes = strlen(buf);
310 	i = atomic_fetchadd_long(&LogWIndex, plen + bytes);
311 	i = i & LOGBUF_MASK;
312 	if (plen <= (size_t)(LOGBUF_SIZE - i)) {
313 		bcopy(prefix, LogBuf + i, plen);
314 	} else {
315 		bcopy(prefix, LogBuf + i, LOGBUF_SIZE - i);
316 		plen -= LOGBUF_SIZE - i;
317 		bcopy(prefix, LogBuf, plen);
318 	}
319 
320 	i += plen;
321 	i = i & LOGBUF_MASK;
322 	if (bytes <= (size_t)(LOGBUF_SIZE - i)) {
323 		bcopy(buf, LogBuf + i, bytes);
324 	} else {
325 		bcopy(buf, LogBuf + i, LOGBUF_SIZE - i);
326 		bytes -= LOGBUF_SIZE - i;
327 		bcopy(buf, LogBuf, bytes);
328 	}
329 }
330 
331 static void
_thr_debug_sig(int signo __unused)332 _thr_debug_sig(int signo __unused)
333 {
334         char buf[256];
335 	int fd;
336 	unsigned long i;
337 
338 	snprintf(buf, sizeof(buf), "/tmp/cond%d.log", (int)__sys_getpid());
339 	fd = open(buf, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666);
340 	if (fd >= 0) {
341 		i = LogWIndex;
342 		if (i < LOGBUF_SIZE) {
343 			write(fd, LogBuf, i);
344 		} else {
345 			i &= LOGBUF_MASK;
346 			write(fd, LogBuf + i, LOGBUF_SIZE - i);
347 			write(fd, LogBuf, i);
348 		}
349 		close(fd);
350 	}
351 }
352 
353 #endif
354