thr_sig.c (58094) | thr_sig.c (67097) |
---|---|
1/* 2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 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 --- 15 unchanged lines hidden (view full) --- 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * | 1/* 2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 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 --- 15 unchanged lines hidden (view full) --- 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * |
32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 58094 2000-03-15 13:59:27Z deischen $ | 32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 67097 2000-10-13 22:12:32Z deischen $ |
33 */ 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/signalvar.h> 37#include <signal.h> 38#include <fcntl.h> 39#include <unistd.h> 40#include <setjmp.h> 41#include <errno.h> 42#ifdef _THREAD_SAFE 43#include <pthread.h> 44#include "pthread_private.h" 45 46/* Prototypes: */ | 33 */ 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/signalvar.h> 37#include <signal.h> 38#include <fcntl.h> 39#include <unistd.h> 40#include <setjmp.h> 41#include <errno.h> 42#ifdef _THREAD_SAFE 43#include <pthread.h> 44#include "pthread_private.h" 45 46/* Prototypes: */ |
47static void thread_sig_check_state(pthread_t pthread, int sig); 48static void thread_sig_finish_longjmp(void *arg); 49static void handle_state_change(pthread_t pthread); | 47static void thread_sig_add(pthread_t pthread, int sig, int has_args); 48static pthread_t thread_sig_find(int sig); 49static void thread_sig_handle_special(int sig); 50static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp); 51static void thread_sigframe_add(pthread_t thread, int sig); 52static void thread_sigframe_leave(pthread_t thread, int frame); 53static void thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf); 54static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf); |
50 | 55 |
56/* #define DEBUG_SIGNAL */ 57#ifdef DEBUG_SIGNAL 58#define DBG_MSG stdout_debug 59#else 60#define DBG_MSG(x...) 61#endif |
|
51 | 62 |
52/* Static variables: */ 53static spinlock_t signal_lock = _SPINLOCK_INITIALIZER; 54static unsigned int pending_sigs[NSIG]; 55static unsigned int handled_sigs[NSIG]; 56static int volatile check_pending = 0; 57static int volatile check_waiting = 0; | 63#if defined(_PTHREADS_INVARIANTS) 64#define SIG_SET_ACTIVE() _sig_in_handler = 1 65#define SIG_SET_INACTIVE() _sig_in_handler = 0 66#else 67#define SIG_SET_ACTIVE() 68#define SIG_SET_INACTIVE() 69#endif |
58 | 70 |
59/* Initialize signal handling facility: */ | |
60void | 71void |
61_thread_sig_init(void) | 72_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) |
62{ | 73{ |
63 int i; | 74 pthread_t pthread; 75 int current_frame; 76 char c; |
64 | 77 |
65 /* Clear pending and handled signal counts: */ 66 for (i = 1; i < NSIG; i++) { 67 pending_sigs[i - 1] = 0; 68 handled_sigs[i - 1] = 0; 69 } | 78 if (ucp == NULL) 79 PANIC("Thread signal handler received null context"); 80 DBG_MSG("Got signal %d, current thread %p\n", sig, _thread_run); |
70 | 81 |
71 /* Clear the lock: */ 72 signal_lock.access_lock = 0; 73 74 /* Clear the process pending signals: */ 75 sigemptyset(&_process_sigpending); 76} 77 78void 79_thread_sig_handler(int sig, int code, ucontext_t * scp) 80{ 81 pthread_t pthread, pthread_next; 82 int i; 83 char c; 84 | |
85 /* Check if an interval timer signal: */ 86 if (sig == _SCHED_SIGNAL) { | 82 /* Check if an interval timer signal: */ 83 if (sig == _SCHED_SIGNAL) { |
84 /* Update the scheduling clock: */ 85 gettimeofday((struct timeval *)&_sched_tod, NULL); 86 _sched_ticks++; 87 |
|
87 if (_thread_kern_in_sched != 0) { 88 /* 89 * The scheduler is already running; ignore this 90 * signal. 91 */ 92 } 93 /* 94 * Check if the scheduler interrupt has come when 95 * the currently running thread has deferred thread 96 * signals. 97 */ 98 else if (_thread_run->sig_defer_count > 0) 99 _thread_run->yield_on_sig_undefer = 1; | 88 if (_thread_kern_in_sched != 0) { 89 /* 90 * The scheduler is already running; ignore this 91 * signal. 92 */ 93 } 94 /* 95 * Check if the scheduler interrupt has come when 96 * the currently running thread has deferred thread 97 * signals. 98 */ 99 else if (_thread_run->sig_defer_count > 0) 100 _thread_run->yield_on_sig_undefer = 1; |
100 | |
101 else { 102 /* | 101 else { 102 /* |
103 * Save the context of the currently running thread: 104 */ 105 thread_sig_savecontext(_thread_run, ucp); 106 107 /* |
|
103 * Schedule the next thread. This function is not 104 * expected to return because it will do a longjmp 105 * instead. 106 */ | 108 * Schedule the next thread. This function is not 109 * expected to return because it will do a longjmp 110 * instead. 111 */ |
107 _thread_kern_sched(scp); | 112 _thread_kern_sched(ucp); |
108 109 /* 110 * This point should not be reached, so abort the 111 * process: 112 */ 113 PANIC("Returned to signal function from scheduler"); 114 } 115 } 116 /* 117 * Check if the kernel has been interrupted while the scheduler 118 * is accessing the scheduling queues or if there is a currently 119 * running thread that has deferred signals. 120 */ | 113 114 /* 115 * This point should not be reached, so abort the 116 * process: 117 */ 118 PANIC("Returned to signal function from scheduler"); 119 } 120 } 121 /* 122 * Check if the kernel has been interrupted while the scheduler 123 * is accessing the scheduling queues or if there is a currently 124 * running thread that has deferred signals. 125 */ |
121 else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) && 122 (_thread_run->sig_defer_count > 0))) { | 126 else if ((_thread_kern_in_sched != 0) || 127 (_thread_run->sig_defer_count > 0)) { |
123 /* Cast the signal number to a character variable: */ 124 c = sig; 125 126 /* 127 * Write the signal number to the kernel pipe so that it will 128 * be ready to read when this signal handler returns. 129 */ | 128 /* Cast the signal number to a character variable: */ 129 c = sig; 130 131 /* 132 * Write the signal number to the kernel pipe so that it will 133 * be ready to read when this signal handler returns. 134 */ |
130 _thread_sys_write(_thread_kern_pipe[1], &c, 1); | 135 if (_queue_signals != 0) { 136 _thread_sys_write(_thread_kern_pipe[1], &c, 1); 137 DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig); 138 } 139 if (_thread_sigq[sig - 1].blocked == 0) { 140 DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig); 141 /* 142 * Do not block this signal; it will be blocked 143 * when the pending signals are run down. 144 */ 145 /* _thread_sigq[sig - 1].blocked = 1; */ |
131 | 146 |
132 /* Indicate that there are queued signals in the pipe. */ 133 _sigq_check_reqd = 1; 134 } else { 135 if (_atomic_lock(&signal_lock.access_lock)) { 136 /* There is another signal handler running: */ 137 pending_sigs[sig - 1]++; 138 check_pending = 1; | 147 /* 148 * Queue the signal, saving siginfo and sigcontext 149 * (ucontext). 150 * 151 * XXX - Do we need to copy siginfo and ucp? 152 */ 153 _thread_sigq[sig - 1].signo = sig; 154 if (info != NULL) 155 memcpy(&_thread_sigq[sig - 1].siginfo, info, 156 sizeof(*info)); 157 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); 158 159 /* Indicate that there are queued signals: */ 160 _thread_sigq[sig - 1].pending = 1; 161 _sigq_check_reqd = 1; |
139 } | 162 } |
140 else { 141 /* It's safe to handle the signal now. */ 142 pthread = _thread_sig_handle(sig, scp); | 163 /* These signals need special handling: */ 164 else if (sig == SIGCHLD || sig == SIGTSTP || 165 sig == SIGTTIN || sig == SIGTTOU) { 166 _thread_sigq[sig - 1].pending = 1; 167 _thread_sigq[sig - 1].signo = sig; 168 _sigq_check_reqd = 1; 169 } 170 else 171 DBG_MSG("Got signal %d, ignored.\n", sig); 172 } 173 /* 174 * The signal handlers should have been installed so that they 175 * cannot be interrupted by other signals. 176 */ 177 else if (_thread_sigq[sig - 1].blocked == 0) { 178 /* The signal is not blocked; handle the signal: */ 179 current_frame = _thread_run->sigframe_count; |
143 | 180 |
144 /* Reset the pending and handled count back to 0: */ 145 pending_sigs[sig - 1] = 0; 146 handled_sigs[sig - 1] = 0; | 181 /* 182 * Ignore subsequent occurrences of this signal 183 * until the current signal is handled: 184 */ 185 _thread_sigq[sig - 1].blocked = 1; |
147 | 186 |
148 if (pthread == NULL) 149 signal_lock.access_lock = 0; 150 else { 151 sigaddset(&pthread->sigmask, sig); | 187 /* This signal will be handled; clear the pending flag: */ 188 _thread_sigq[sig - 1].pending = 0; |
152 | 189 |
153 /* 154 * Make sure not to deliver the same signal to 155 * the thread twice. sigpend is potentially 156 * modified by the call chain 157 * _thread_sig_handle() --> 158 * thread_sig_check_state(), which can happen 159 * just above. 160 */ 161 if (sigismember(&pthread->sigpend, sig)) 162 sigdelset(&pthread->sigpend, sig); | 190 /* 191 * Save siginfo and sigcontext (ucontext). 192 * 193 * XXX - Do we need to copy siginfo and ucp? 194 */ 195 _thread_sigq[sig - 1].signo = sig; |
163 | 196 |
164 signal_lock.access_lock = 0; 165 _thread_sig_deliver(pthread, sig); 166 sigdelset(&pthread->sigmask, sig); 167 } 168 } | 197 if (info != NULL) 198 memcpy(&_thread_sigq[sig - 1].siginfo, info, 199 sizeof(*info)); 200 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); 201 SIG_SET_ACTIVE(); |
169 | 202 |
170 /* Enter a loop to process pending signals: */ 171 while ((check_pending != 0) && 172 (_atomic_lock(&signal_lock.access_lock) == 0)) { 173 check_pending = 0; 174 for (i = 1; i < NSIG; i++) { 175 if (pending_sigs[i - 1] > handled_sigs[i - 1]) { 176 pending_sigs[i - 1] = handled_sigs[i - 1]; 177 pthread = _thread_sig_handle(i, scp); 178 if (pthread != NULL) { 179 sigaddset(&pthread->sigmask, i); 180 /* Save the old state: */ 181 pthread->oldstate = pthread->state; 182 signal_lock.access_lock = 0; 183 _thread_sig_deliver(pthread, i); 184 sigdelset(&pthread->sigmask, i); 185 if (_atomic_lock(&signal_lock.access_lock)) { 186 check_pending = 1; 187 /* 188 * Have the lock holder take care 189 * of any state changes: 190 */ 191 if (pthread->state != pthread->oldstate) 192 check_waiting = 1; 193 return; 194 } 195 if (pthread->state != pthread->oldstate) 196 handle_state_change(pthread); 197 } 198 } 199 } 200 while (check_waiting != 0) { 201 check_waiting = 0; 202 /* 203 * Enter a loop to wake up all threads waiting 204 * for a process to complete: 205 */ 206 for (pthread = TAILQ_FIRST(&_waitingq); 207 pthread != NULL; pthread = pthread_next) { 208 pthread_next = TAILQ_NEXT(pthread, pqe); 209 if (pthread->state == PS_RUNNING) 210 handle_state_change(pthread); 211 } 212 } 213 /* Release the lock: */ 214 signal_lock.access_lock = 0; | 203 /* Handle special signals: */ 204 thread_sig_handle_special(sig); 205 206 if ((pthread = thread_sig_find(sig)) != NULL) { 207 DBG_MSG("Got signal %d, adding frame to thread %p\n", 208 sig, pthread); 209 /* 210 * A thread was found that can handle the signal. 211 * Save the context of the currently running thread 212 * so that we can switch to another thread without 213 * losing track of where the current thread left off. 214 * This also applies if the current thread is the 215 * thread to be signaled. 216 */ 217 thread_sig_savecontext(_thread_run, ucp); 218 219 /* Setup the target thread to receive the signal: */ 220 thread_sig_add(pthread, sig, /*has_args*/ 1); 221 222 /* Take a peek at the next ready to run thread: */ 223 pthread = PTHREAD_PRIOQ_FIRST(); 224 DBG_MSG("Finished adding frame, head of prio list %p\n", 225 pthread); |
215 } | 226 } |
227 else 228 DBG_MSG("No thread to handle signal %d\n", sig); 229 SIG_SET_INACTIVE(); |
|
216 217 /* | 230 231 /* |
218 * Check to see if the current thread performed a 219 * [sig|_]longjmp() out of a signal handler. | 232 * Switch to a different context if the currently running 233 * thread takes a signal, or if another thread takes a 234 * signal and the currently running thread is not in a 235 * signal handler. |
220 */ | 236 */ |
221 if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP | 222 JMPFLAGS__LONGJMP)) != 0) { 223 _thread_run->jmpflags = JMPFLAGS_NONE; 224 __longjmp(_thread_run->nested_jmp.jmp, 225 _thread_run->longjmp_val); 226 } else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) { 227 _thread_run->jmpflags = JMPFLAGS_NONE; 228 __siglongjmp(_thread_run->nested_jmp.sigjmp, 229 _thread_run->longjmp_val); | 237 if ((_thread_run->sigframe_count > current_frame) || 238 ((pthread != NULL) && 239 (pthread->active_priority > _thread_run->active_priority))) { 240 /* Enter the kernel scheduler: */ 241 DBG_MSG("Entering scheduler from signal handler\n"); 242 _thread_kern_sched(ucp); |
230 } 231 } | 243 } 244 } |
245 else { 246 SIG_SET_ACTIVE(); 247 thread_sig_handle_special(sig); 248 SIG_SET_INACTIVE(); 249 } |
|
232} 233 | 250} 251 |
252static void 253thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp) 254{ 255 struct pthread_signal_frame *psf; 256 257 psf = _thread_run->curframe; 258 259 memcpy(&psf->ctx.uc, ucp, sizeof(*ucp)); 260 261 /* XXX - Save FP registers too? */ 262 FP_SAVE_UC(&psf->ctx.uc); 263 264 /* Mark the context saved as a ucontext: */ 265 psf->ctxtype = CTX_UC; 266} 267 268/* 269 * Find a thread that can handle the signal. 270 */ |
|
234pthread_t | 271pthread_t |
235_thread_sig_handle(int sig, ucontext_t * scp) | 272thread_sig_find(int sig) |
236{ | 273{ |
237 int i, handler_installed; | 274 int handler_installed; |
238 pthread_t pthread, pthread_next; 239 pthread_t suspended_thread, signaled_thread; 240 | 275 pthread_t pthread, pthread_next; 276 pthread_t suspended_thread, signaled_thread; 277 |
278 DBG_MSG("Looking for thread to handle signal %d\n", sig); |
|
241 /* Check if the signal requires a dump of thread information: */ 242 if (sig == SIGINFO) 243 /* Dump thread information to file: */ 244 _thread_dump_info(); 245 246 /* Check if an interval timer signal: */ 247 else if (sig == _SCHED_SIGNAL) { 248 /* 249 * This shouldn't ever occur (should this panic?). 250 */ 251 } else { | 279 /* Check if the signal requires a dump of thread information: */ 280 if (sig == SIGINFO) 281 /* Dump thread information to file: */ 282 _thread_dump_info(); 283 284 /* Check if an interval timer signal: */ 285 else if (sig == _SCHED_SIGNAL) { 286 /* 287 * This shouldn't ever occur (should this panic?). 288 */ 289 } else { |
252 /* Check if a child has terminated: */ 253 if (sig == SIGCHLD) { 254 /* 255 * Go through the file list and set all files 256 * to non-blocking again in case the child 257 * set some of them to block. Sigh. 258 */ 259 for (i = 0; i < _thread_dtablesize; i++) { 260 /* Check if this file is used: */ 261 if (_thread_fd_table[i] != NULL) { 262 /* 263 * Set the file descriptor to 264 * non-blocking: 265 */ 266 _thread_sys_fcntl(i, F_SETFL, 267 _thread_fd_table[i]->flags | 268 O_NONBLOCK); 269 } 270 } 271 /* 272 * Enter a loop to wake up all threads waiting 273 * for a process to complete: 274 */ 275 for (pthread = TAILQ_FIRST(&_waitingq); 276 pthread != NULL; pthread = pthread_next) { 277 /* 278 * Grab the next thread before possibly 279 * destroying the link entry: 280 */ 281 pthread_next = TAILQ_NEXT(pthread, pqe); 282 283 /* 284 * If this thread is waiting for a child 285 * process to complete, wake it up: 286 */ 287 if (pthread->state == PS_WAIT_WAIT) { 288 /* Make the thread runnable: */ 289 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 290 291 /* Return the signal number: */ 292 pthread->signo = sig; 293 } 294 } 295 } 296 | |
297 /* | 290 /* |
298 * POSIX says that pending SIGCONT signals are 299 * discarded when one of these signals occurs. 300 */ 301 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { 302 /* 303 * Enter a loop to discard pending SIGCONT 304 * signals: 305 */ 306 TAILQ_FOREACH(pthread, &_thread_list, tle) { 307 sigdelset(&pthread->sigpend,SIGCONT); 308 } 309 } 310 311 /* | |
312 * Enter a loop to look for threads that have the signal 313 * unmasked. POSIX specifies that a thread in a sigwait 314 * will get the signal over any other threads. Second | 291 * Enter a loop to look for threads that have the signal 292 * unmasked. POSIX specifies that a thread in a sigwait 293 * will get the signal over any other threads. Second |
315 * preference will be threads in in a sigsuspend. If 316 * none of the above, then the signal is delivered to the 317 * first thread we find. Note that if a custom handler 318 * is not installed, the signal only affects threads in 319 * sigwait. | 294 * preference will be threads in in a sigsuspend. Third 295 * preference will be the current thread. If none of the 296 * above, then the signal is delivered to the first thread 297 * that is found. Note that if a custom handler is not 298 * installed, the signal only affects threads in sigwait. |
320 */ 321 suspended_thread = NULL; | 299 */ 300 suspended_thread = NULL; |
322 signaled_thread = NULL; | 301 if ((_thread_run != &_thread_kern_thread) && 302 !sigismember(&_thread_run->sigmask, sig)) 303 signaled_thread = _thread_run; 304 else 305 signaled_thread = NULL; |
323 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) || 324 (_thread_sigact[sig - 1].sa_handler == SIG_DFL)) 325 handler_installed = 0; 326 else 327 handler_installed = 1; 328 329 for (pthread = TAILQ_FIRST(&_waitingq); 330 pthread != NULL; pthread = pthread_next) { 331 /* 332 * Grab the next thread before possibly destroying 333 * the link entry. 334 */ 335 pthread_next = TAILQ_NEXT(pthread, pqe); 336 337 if ((pthread->state == PS_SIGWAIT) && 338 sigismember(pthread->data.sigwait, sig)) { 339 /* Change the state of the thread to run: */ 340 PTHREAD_NEW_STATE(pthread,PS_RUNNING); | 306 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) || 307 (_thread_sigact[sig - 1].sa_handler == SIG_DFL)) 308 handler_installed = 0; 309 else 310 handler_installed = 1; 311 312 for (pthread = TAILQ_FIRST(&_waitingq); 313 pthread != NULL; pthread = pthread_next) { 314 /* 315 * Grab the next thread before possibly destroying 316 * the link entry. 317 */ 318 pthread_next = TAILQ_NEXT(pthread, pqe); 319 320 if ((pthread->state == PS_SIGWAIT) && 321 sigismember(pthread->data.sigwait, sig)) { 322 /* Change the state of the thread to run: */ 323 PTHREAD_NEW_STATE(pthread,PS_RUNNING); |
324 /* 325 * A signal handler is not invoked for threads 326 * in sigwait. Clear the blocked and pending 327 * flags. 328 */ 329 _thread_sigq[sig - 1].blocked = 0; 330 _thread_sigq[sig - 1].pending = 0; |
|
341 342 /* Return the signal number: */ 343 pthread->signo = sig; 344 345 /* 346 * POSIX doesn't doesn't specify which thread 347 * will get the signal if there are multiple 348 * waiters, so we give it to the first thread 349 * we find. 350 * 351 * Do not attempt to deliver this signal | 331 332 /* Return the signal number: */ 333 pthread->signo = sig; 334 335 /* 336 * POSIX doesn't doesn't specify which thread 337 * will get the signal if there are multiple 338 * waiters, so we give it to the first thread 339 * we find. 340 * 341 * Do not attempt to deliver this signal |
352 * to other threads. | 342 * to other threads and do not add the signal 343 * to the process pending set. |
353 */ 354 return (NULL); 355 } 356 else if ((handler_installed != 0) && 357 !sigismember(&pthread->sigmask, sig)) { 358 if (pthread->state == PS_SIGSUSPEND) { 359 if (suspended_thread == NULL) 360 suspended_thread = pthread; 361 } else if (signaled_thread == NULL) 362 signaled_thread = pthread; 363 } 364 } 365 366 /* 367 * Only perform wakeups and signal delivery if there is a 368 * custom handler installed: 369 */ | 344 */ 345 return (NULL); 346 } 347 else if ((handler_installed != 0) && 348 !sigismember(&pthread->sigmask, sig)) { 349 if (pthread->state == PS_SIGSUSPEND) { 350 if (suspended_thread == NULL) 351 suspended_thread = pthread; 352 } else if (signaled_thread == NULL) 353 signaled_thread = pthread; 354 } 355 } 356 357 /* 358 * Only perform wakeups and signal delivery if there is a 359 * custom handler installed: 360 */ |
370 if (handler_installed != 0) { | 361 if (handler_installed == 0) { |
371 /* | 362 /* |
363 * There is no handler installed. Unblock the 364 * signal so that if a handler _is_ installed, any 365 * subsequent signals can be handled. 366 */ 367 _thread_sigq[sig - 1].blocked = 0; 368 } else { 369 /* |
|
372 * If we didn't find a thread in the waiting queue, 373 * check the all threads queue: 374 */ 375 if (suspended_thread == NULL && 376 signaled_thread == NULL) { 377 /* 378 * Enter a loop to look for other threads 379 * capable of receiving the signal: --- 18 unchanged lines hidden (view full) --- 398 /* 399 * We only deliver the signal to one thread; 400 * give preference to the suspended thread: 401 */ 402 if (suspended_thread != NULL) 403 pthread = suspended_thread; 404 else 405 pthread = signaled_thread; | 370 * If we didn't find a thread in the waiting queue, 371 * check the all threads queue: 372 */ 373 if (suspended_thread == NULL && 374 signaled_thread == NULL) { 375 /* 376 * Enter a loop to look for other threads 377 * capable of receiving the signal: --- 18 unchanged lines hidden (view full) --- 396 /* 397 * We only deliver the signal to one thread; 398 * give preference to the suspended thread: 399 */ 400 if (suspended_thread != NULL) 401 pthread = suspended_thread; 402 else 403 pthread = signaled_thread; |
406 407 /* 408 * Perform any state changes due to signal 409 * arrival: 410 */ 411 thread_sig_check_state(pthread, sig); | |
412 return (pthread); 413 } 414 } 415 } 416 417 /* Returns nothing. */ 418 return (NULL); 419} 420 | 404 return (pthread); 405 } 406 } 407 } 408 409 /* Returns nothing. */ 410 return (NULL); 411} 412 |
421static void 422thread_sig_finish_longjmp(void *arg) | 413void 414_thread_sig_check_pending(pthread_t pthread) |
423{ | 415{ |
416 sigset_t sigset; 417 int i; 418 |
|
424 /* | 419 /* |
425 * Check to see if the current thread performed a [_]longjmp() out of a 426 * signal handler. | 420 * Check if there are pending signals for the running 421 * thread or process that aren't blocked: |
427 */ | 422 */ |
428 if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP | JMPFLAGS__LONGJMP)) 429 != 0) { 430 _thread_run->jmpflags = JMPFLAGS_NONE; 431 _thread_run->continuation = NULL; 432 __longjmp(_thread_run->nested_jmp.jmp, 433 _thread_run->longjmp_val); | 423 sigset = pthread->sigpend; 424 SIGSETOR(sigset, _process_sigpending); 425 SIGSETNAND(sigset, pthread->sigmask); 426 if (SIGNOTEMPTY(sigset)) { 427 for (i = 1; i < NSIG; i++) { 428 if (sigismember(&sigset, i) != 0) { 429 if (sigismember(&pthread->sigpend, i) != 0) 430 thread_sig_add(pthread, i, 431 /*has_args*/ 0); 432 else { 433 thread_sig_add(pthread, i, 434 /*has_args*/ 1); 435 sigdelset(&_process_sigpending, i); 436 } 437 } 438 } |
434 } | 439 } |
440} 441 442/* 443 * This can only be called from the kernel scheduler. It assumes that 444 * all thread contexts are saved and that a signal frame can safely be 445 * added to any user thread. 446 */ 447void 448_thread_sig_handle_pending(void) 449{ 450 pthread_t pthread; 451 int i, sig; 452 453 PTHREAD_ASSERT(_thread_kern_in_sched != 0, 454 "_thread_sig_handle_pending called from outside kernel schedule"); |
|
435 /* | 455 /* |
436 * Check to see if the current thread performed a siglongjmp 437 * out of a signal handler: | 456 * Check the array of pending signals: |
438 */ | 457 */ |
439 else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) { 440 _thread_run->jmpflags = JMPFLAGS_NONE; 441 _thread_run->continuation = NULL; 442 __siglongjmp(_thread_run->nested_jmp.sigjmp, 443 _thread_run->longjmp_val); | 458 for (i = 0; i < NSIG; i++) { 459 if (_thread_sigq[i].pending != 0) { 460 /* This signal is no longer pending. */ 461 _thread_sigq[i].pending = 0; 462 463 sig = _thread_sigq[i].signo; 464 465 /* Some signals need special handling: */ 466 thread_sig_handle_special(sig); 467 468 if (_thread_sigq[i].blocked == 0) { 469 /* 470 * Block future signals until this one 471 * is handled: 472 */ 473 _thread_sigq[i].blocked = 1; 474 475 if ((pthread = thread_sig_find(sig)) != NULL) { 476 /* 477 * Setup the target thread to receive 478 * the signal: 479 */ 480 thread_sig_add(pthread, sig, 481 /*has_args*/ 1); 482 } 483 } 484 } |
444 } 445} 446 447static void | 485 } 486} 487 488static void |
448handle_state_change(pthread_t pthread) | 489thread_sig_handle_special(int sig) |
449{ | 490{ |
450 /* 451 * We should only need to handle threads whose state was 452 * changed to running: 453 */ 454 if (pthread->state == PS_RUNNING) { 455 switch (pthread->oldstate) { | 491 pthread_t pthread, pthread_next; 492 int i; 493 494 switch (sig) { 495 case SIGCHLD: |
456 /* | 496 /* |
457 * States which do not change when a signal is trapped: | 497 * Go through the file list and set all files 498 * to non-blocking again in case the child 499 * set some of them to block. Sigh. |
458 */ | 500 */ |
459 case PS_DEAD: 460 case PS_DEADLOCK: 461 case PS_RUNNING: 462 case PS_SIGTHREAD: 463 case PS_STATE_MAX: 464 case PS_SUSPENDED: 465 break; 466 | 501 for (i = 0; i < _thread_dtablesize; i++) { 502 /* Check if this file is used: */ 503 if (_thread_fd_table[i] != NULL) { 504 /* 505 * Set the file descriptor to non-blocking: 506 */ 507 _thread_sys_fcntl(i, F_SETFL, 508 _thread_fd_table[i]->flags | O_NONBLOCK); 509 } 510 } |
467 /* | 511 /* |
468 * States which need to return to critical sections 469 * before they can switch contexts: | 512 * Enter a loop to wake up all threads waiting 513 * for a process to complete: |
470 */ | 514 */ |
471 case PS_COND_WAIT: 472 case PS_FDLR_WAIT: 473 case PS_FDLW_WAIT: 474 case PS_FILE_WAIT: 475 case PS_JOIN: 476 case PS_MUTEX_WAIT: 477 /* Indicate that the thread was interrupted: */ 478 pthread->interrupted = 1; | 515 for (pthread = TAILQ_FIRST(&_waitingq); 516 pthread != NULL; pthread = pthread_next) { |
479 /* | 517 /* |
480 * Defer the [sig|_]longjmp until leaving the critical 481 * region: | 518 * Grab the next thread before possibly 519 * destroying the link entry: |
482 */ | 520 */ |
483 pthread->jmpflags |= JMPFLAGS_DEFERRED; | 521 pthread_next = TAILQ_NEXT(pthread, pqe); |
484 | 522 |
485 /* Set the continuation routine: */ 486 pthread->continuation = thread_sig_finish_longjmp; 487 /* FALLTHROUGH */ 488 case PS_FDR_WAIT: 489 case PS_FDW_WAIT: 490 case PS_POLL_WAIT: 491 case PS_SELECT_WAIT: 492 case PS_SIGSUSPEND: 493 case PS_SIGWAIT: 494 case PS_SLEEP_WAIT: 495 case PS_SPINBLOCK: 496 case PS_WAIT_WAIT: 497 if ((pthread->flags & PTHREAD_FLAGS_IN_WAITQ) != 0) { 498 PTHREAD_WAITQ_REMOVE(pthread); 499 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 500 PTHREAD_WORKQ_REMOVE(pthread); | 523 /* 524 * If this thread is waiting for a child 525 * process to complete, wake it up: 526 */ 527 if (pthread->state == PS_WAIT_WAIT) { 528 /* Make the thread runnable: */ 529 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 530 531 /* Return the signal number: */ 532 pthread->signo = sig; |
501 } | 533 } |
502 break; | |
503 } | 534 } |
535 break; |
|
504 | 536 |
505 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) 506 PTHREAD_PRIOQ_INSERT_TAIL(pthread); | 537 /* 538 * POSIX says that pending SIGCONT signals are 539 * discarded when one of these signals occurs. 540 */ 541 case SIGTSTP: 542 case SIGTTIN: 543 case SIGTTOU: 544 /* 545 * Enter a loop to discard pending SIGCONT 546 * signals: 547 */ 548 TAILQ_FOREACH(pthread, &_thread_list, tle) { 549 sigdelset(&pthread->sigpend, SIGCONT); 550 } 551 break; 552 553 default: 554 break; |
507 } 508} 509 | 555 } 556} 557 |
510 511/* Perform thread specific actions in response to a signal: */ | 558/* 559 * Perform thread specific actions in response to a signal. 560 * This function is only called if there is a handler installed 561 * for the signal, and if the target thread has the signal 562 * unmasked. 563 */ |
512static void | 564static void |
513thread_sig_check_state(pthread_t pthread, int sig) | 565thread_sig_add(pthread_t pthread, int sig, int has_args) |
514{ | 566{ |
567 int restart, frame; 568 int block_signals = 0; 569 int suppress_handler = 0; 570 571 restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; 572 |
|
515 /* 516 * Process according to thread state: 517 */ 518 switch (pthread->state) { 519 /* 520 * States which do not change when a signal is trapped: 521 */ | 573 /* 574 * Process according to thread state: 575 */ 576 switch (pthread->state) { 577 /* 578 * States which do not change when a signal is trapped: 579 */ |
522 case PS_COND_WAIT: | |
523 case PS_DEAD: 524 case PS_DEADLOCK: | 580 case PS_DEAD: 581 case PS_DEADLOCK: |
525 case PS_FILE_WAIT: 526 case PS_JOIN: 527 case PS_MUTEX_WAIT: 528 case PS_RUNNING: | |
529 case PS_STATE_MAX: 530 case PS_SIGTHREAD: | 582 case PS_STATE_MAX: 583 case PS_SIGTHREAD: |
531 case PS_SPINBLOCK: | 584 /* 585 * You can't call a signal handler for threads in these 586 * states. 587 */ 588 suppress_handler = 1; 589 break; 590 591 /* 592 * States which do not need any cleanup handling when signals 593 * occur: 594 */ 595 case PS_RUNNING: 596 /* 597 * Remove the thread from the queue before changing its 598 * priority: 599 */ 600 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) 601 PTHREAD_PRIOQ_REMOVE(pthread); 602 break; 603 |
532 case PS_SUSPENDED: | 604 case PS_SUSPENDED: |
533 /* Increment the pending signal count. */ 534 sigaddset(&pthread->sigpend,sig); | |
535 break; 536 | 605 break; 606 |
607 case PS_SPINBLOCK: 608 /* Remove the thread from the workq and waitq: */ 609 PTHREAD_WORKQ_REMOVE(pthread); 610 PTHREAD_WAITQ_REMOVE(pthread); 611 /* Make the thread runnable: */ 612 PTHREAD_SET_STATE(pthread, PS_RUNNING); 613 break; 614 |
|
537 case PS_SIGWAIT: | 615 case PS_SIGWAIT: |
616 /* The signal handler is not called for threads in SIGWAIT. */ 617 suppress_handler = 1; |
|
538 /* Wake up the thread if the signal is blocked. */ 539 if (sigismember(pthread->data.sigwait, sig)) { 540 /* Change the state of the thread to run: */ | 618 /* Wake up the thread if the signal is blocked. */ 619 if (sigismember(pthread->data.sigwait, sig)) { 620 /* Change the state of the thread to run: */ |
541 PTHREAD_NEW_STATE(pthread,PS_RUNNING); | 621 PTHREAD_NEW_STATE(pthread, PS_RUNNING); |
542 543 /* Return the signal number: */ 544 pthread->signo = sig; 545 } else 546 /* Increment the pending signal count. */ | 622 623 /* Return the signal number: */ 624 pthread->signo = sig; 625 } else 626 /* Increment the pending signal count. */ |
547 sigaddset(&pthread->sigpend,sig); | 627 sigaddset(&pthread->sigpend, sig); |
548 break; 549 550 /* 551 * The wait state is a special case due to the handling of 552 * SIGCHLD signals. 553 */ 554 case PS_WAIT_WAIT: | 628 break; 629 630 /* 631 * The wait state is a special case due to the handling of 632 * SIGCHLD signals. 633 */ 634 case PS_WAIT_WAIT: |
555 /* 556 * Check for signals other than the death of a child 557 * process: 558 */ 559 if (sig != SIGCHLD) 560 /* Flag the operation as interrupted: */ 561 pthread->interrupted = 1; | 635 if (sig == SIGCHLD) { 636 /* Change the state of the thread to run: */ 637 PTHREAD_WAITQ_REMOVE(pthread); 638 PTHREAD_SET_STATE(pthread, PS_RUNNING); |
562 | 639 |
563 /* Change the state of the thread to run: */ 564 PTHREAD_NEW_STATE(pthread,PS_RUNNING); | 640 /* Return the signal number: */ 641 pthread->signo = sig; 642 } 643 else { 644 /* 645 * Mark the thread as interrupted only if the 646 * restart flag is not set on the signal action: 647 */ 648 if (restart == 0) 649 pthread->interrupted = 1; 650 PTHREAD_WAITQ_REMOVE(pthread); 651 PTHREAD_SET_STATE(pthread, PS_RUNNING); 652 } 653 break; |
565 | 654 |
566 /* Return the signal number: */ 567 pthread->signo = sig; | 655 /* 656 * States which cannot be interrupted but still require the 657 * signal handler to run: 658 */ 659 case PS_COND_WAIT: 660 case PS_JOIN: 661 case PS_MUTEX_WAIT: 662 /* 663 * Remove the thread from the wait queue. It will 664 * be added back to the wait queue once all signal 665 * handlers have been invoked. 666 */ 667 PTHREAD_WAITQ_REMOVE(pthread); |
568 break; 569 570 /* | 668 break; 669 670 /* |
571 * States that are interrupted by the occurrence of a signal 572 * other than the scheduling alarm: | 671 * States which are interruptible but may need to be removed 672 * from queues before any signal handler is called. 673 * 674 * XXX - We may not need to handle this condition, but will 675 * mark it as a potential problem. |
573 */ 574 case PS_FDLR_WAIT: 575 case PS_FDLW_WAIT: | 676 */ 677 case PS_FDLR_WAIT: 678 case PS_FDLW_WAIT: |
679 case PS_FILE_WAIT: 680 if (restart == 0) 681 pthread->interrupted = 1; 682 /* 683 * Remove the thread from the wait queue. Our 684 * signal handler hook will remove this thread 685 * from the fd or file queue before invoking 686 * the actual handler. 687 */ 688 PTHREAD_WAITQ_REMOVE(pthread); 689 /* 690 * To ensure the thread is removed from the fd and file 691 * queues before any other signal interrupts it, set the 692 * signal mask to block all signals. As soon as the thread 693 * is removed from the queue the signal mask will be 694 * restored. 695 */ 696 block_signals = 1; 697 break; 698 699 /* 700 * States which are interruptible: 701 */ |
|
576 case PS_FDR_WAIT: 577 case PS_FDW_WAIT: | 702 case PS_FDR_WAIT: 703 case PS_FDW_WAIT: |
578 case PS_POLL_WAIT: 579 case PS_SLEEP_WAIT: 580 case PS_SELECT_WAIT: 581 if ((_thread_sigact[sig - 1].sa_flags & SA_RESTART) == 0) { 582 /* Flag the operation as interrupted: */ | 704 if (restart == 0) { 705 /* 706 * Flag the operation as interrupted and 707 * set the state to running: 708 */ |
583 pthread->interrupted = 1; | 709 pthread->interrupted = 1; |
584 585 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 586 PTHREAD_WORKQ_REMOVE(pthread); 587 588 /* Change the state of the thread to run: */ 589 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 590 591 /* Return the signal number: */ 592 pthread->signo = sig; | 710 PTHREAD_SET_STATE(pthread, PS_RUNNING); |
593 } | 711 } |
712 PTHREAD_WORKQ_REMOVE(pthread); 713 PTHREAD_WAITQ_REMOVE(pthread); |
|
594 break; 595 | 714 break; 715 |
596 case PS_SIGSUSPEND: | 716 case PS_POLL_WAIT: 717 case PS_SELECT_WAIT: 718 case PS_SLEEP_WAIT: |
597 /* | 719 /* |
598 * Only wake up the thread if there is a handler installed 599 * for the signal. | 720 * Unmasked signals always cause poll, select, and sleep 721 * to terminate early, regardless of SA_RESTART: |
600 */ | 722 */ |
601 if (_thread_sigact[sig - 1].sa_handler != SIG_DFL) { 602 /* Change the state of the thread to run: */ 603 PTHREAD_NEW_STATE(pthread,PS_RUNNING); | 723 pthread->interrupted = 1; 724 /* Remove threads in poll and select from the workq: */ 725 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) 726 PTHREAD_WORKQ_REMOVE(pthread); 727 PTHREAD_WAITQ_REMOVE(pthread); 728 PTHREAD_SET_STATE(pthread, PS_RUNNING); 729 break; |
604 | 730 |
605 /* Return the signal number: */ 606 pthread->signo = sig; 607 } | 731 case PS_SIGSUSPEND: 732 PTHREAD_WAITQ_REMOVE(pthread); 733 PTHREAD_SET_STATE(pthread, PS_RUNNING); |
608 break; 609 } | 734 break; 735 } |
736 737 if (suppress_handler == 0) { 738 /* 739 * Save the current state of the thread and add a 740 * new signal frame. 741 */ 742 frame = pthread->sigframe_count; 743 thread_sigframe_save(pthread, pthread->curframe); 744 thread_sigframe_add(pthread, sig); 745 pthread->sigframes[frame + 1]->sig_has_args = has_args; 746 SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask); 747 if (block_signals != 0) { 748 /* Save the signal mask and block all signals: */ 749 pthread->sigframes[frame + 1]->saved_state.psd_sigmask = 750 pthread->sigmask; 751 sigfillset(&pthread->sigmask); 752 } 753 754 /* Make sure the thread is runnable: */ 755 if (pthread->state != PS_RUNNING) 756 PTHREAD_SET_STATE(pthread, PS_RUNNING); 757 /* 758 * The thread should be removed from all scheduling 759 * queues at this point. Raise the priority and place 760 * the thread in the run queue. 761 */ 762 pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; 763 if (pthread != _thread_run) 764 PTHREAD_PRIOQ_INSERT_TAIL(pthread); 765 } |
|
610} 611 | 766} 767 |
612/* Send a signal to a specific thread (ala pthread_kill): */ | 768/* 769 * Send a signal to a specific thread (ala pthread_kill): 770 */ |
613void 614_thread_sig_send(pthread_t pthread, int sig) 615{ 616 /* 617 * Check that the signal is not being ignored: 618 */ 619 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 620 if (pthread->state == PS_SIGWAIT && 621 sigismember(pthread->data.sigwait, sig)) { 622 /* Change the state of the thread to run: */ | 771void 772_thread_sig_send(pthread_t pthread, int sig) 773{ 774 /* 775 * Check that the signal is not being ignored: 776 */ 777 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 778 if (pthread->state == PS_SIGWAIT && 779 sigismember(pthread->data.sigwait, sig)) { 780 /* Change the state of the thread to run: */ |
623 PTHREAD_NEW_STATE(pthread,PS_RUNNING); | 781 PTHREAD_NEW_STATE(pthread, PS_RUNNING); |
624 625 /* Return the signal number: */ 626 pthread->signo = sig; | 782 783 /* Return the signal number: */ 784 pthread->signo = sig; |
627 } else if (pthread->state != PS_SIGWAIT && 628 !sigismember(&pthread->sigmask, sig)) { 629 /* Perform any state changes due to signal arrival: */ 630 thread_sig_check_state(pthread, sig); 631 /* Increment the pending signal count. */ 632 sigaddset(&pthread->sigpend,sig); | 785 } else if (pthread == _thread_run) { 786 /* Add the signal to the pending set: */ 787 sigaddset(&pthread->sigpend, sig); 788 /* 789 * Deliver the signal to the process if a 790 * handler is not installed: 791 */ 792 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) 793 kill(getpid(), sig); 794 if (!sigismember(&pthread->sigmask, sig)) { 795 /* 796 * Call the kernel scheduler which will safely 797 * install a signal frame for this thread: 798 */ 799 _thread_kern_sched_sig(); 800 } |
633 } else { | 801 } else { |
634 /* Increment the pending signal count. */ 635 sigaddset(&pthread->sigpend,sig); | 802 if (pthread->state != PS_SIGWAIT && 803 !sigismember(&pthread->sigmask, sig)) { 804 /* Protect the scheduling queues: */ 805 _thread_kern_sig_defer(); 806 /* 807 * Perform any state changes due to signal 808 * arrival: 809 */ 810 thread_sig_add(pthread, sig, /* has args */ 0); 811 /* Unprotect the scheduling queues: */ 812 _thread_kern_sig_undefer(); 813 } 814 else 815 /* Increment the pending signal count. */ 816 sigaddset(&pthread->sigpend,sig); 817 818 /* 819 * Deliver the signal to the process if a 820 * handler is not installed: 821 */ 822 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) 823 kill(getpid(), sig); |
636 } 637 } 638} 639 | 824 } 825 } 826} 827 |
640/* Dispatch pending signals to the running thread: */ | 828/* 829 * User thread signal handler wrapper. 830 * 831 * thread - current running thread 832 */ |
641void | 833void |
642_dispatch_signals() | 834_thread_sig_wrapper(void) |
643{ | 835{ |
644 sigset_t sigset; 645 int i; | 836 void (*sigfunc)(int, siginfo_t *, void *); 837 struct pthread_signal_frame *psf; 838 pthread_t thread; 839 int dead = 0; 840 int i, sig, has_args; 841 int frame, dst_frame; |
646 | 842 |
843 thread = _thread_run; 844 845 /* Get the current frame and state: */ 846 frame = thread->sigframe_count; 847 PTHREAD_ASSERT(frame > 0, "Invalid signal frame in signal handler"); 848 psf = thread->curframe; 849 850 /* Check the threads previous state: */ 851 if (psf->saved_state.psd_state != PS_RUNNING) { 852 /* 853 * Do a little cleanup handling for those threads in 854 * queues before calling the signal handler. Signals 855 * for these threads are temporarily blocked until 856 * after cleanup handling. 857 */ 858 switch (psf->saved_state.psd_state) { 859 case PS_FDLR_WAIT: 860 case PS_FDLW_WAIT: 861 _fd_lock_backout(thread); 862 psf->saved_state.psd_state = PS_RUNNING; 863 /* Reenable signals: */ 864 thread->sigmask = psf->saved_state.psd_sigmask; 865 break; 866 867 case PS_FILE_WAIT: 868 _flockfile_backout(thread); 869 psf->saved_state.psd_state = PS_RUNNING; 870 /* Reenable signals: */ 871 thread->sigmask = psf->saved_state.psd_sigmask; 872 break; 873 874 default: 875 break; 876 } 877 } 878 |
|
647 /* | 879 /* |
648 * Check if there are pending signals for the running 649 * thread or process that aren't blocked: | 880 * Unless the thread exits or longjmps out of the signal handler, 881 * return to the previous frame: |
650 */ | 882 */ |
651 sigset = _thread_run->sigpend; 652 SIGSETOR(sigset, _process_sigpending); 653 SIGSETNAND(sigset, _thread_run->sigmask); 654 if (SIGNOTEMPTY(sigset)) { | 883 dst_frame = frame - 1; 884 885 /* 886 * Check that a custom handler is installed and if the signal 887 * is not blocked: 888 */ 889 sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction; 890 if (((__sighandler_t *)sigfunc != SIG_DFL) && 891 ((__sighandler_t *)sigfunc != SIG_IGN)) { |
655 /* | 892 /* |
656 * Enter a loop to calculate deliverable pending signals 657 * before actually delivering them. The pending signals 658 * must be removed from the pending signal sets before 659 * calling the signal handler because the handler may 660 * call library routines that again check for and deliver 661 * pending signals. | 893 * The signal jump buffer is allocated off the stack. 894 * If the signal handler tries to [_][sig]longjmp() or 895 * setcontext(), our wrapped versions of these routines 896 * will copy the user supplied jump buffer or context 897 * to the destination signal frame, set the destination 898 * signal frame in psf->dst_frame, and _longjmp() back 899 * to here. |
662 */ | 900 */ |
663 for (i = 1; i < NSIG; i++) { | 901 jmp_buf jb; 902 903 /* 904 * Set up the context for abnormal returns out of signal 905 * handlers. 906 */ 907 psf->sig_jb = &jb; 908 if (_setjmp(jb) == 0) { 909 DBG_MSG("_thread_sig_wrapper: Entering frame %d, " 910 "stack 0x%lx\n", frame, GET_STACK_JB(jb)); |
664 /* | 911 /* |
665 * Check that a custom handler is installed 666 * and if the signal is not blocked: | 912 * Invalidate the destination frame before calling 913 * the signal handler. |
667 */ | 914 */ |
668 if (_thread_sigact[i - 1].sa_handler != SIG_DFL && 669 _thread_sigact[i - 1].sa_handler != SIG_IGN && 670 sigismember(&sigset, i)) { 671 if (sigismember(&_thread_run->sigpend,i)) 672 /* Clear the thread pending signal: */ 673 sigdelset(&_thread_run->sigpend,i); 674 else 675 /* Clear the process pending signal: */ 676 sigdelset(&_process_sigpending,i); 677 } | 915 psf->dst_frame = -1; 916 917 /* 918 * Dispatch the signal via the custom signal 919 * handler: 920 */ 921 if (psf->sig_has_args == 0) 922 (*(sigfunc))(psf->signo, NULL, NULL); 923 else if ((_thread_sigact[psf->signo - 1].sa_flags & 924 SA_SIGINFO) != 0) 925 (*(sigfunc))(psf->signo, 926 &_thread_sigq[psf->signo - 1].siginfo, 927 &_thread_sigq[psf->signo - 1].uc); |
678 else | 928 else |
679 /* Remove the signal if it can't be handled: */ 680 sigdelset(&sigset, i); | 929 (*(sigfunc))(psf->signo, 930 (siginfo_t *)_thread_sigq[psf->signo - 1].siginfo.si_code, 931 &_thread_sigq[psf->signo - 1].uc); |
681 } | 932 } |
933 else { 934 /* 935 * The return from _setjmp() should only be non-zero 936 * when the signal handler wants to xxxlongjmp() or 937 * setcontext() to a different context, or if the 938 * thread has exited (via pthread_exit). 939 */ 940 /* 941 * Grab a copy of the destination frame before it 942 * gets clobbered after unwinding. 943 */ 944 dst_frame = psf->dst_frame; 945 DBG_MSG("Abnormal exit from handler for signal %d, " 946 "frame %d\n", psf->signo, frame); |
|
682 | 947 |
683 /* Now deliver the signals: */ 684 for (i = 1; i < NSIG; i++) { 685 if (sigismember(&sigset, i)) 686 /* Deliver the signal to the running thread: */ 687 _thread_sig_deliver(_thread_run, i); | 948 /* Has the thread exited? */ 949 if ((dead = thread->flags & PTHREAD_EXITING) != 0) 950 /* When exiting, unwind to frame 0. */ 951 dst_frame = 0; 952 else if ((dst_frame < 0) || (dst_frame > frame)) 953 PANIC("Attempt to unwind to invalid " 954 "signal frame"); 955 956 /* Unwind to the target frame: */ 957 for (i = frame; i > dst_frame; i--) { 958 DBG_MSG("Leaving frame %d, signal %d\n", i, 959 thread->sigframes[i]->signo); 960 /* Leave the current signal frame: */ 961 thread_sigframe_leave(thread, i); 962 963 /* 964 * Save whatever is needed out of the state 965 * data; as soon as the frame count is 966 * is decremented, another signal can arrive 967 * and corrupt this view of the state data. 968 */ 969 sig = thread->sigframes[i]->signo; 970 has_args = thread->sigframes[i]->sig_has_args; 971 972 /* 973 * We're done with this signal frame: 974 */ 975 thread->curframe = thread->sigframes[i - 1]; 976 thread->sigframe_count = i - 1; 977 978 /* 979 * Only unblock the signal if it was a 980 * process signal as opposed to a signal 981 * generated by pthread_kill(). 982 */ 983 if (has_args != 0) 984 _thread_sigq[sig - 1].blocked = 0; 985 } |
688 } 689 } | 986 } 987 } |
988 989 /* 990 * Call the kernel scheduler to schedule the next 991 * thread. 992 */ 993 if (dead == 0) { 994 /* Restore the threads state: */ 995 thread_sigframe_restore(thread, thread->sigframes[dst_frame]); 996 _thread_kern_sched_frame(dst_frame); 997 } 998 else { 999 PTHREAD_ASSERT(dst_frame == 0, 1000 "Invalid signal frame for dead thread"); 1001 1002 /* Perform any necessary cleanup before exiting. */ 1003 thread_sigframe_leave(thread, 0); 1004 1005 /* This should never return: */ 1006 _thread_exit_finish(); 1007 PANIC("Return from _thread_exit_finish in signal wrapper"); 1008 } |
|
690} 691 | 1009} 1010 |
692/* Deliver a signal to a thread: */ 693void 694_thread_sig_deliver(pthread_t pthread, int sig) | 1011static void 1012thread_sigframe_add(pthread_t thread, int sig) |
695{ | 1013{ |
696 sigset_t mask; 697 pthread_t pthread_saved; 698 jmp_buf jb, *saved_sighandler_jmp_buf; | 1014 unsigned long stackp = 0; |
699 | 1015 |
1016 /* Get the top of the threads stack: */ 1017 switch (thread->curframe->ctxtype) { 1018 case CTX_JB: 1019 case CTX_JB_NOSIG: 1020 stackp = GET_STACK_JB(thread->curframe->ctx.jb); 1021 break; 1022 case CTX_SJB: 1023 stackp = GET_STACK_SJB(thread->curframe->ctx.sigjb); 1024 break; 1025 case CTX_UC: 1026 stackp = GET_STACK_UC(&thread->curframe->ctx.uc); 1027 break; 1028 default: 1029 PANIC("Invalid thread context type"); 1030 break; 1031 } 1032 |
|
700 /* | 1033 /* |
701 * Check that a custom handler is installed 702 * and if the signal is not blocked: | 1034 * Leave a little space on the stack and round down to the 1035 * nearest aligned word: |
703 */ | 1036 */ |
704 if (_thread_sigact[sig - 1].sa_handler != SIG_DFL && 705 _thread_sigact[sig - 1].sa_handler != SIG_IGN) { 706 /* Save the current thread: */ 707 pthread_saved = _thread_run; | 1037 stackp -= sizeof(double); 1038 stackp &= ~0x3UL; |
708 | 1039 |
709 /* Save the threads signal mask: */ 710 mask = pthread->sigmask; | 1040 /* Allocate room on top of the stack for a new signal frame: */ 1041 stackp -= sizeof(struct pthread_signal_frame); |
711 | 1042 |
712 /* 713 * Add the current signal and signal handler 714 * mask to the thread's current signal mask: 715 */ 716 SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask); 717 sigaddset(&pthread->sigmask, sig); | 1043 /* Set up the new frame: */ 1044 thread->sigframe_count++; 1045 thread->sigframes[thread->sigframe_count] = 1046 (struct pthread_signal_frame *) stackp; 1047 thread->curframe = thread->sigframes[thread->sigframe_count]; 1048 thread->curframe->stackp = stackp; 1049 thread->curframe->ctxtype = CTX_JB; 1050 thread->curframe->longjmp_val = 1; 1051 thread->curframe->signo = sig; |
718 | 1052 |
719 /* Current thread inside critical region? */ 720 if (_thread_run->sig_defer_count > 0) 721 pthread->sig_defer_count++; | 1053 /* 1054 * Set up the context: 1055 */ 1056 _setjmp(thread->curframe->ctx.jb); 1057 SET_STACK_JB(thread->curframe->ctx.jb, stackp); 1058 SET_RETURN_ADDR_JB(thread->curframe->ctx.jb, _thread_sig_wrapper); 1059} |
722 | 1060 |
723 /* Increment the number of nested signals being handled. */ 724 pthread->signal_nest_level++; | 1061/* 1062 * Locate the signal frame from the specified stack pointer. 1063 */ 1064int 1065_thread_sigframe_find(pthread_t pthread, void *stackp) 1066{ 1067 int frame; |
725 | 1068 |
726 /* 727 * The jump buffer is allocated off the stack and the current 728 * jump buffer is saved. If the signal handler tries to 729 * [sig|_]longjmp(), our version of [sig|_]longjmp() will copy 730 * the user supplied jump buffer into 731 * _thread_run->nested_jmp.[sig]jmp and _longjmp() back to here. 732 */ 733 saved_sighandler_jmp_buf = pthread->sighandler_jmp_buf; 734 pthread->sighandler_jmp_buf = &jb; | 1069 /* 1070 * Find the destination of the target frame based on the 1071 * given stack pointer. 1072 */ 1073 for (frame = pthread->sigframe_count; frame >= 0; frame--) { 1074 if (stackp < (void *)pthread->sigframes[frame]->stackp) 1075 break; 1076 } 1077 return (frame); 1078} 1079 1080void 1081thread_sigframe_leave(pthread_t thread, int frame) 1082{ 1083 struct pthread_state_data *psd; |
735 | 1084 |
736 _thread_run = pthread; | 1085 psd = &thread->sigframes[frame]->saved_state; |
737 | 1086 |
738 if (_setjmp(jb) == 0) { 739 /* 740 * Dispatch the signal via the custom signal 741 * handler: 742 */ 743 (*(_thread_sigact[sig - 1].sa_handler))(sig); 744 } | 1087 /* 1088 * Perform any necessary cleanup for this signal frame: 1089 */ 1090 switch (psd->psd_state) { 1091 case PS_DEAD: 1092 case PS_DEADLOCK: 1093 case PS_RUNNING: 1094 case PS_SIGTHREAD: 1095 case PS_STATE_MAX: 1096 case PS_SUSPENDED: 1097 break; |
745 | 1098 |
746 _thread_run = pthread_saved; | 1099 /* 1100 * Threads in the following states need to be removed 1101 * from queues. 1102 */ 1103 case PS_COND_WAIT: 1104 _cond_wait_backout(thread); 1105 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) 1106 PTHREAD_WAITQ_REMOVE(thread); 1107 break; |
747 | 1108 |
748 pthread->sighandler_jmp_buf = saved_sighandler_jmp_buf; | 1109 case PS_FDLR_WAIT: 1110 case PS_FDLW_WAIT: 1111 _fd_lock_backout(thread); 1112 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) 1113 PTHREAD_WAITQ_REMOVE(thread); 1114 break; |
749 | 1115 |
750 /* Decrement the signal nest level. */ 751 pthread->signal_nest_level--; | 1116 case PS_FILE_WAIT: 1117 _flockfile_backout(thread); 1118 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) 1119 PTHREAD_WAITQ_REMOVE(thread); 1120 break; |
752 | 1121 |
753 /* Current thread inside critical region? */ 754 if (_thread_run->sig_defer_count > 0) 755 pthread->sig_defer_count--; | 1122 case PS_JOIN: 1123 _join_backout(thread); 1124 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) 1125 PTHREAD_WAITQ_REMOVE(thread); 1126 break; |
756 | 1127 |
757 /* Restore the threads signal mask: */ 758 pthread->sigmask = mask; | 1128 case PS_MUTEX_WAIT: 1129 _mutex_lock_backout(thread); 1130 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) 1131 PTHREAD_WAITQ_REMOVE(thread); 1132 break; 1133 1134 case PS_FDR_WAIT: 1135 case PS_FDW_WAIT: 1136 case PS_POLL_WAIT: 1137 case PS_SELECT_WAIT: 1138 case PS_SIGSUSPEND: 1139 case PS_SIGWAIT: 1140 case PS_SLEEP_WAIT: 1141 case PS_SPINBLOCK: 1142 case PS_WAIT_WAIT: 1143 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) { 1144 PTHREAD_WAITQ_REMOVE(thread); 1145 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WORKQ) != 0) 1146 PTHREAD_WORKQ_REMOVE(thread); 1147 } 1148 break; |
759 } 760} | 1149 } 1150} |
1151 1152static void 1153thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf) 1154{ 1155 thread->interrupted = psf->saved_state.psd_interrupted; 1156 thread->sigmask = psf->saved_state.psd_sigmask; 1157 thread->state = psf->saved_state.psd_state; 1158 thread->flags = psf->saved_state.psd_flags; 1159 thread->wakeup_time = psf->saved_state.psd_wakeup_time; 1160 thread->data = psf->saved_state.psd_wait_data; 1161} 1162 1163static void 1164thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf) 1165{ 1166 psf->saved_state.psd_interrupted = thread->interrupted; 1167 psf->saved_state.psd_sigmask = thread->sigmask; 1168 psf->saved_state.psd_state = thread->state; 1169 psf->saved_state.psd_flags = thread->flags; 1170 thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE | 1171 PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ | 1172 PTHREAD_FLAGS_IN_JOINQ; 1173 psf->saved_state.psd_wakeup_time = thread->wakeup_time; 1174 psf->saved_state.psd_wait_data = thread->data; 1175} 1176 |
|
761#endif | 1177#endif |