thr_sig.c (44963) | thr_sig.c (48046) |
---|---|
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 * $Id$ |
|
32 */ 33#include <signal.h> 34#include <fcntl.h> 35#include <unistd.h> 36#include <errno.h> 37#ifdef _THREAD_SAFE 38#include <pthread.h> 39#include "pthread_private.h" 40 | 33 */ 34#include <signal.h> 35#include <fcntl.h> 36#include <unistd.h> 37#include <errno.h> 38#ifdef _THREAD_SAFE 39#include <pthread.h> 40#include "pthread_private.h" 41 |
41/* 42 * State change macro for signal handler: 43 */ 44#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \ 45 if ((_thread_run->sched_defer_count == 0) && \ 46 (_thread_kern_in_sched == 0)) { \ 47 PTHREAD_NEW_STATE(thrd, newstate); \ 48 } else { \ 49 _waitingq_check_reqd = 1; \ 50 PTHREAD_SET_STATE(thrd, newstate); \ 51 } \ 52} 53 | |
54/* Static variables: */ | 42/* Static variables: */ |
55static int volatile yield_on_unlock_thread = 0; 56static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER; | 43static spinlock_t signal_lock = _SPINLOCK_INITIALIZER; 44unsigned int pending_sigs[NSIG]; 45unsigned int handled_sigs[NSIG]; 46int volatile check_pending = 0; |
57 | 47 |
58/* Lock the thread list: */ | 48/* Initialize signal handling facility: */ |
59void | 49void |
60_lock_thread_list() | 50_thread_sig_init(void) |
61{ | 51{ |
62 /* Lock the thread list: */ 63 _SPINLOCK(&thread_link_list_lock); 64} | 52 int i; |
65 | 53 |
66/* Lock the thread list: */ 67void 68_unlock_thread_list() 69{ 70 /* Unlock the thread list: */ 71 _SPINUNLOCK(&thread_link_list_lock); 72 73 /* 74 * Check if a scheduler interrupt occurred while the thread 75 * list was locked: 76 */ 77 if (yield_on_unlock_thread) { 78 /* Reset the interrupt flag: */ 79 yield_on_unlock_thread = 0; 80 81 /* This thread has overstayed it's welcome: */ 82 sched_yield(); | 54 /* Clear pending and handled signal counts: */ 55 for (i = 1; i < NSIG; i++) { 56 pending_sigs[i - 1] = 0; 57 handled_sigs[i - 1] = 0; |
83 } | 58 } |
59 60 /* Clear the lock: */ 61 signal_lock.access_lock = 0; |
|
84} 85 86void 87_thread_sig_handler(int sig, int code, struct sigcontext * scp) 88{ | 62} 63 64void 65_thread_sig_handler(int sig, int code, struct sigcontext * scp) 66{ |
89 char c; 90 int i; 91 pthread_t pthread; | 67 char c; 68 int i; |
92 | 69 |
93 /* 94 * Check if the pthread kernel has unblocked signals (or is about to) 95 * and was on its way into a _select when the current 96 * signal interrupted it: 97 */ 98 if (_thread_kern_in_select) { 99 /* Cast the signal number to a character variable: */ 100 c = sig; 101 102 /* 103 * Write the signal number to the kernel pipe so that it will 104 * be ready to read when this signal handler returns. This 105 * means that the _select call will complete 106 * immediately. 107 */ 108 _thread_sys_write(_thread_kern_pipe[1], &c, 1); 109 } 110 /* Check if the signal requires a dump of thread information: */ 111 if (sig == SIGINFO) 112 /* Dump thread information to file: */ 113 _thread_dump_info(); 114 | |
115 /* Check if an interval timer signal: */ | 70 /* Check if an interval timer signal: */ |
116 else if (sig == _SCHED_SIGNAL) { 117 /* Check if the scheduler interrupt has come at an 118 * unfortunate time which one of the threads is 119 * modifying the thread list: 120 */ 121 if (thread_link_list_lock.access_lock) | 71 if (sig == _SCHED_SIGNAL) { 72 if (_thread_kern_in_sched != 0) { |
122 /* | 73 /* |
123 * Set a flag so that the thread that has 124 * the lock yields when it unlocks the 125 * thread list: | 74 * The scheduler is already running; ignore this 75 * signal. |
126 */ | 76 */ |
127 yield_on_unlock_thread = 1; 128 | 77 } |
129 /* 130 * Check if the scheduler interrupt has come when 131 * the currently running thread has deferred thread | 78 /* 79 * Check if the scheduler interrupt has come when 80 * the currently running thread has deferred thread |
132 * scheduling. | 81 * signals. |
133 */ | 82 */ |
134 else if (_thread_run->sched_defer_count) 135 _thread_run->yield_on_sched_undefer = 1; | 83 else if (_thread_run->sig_defer_count > 0) 84 _thread_run->yield_on_sig_undefer = 1; |
136 | 85 |
137 /* 138 * Check if the kernel has not been interrupted while 139 * executing scheduler code: 140 */ 141 else if (!_thread_kern_in_sched) { | 86 else { |
142 /* 143 * Schedule the next thread. This function is not 144 * expected to return because it will do a longjmp 145 * instead. 146 */ 147 _thread_kern_sched(scp); 148 149 /* 150 * This point should not be reached, so abort the 151 * process: 152 */ 153 PANIC("Returned to signal function from scheduler"); 154 } | 87 /* 88 * Schedule the next thread. This function is not 89 * expected to return because it will do a longjmp 90 * instead. 91 */ 92 _thread_kern_sched(scp); 93 94 /* 95 * This point should not be reached, so abort the 96 * process: 97 */ 98 PANIC("Returned to signal function from scheduler"); 99 } |
100 } 101 /* 102 * Check if the kernel has been interrupted while the scheduler 103 * is accessing the scheduling queues or if there is a currently 104 * running thread that has deferred signals. 105 */ 106 else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) && 107 (_thread_run->sig_defer_count > 0))) { 108 /* Cast the signal number to a character variable: */ 109 c = sig; 110 111 /* 112 * Write the signal number to the kernel pipe so that it will 113 * be ready to read when this signal handler returns. 114 */ 115 _thread_sys_write(_thread_kern_pipe[1], &c, 1); 116 117 /* Indicate that there are queued signals in the pipe. */ 118 _sigq_check_reqd = 1; 119 } 120 else { 121 if (_atomic_lock(&signal_lock.access_lock)) { 122 /* There is another signal handler running: */ 123 pending_sigs[sig - 1]++; 124 check_pending = 1; 125 } 126 else { 127 /* It's safe to handle the signal now. */ 128 _thread_sig_handle(sig, scp); 129 130 /* Reset the pending and handled count back to 0: */ 131 pending_sigs[sig - 1] = 0; 132 handled_sigs[sig - 1] = 0; 133 134 signal_lock.access_lock = 0; 135 } 136 137 /* Enter a loop to process pending signals: */ 138 while ((check_pending != 0) && 139 (_atomic_lock(&signal_lock.access_lock) == 0)) { 140 check_pending = 0; 141 for (i = 1; i < NSIG; i++) { 142 if (pending_sigs[i - 1] > handled_sigs[i - 1]) 143 _thread_sig_handle(i, scp); 144 } 145 signal_lock.access_lock = 0; 146 } 147 } 148} 149 150void 151_thread_sig_handle(int sig, struct sigcontext * scp) 152{ 153 int i; 154 pthread_t pthread, pthread_next; 155 156 /* Check if the signal requires a dump of thread information: */ 157 if (sig == SIGINFO) 158 /* Dump thread information to file: */ 159 _thread_dump_info(); 160 161 /* Check if an interval timer signal: */ 162 else if (sig == _SCHED_SIGNAL) { 163 /* 164 * This shouldn't ever occur (should this panic?). 165 */ |
|
155 } else { 156 /* Check if a child has terminated: */ 157 if (sig == SIGCHLD) { 158 /* 159 * Go through the file list and set all files 160 * to non-blocking again in case the child 161 * set some of them to block. Sigh. 162 */ --- 15 unchanged lines hidden (view full) --- 178 * POSIX says that pending SIGCONT signals are 179 * discarded when one of these signals occurs. 180 */ 181 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { 182 /* 183 * Enter a loop to discard pending SIGCONT 184 * signals: 185 */ | 166 } else { 167 /* Check if a child has terminated: */ 168 if (sig == SIGCHLD) { 169 /* 170 * Go through the file list and set all files 171 * to non-blocking again in case the child 172 * set some of them to block. Sigh. 173 */ --- 15 unchanged lines hidden (view full) --- 189 * POSIX says that pending SIGCONT signals are 190 * discarded when one of these signals occurs. 191 */ 192 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { 193 /* 194 * Enter a loop to discard pending SIGCONT 195 * signals: 196 */ |
186 for (pthread = _thread_link_list; 187 pthread != NULL; 188 pthread = pthread->nxt) | 197 TAILQ_FOREACH(pthread, &_thread_list, tle) { |
189 sigdelset(&pthread->sigpend,SIGCONT); | 198 sigdelset(&pthread->sigpend,SIGCONT); |
199 } |
|
190 } 191 192 /* 193 * Enter a loop to process each thread in the waiting 194 * list that is sigwait-ing on a signal. Since POSIX 195 * doesn't specify which thread will get the signal 196 * if there are multiple waiters, we'll give it to the 197 * first one we find. 198 */ | 200 } 201 202 /* 203 * Enter a loop to process each thread in the waiting 204 * list that is sigwait-ing on a signal. Since POSIX 205 * doesn't specify which thread will get the signal 206 * if there are multiple waiters, we'll give it to the 207 * first one we find. 208 */ |
199 TAILQ_FOREACH(pthread, &_waitingq, pqe) { | 209 for (pthread = TAILQ_FIRST(&_waitingq); 210 pthread != NULL; pthread = pthread_next) { 211 /* 212 * Grab the next thread before possibly destroying 213 * the link entry. 214 */ 215 pthread_next = TAILQ_NEXT(pthread, pqe); 216 |
200 if ((pthread->state == PS_SIGWAIT) && 201 sigismember(pthread->data.sigwait, sig)) { 202 /* Change the state of the thread to run: */ | 217 if ((pthread->state == PS_SIGWAIT) && 218 sigismember(pthread->data.sigwait, sig)) { 219 /* Change the state of the thread to run: */ |
203 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); | 220 PTHREAD_NEW_STATE(pthread,PS_RUNNING); |
204 205 /* Return the signal number: */ 206 pthread->signo = sig; 207 208 /* 209 * Do not attempt to deliver this signal 210 * to other threads. 211 */ 212 return; 213 } 214 } 215 216 /* Check if the signal is not being ignored: */ 217 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) 218 /* 219 * Enter a loop to process each thread in the linked 220 * list: 221 */ | 221 222 /* Return the signal number: */ 223 pthread->signo = sig; 224 225 /* 226 * Do not attempt to deliver this signal 227 * to other threads. 228 */ 229 return; 230 } 231 } 232 233 /* Check if the signal is not being ignored: */ 234 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) 235 /* 236 * Enter a loop to process each thread in the linked 237 * list: 238 */ |
222 for (pthread = _thread_link_list; pthread != NULL; 223 pthread = pthread->nxt) { | 239 TAILQ_FOREACH(pthread, &_thread_list, tle) { |
224 pthread_t pthread_saved = _thread_run; 225 | 240 pthread_t pthread_saved = _thread_run; 241 |
242 /* Current thread inside critical region? */ 243 if (_thread_run->sig_defer_count > 0) 244 pthread->sig_defer_count++; 245 |
|
226 _thread_run = pthread; 227 _thread_signal(pthread,sig); 228 229 /* 230 * Dispatch pending signals to the 231 * running thread: 232 */ 233 _dispatch_signals(); 234 _thread_run = pthread_saved; | 246 _thread_run = pthread; 247 _thread_signal(pthread,sig); 248 249 /* 250 * Dispatch pending signals to the 251 * running thread: 252 */ 253 _dispatch_signals(); 254 _thread_run = pthread_saved; |
255 256 /* Current thread inside critical region? */ 257 if (_thread_run->sig_defer_count > 0) 258 pthread->sig_defer_count--; |
|
235 } 236 } 237 238 /* Returns nothing. */ 239 return; 240} 241 242/* Perform thread specific actions in response to a signal: */ --- 36 unchanged lines hidden (view full) --- 279 * Check for signals other than the death of a child 280 * process: 281 */ 282 if (sig != SIGCHLD) 283 /* Flag the operation as interrupted: */ 284 pthread->interrupted = 1; 285 286 /* Change the state of the thread to run: */ | 259 } 260 } 261 262 /* Returns nothing. */ 263 return; 264} 265 266/* Perform thread specific actions in response to a signal: */ --- 36 unchanged lines hidden (view full) --- 303 * Check for signals other than the death of a child 304 * process: 305 */ 306 if (sig != SIGCHLD) 307 /* Flag the operation as interrupted: */ 308 pthread->interrupted = 1; 309 310 /* Change the state of the thread to run: */ |
287 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); | 311 PTHREAD_NEW_STATE(pthread,PS_RUNNING); |
288 289 /* Return the signal number: */ 290 pthread->signo = sig; 291 break; 292 293 /* 294 * States that are interrupted by the occurrence of a signal 295 * other than the scheduling alarm: 296 */ 297 case PS_FDR_WAIT: 298 case PS_FDW_WAIT: | 312 313 /* Return the signal number: */ 314 pthread->signo = sig; 315 break; 316 317 /* 318 * States that are interrupted by the occurrence of a signal 319 * other than the scheduling alarm: 320 */ 321 case PS_FDR_WAIT: 322 case PS_FDW_WAIT: |
323 case PS_POLL_WAIT: |
|
299 case PS_SLEEP_WAIT: 300 case PS_SELECT_WAIT: 301 if (sig != SIGCHLD || 302 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 303 /* Flag the operation as interrupted: */ 304 pthread->interrupted = 1; 305 | 324 case PS_SLEEP_WAIT: 325 case PS_SELECT_WAIT: 326 if (sig != SIGCHLD || 327 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 328 /* Flag the operation as interrupted: */ 329 pthread->interrupted = 1; 330 |
331 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 332 PTHREAD_WORKQ_REMOVE(pthread); 333 |
|
306 /* Change the state of the thread to run: */ | 334 /* Change the state of the thread to run: */ |
307 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); | 335 PTHREAD_NEW_STATE(pthread,PS_RUNNING); |
308 309 /* Return the signal number: */ 310 pthread->signo = sig; 311 } 312 break; 313 314 case PS_SIGSUSPEND: 315 /* 316 * Only wake up the thread if the signal is unblocked 317 * and there is a handler installed for the signal. 318 */ 319 if (!sigismember(&pthread->sigmask, sig) && 320 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 321 /* Change the state of the thread to run: */ | 336 337 /* Return the signal number: */ 338 pthread->signo = sig; 339 } 340 break; 341 342 case PS_SIGSUSPEND: 343 /* 344 * Only wake up the thread if the signal is unblocked 345 * and there is a handler installed for the signal. 346 */ 347 if (!sigismember(&pthread->sigmask, sig) && 348 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 349 /* Change the state of the thread to run: */ |
322 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); | 350 PTHREAD_NEW_STATE(pthread,PS_RUNNING); |
323 324 /* Return the signal number: */ 325 pthread->signo = sig; 326 } 327 break; 328 } 329} 330 --- 32 unchanged lines hidden --- | 351 352 /* Return the signal number: */ 353 pthread->signo = sig; 354 } 355 break; 356 } 357} 358 --- 32 unchanged lines hidden --- |