xref: /freebsd/lib/libthr/thread/thr_sig.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 "thr_private.h"
40 
41 /* #define DEBUG_SIGNAL */
42 #ifdef DEBUG_SIGNAL
43 #define DBG_MSG		stdout_debug
44 #else
45 #define DBG_MSG(x...)
46 #endif
47 
48 __weak_reference(_sigprocmask, sigprocmask);
49 
50 int
51 _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
52 {
53 	sigset_t new;
54 
55 	/*
56 	 * Make sure applications can't unblock our synchronization
57 	 * signal. We always want to take this with sigwait().
58 	 */
59 	if (set != NULL) {
60 		new = *set;
61 		switch (how) {
62 		case SIG_BLOCK:
63 		case SIG_SETMASK:
64 			SIGADDSET(new, SIGTHR);
65 			break;
66 		case SIG_UNBLOCK:
67 			SIGDELSET(new, SIGTHR);
68 			break;
69 		default:
70 			break;
71 		}
72 		set = &new;
73 	}
74 
75 	return (__sys_sigprocmask(how, set, oset));
76 }
77 
78 __weak_reference(_pthread_sigmask, pthread_sigmask);
79 
80 int
81 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
82 {
83 	int error;
84 
85 	/*
86 	 * This always sets the mask on the current thread.
87 	 */
88 	error = sigprocmask(how, set, oset);
89 
90 	/*
91 	 * pthread_sigmask returns errno or success while sigprocmask returns
92 	 * -1 and sets errno.
93 	 */
94 	if (error == -1)
95 		error = errno;
96 
97 	return (error);
98 }
99 
100 
101 __weak_reference(_pthread_kill, pthread_kill);
102 
103 int
104 _pthread_kill(pthread_t pthread, int sig)
105 {
106 
107 	if (_thread_initial == NULL)
108 		_thread_init();
109 	return (thr_kill(pthread->thr_id, sig));
110 }
111 
112 /*
113  * User thread signal handler wrapper.
114  */
115 void
116 _thread_sig_wrapper(int sig, siginfo_t *info, void *context)
117 {
118 	struct pthread_state_data psd;
119 	__siginfohandler_t *handler;
120 
121 	GIANT_LOCK(curthread);
122 	/* Save the thread's previous state. */
123 	psd.psd_wait_data = curthread->data;
124 	psd.psd_state = curthread->state;
125 	psd.psd_flags = curthread->flags;
126 
127 	/*
128 	 * Do a little cleanup handling for those threads in
129 	 * queues before calling the signal handler.  Signals
130 	 * for these threads are temporarily blocked until
131 	 * after cleanup handling.
132 	 */
133 	switch (psd.psd_state) {
134 	case PS_COND_WAIT:
135 		_cond_wait_backout(curthread);
136 		psd.psd_state = PS_RUNNING;
137 		break;
138 
139 	case PS_MUTEX_WAIT:
140 		_mutex_lock_backout(curthread);
141 		psd.psd_state = PS_RUNNING;
142 		break;
143 
144 	default:
145 		break;
146 	}
147 
148 	if (_thread_sigact[sig -1].sa_handler != NULL) {
149 		GIANT_UNLOCK(curthread);
150 		handler = (__siginfohandler_t *)
151 			_thread_sigact[sig - 1].sa_handler;
152 		handler(sig, info, (ucontext_t *)context);
153 		GIANT_LOCK(curthread);
154 	}
155 
156         /* Restore the signal frame. */
157 	curthread->data = psd.psd_wait_data;
158 	curthread->state = psd.psd_state;
159 	curthread->flags = psd.psd_flags &
160 	    (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
161 	GIANT_UNLOCK(curthread);
162 }
163