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 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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 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 */ 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 41/* Static variables: */ 42static int volatile yield_on_unlock_dead = 0; 43static int volatile yield_on_unlock_thread = 0; 44static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER; 45static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER; 46 47/* Lock the thread list: */ 48void 49_lock_thread_list() 50{ 51 /* Lock the thread list: */ 52 _SPINLOCK(&thread_link_list_lock); 53} 54 55/* Lock the dead thread list: */ 56void 57_lock_dead_thread_list() 58{ 59 /* Lock the dead thread list: */ 60 _SPINLOCK(&thread_dead_lock); 61} 62 63/* Lock the thread list: */ 64void 65_unlock_thread_list() 66{ 67 /* Unlock the thread list: */ 68 _SPINUNLOCK(&thread_link_list_lock); 69 70 /* 71 * Check if a scheduler interrupt occurred while the thread 72 * list was locked: 73 */ 74 if (yield_on_unlock_thread) { 75 /* Reset the interrupt flag: */ 76 yield_on_unlock_thread = 0; 77 78 /* This thread has overstayed it's welcome: */ 79 sched_yield(); 80 } 81} 82 83/* Lock the dead thread list: */ 84void 85_unlock_dead_thread_list() 86{ 87 /* Unlock the dead thread list: */ 88 _SPINUNLOCK(&thread_dead_lock); 89 90 /* 91 * Check if a scheduler interrupt occurred while the dead 92 * thread list was locked: 93 */ 94 if (yield_on_unlock_dead) { 95 /* Reset the interrupt flag: */ 96 yield_on_unlock_dead = 0; 97 98 /* This thread has overstayed it's welcome: */ 99 sched_yield(); 100 } 101} 102 103void 104_thread_sig_handler(int sig, int code, struct sigcontext * scp) 105{ 106 char c; 107 int i; 108 int dispatch = 0; 109 pthread_t pthread; 110 111 /* 112 * Check if the pthread kernel has unblocked signals (or is about to) 113 * and was on its way into a _select when the current 114 * signal interrupted it: 115 */ 116 if (_thread_kern_in_select) { 117 /* Cast the signal number to a character variable: */ 118 c = sig; 119 120 /* 121 * Write the signal number to the kernel pipe so that it will 122 * be ready to read when this signal handler returns. This 123 * means that the _select call will complete 124 * immediately. 125 */ 126 _thread_sys_write(_thread_kern_pipe[1], &c, 1); 127 } 128 129 /* Check if the signal requires a dump of thread information: */ 130 if (sig == SIGINFO) 131 /* Dump thread information to file: */ 132 _thread_dump_info(); 133 134 /* Check if an interval timer signal: */ 135 else if (sig == SIGVTALRM) { 136 /* Check if the scheduler interrupt has come at an 137 * unfortunate time which one of the threads is 138 * modifying the thread list: 139 */ 140 if (thread_link_list_lock.access_lock) 141 /* 142 * Set a flag so that the thread that has 143 * the lock yields when it unlocks the 144 * thread list: 145 */ 146 yield_on_unlock_thread = 1; 147 148 /* Check if the scheduler interrupt has come at an 149 * unfortunate time which one of the threads is 150 * modifying the dead thread list: 151 */ 152 if (thread_dead_lock.access_lock) 153 /* 154 * Set a flag so that the thread that has 155 * the lock yields when it unlocks the 156 * dead thread list: 157 */ 158 yield_on_unlock_dead = 1; 159 160 /* 161 * Check if the kernel has not been interrupted while 162 * executing scheduler code: 163 */ 164 else if (!_thread_kern_in_sched) { 165 /* 166 * Schedule the next thread. This function is not 167 * expected to return because it will do a longjmp 168 * instead. 169 */ 170 _thread_kern_sched(scp); 171 172 /* 173 * This point should not be reached, so abort the 174 * process: 175 */ 176 PANIC("Returned to signal function from scheduler"); 177 } 178 } else { 179 /* Check if a child has terminated: */ 180 if (sig == SIGCHLD) { 181 /* 182 * Go through the file list and set all files 183 * to non-blocking again in case the child 184 * set some of them to block. Sigh. 185 */ 186 for (i = 0; i < _thread_dtablesize; i++) { 187 /* Check if this file is used: */ 188 if (_thread_fd_table[i] != NULL) { 189 /* 190 * Set the file descriptor to 191 * non-blocking: 192 */ 193 _thread_sys_fcntl(i, F_SETFL, 194 _thread_fd_table[i]->flags | 195 O_NONBLOCK); 196 } 197 } 198 } 199 200 /* 201 * POSIX says that pending SIGCONT signals are 202 * discarded when one of there signals occurs. 203 */ 204 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { 205 /* 206 * Enter a loop to discard pending SIGCONT 207 * signals: 208 */ 209 for (pthread = _thread_link_list; 210 pthread != NULL; 211 pthread = pthread->nxt) 212 sigdelset(&pthread->sigpend,SIGCONT); 213 } 214
| 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 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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 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 */ 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 41/* Static variables: */ 42static int volatile yield_on_unlock_dead = 0; 43static int volatile yield_on_unlock_thread = 0; 44static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER; 45static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER; 46 47/* Lock the thread list: */ 48void 49_lock_thread_list() 50{ 51 /* Lock the thread list: */ 52 _SPINLOCK(&thread_link_list_lock); 53} 54 55/* Lock the dead thread list: */ 56void 57_lock_dead_thread_list() 58{ 59 /* Lock the dead thread list: */ 60 _SPINLOCK(&thread_dead_lock); 61} 62 63/* Lock the thread list: */ 64void 65_unlock_thread_list() 66{ 67 /* Unlock the thread list: */ 68 _SPINUNLOCK(&thread_link_list_lock); 69 70 /* 71 * Check if a scheduler interrupt occurred while the thread 72 * list was locked: 73 */ 74 if (yield_on_unlock_thread) { 75 /* Reset the interrupt flag: */ 76 yield_on_unlock_thread = 0; 77 78 /* This thread has overstayed it's welcome: */ 79 sched_yield(); 80 } 81} 82 83/* Lock the dead thread list: */ 84void 85_unlock_dead_thread_list() 86{ 87 /* Unlock the dead thread list: */ 88 _SPINUNLOCK(&thread_dead_lock); 89 90 /* 91 * Check if a scheduler interrupt occurred while the dead 92 * thread list was locked: 93 */ 94 if (yield_on_unlock_dead) { 95 /* Reset the interrupt flag: */ 96 yield_on_unlock_dead = 0; 97 98 /* This thread has overstayed it's welcome: */ 99 sched_yield(); 100 } 101} 102 103void 104_thread_sig_handler(int sig, int code, struct sigcontext * scp) 105{ 106 char c; 107 int i; 108 int dispatch = 0; 109 pthread_t pthread; 110 111 /* 112 * Check if the pthread kernel has unblocked signals (or is about to) 113 * and was on its way into a _select when the current 114 * signal interrupted it: 115 */ 116 if (_thread_kern_in_select) { 117 /* Cast the signal number to a character variable: */ 118 c = sig; 119 120 /* 121 * Write the signal number to the kernel pipe so that it will 122 * be ready to read when this signal handler returns. This 123 * means that the _select call will complete 124 * immediately. 125 */ 126 _thread_sys_write(_thread_kern_pipe[1], &c, 1); 127 } 128 129 /* Check if the signal requires a dump of thread information: */ 130 if (sig == SIGINFO) 131 /* Dump thread information to file: */ 132 _thread_dump_info(); 133 134 /* Check if an interval timer signal: */ 135 else if (sig == SIGVTALRM) { 136 /* Check if the scheduler interrupt has come at an 137 * unfortunate time which one of the threads is 138 * modifying the thread list: 139 */ 140 if (thread_link_list_lock.access_lock) 141 /* 142 * Set a flag so that the thread that has 143 * the lock yields when it unlocks the 144 * thread list: 145 */ 146 yield_on_unlock_thread = 1; 147 148 /* Check if the scheduler interrupt has come at an 149 * unfortunate time which one of the threads is 150 * modifying the dead thread list: 151 */ 152 if (thread_dead_lock.access_lock) 153 /* 154 * Set a flag so that the thread that has 155 * the lock yields when it unlocks the 156 * dead thread list: 157 */ 158 yield_on_unlock_dead = 1; 159 160 /* 161 * Check if the kernel has not been interrupted while 162 * executing scheduler code: 163 */ 164 else if (!_thread_kern_in_sched) { 165 /* 166 * Schedule the next thread. This function is not 167 * expected to return because it will do a longjmp 168 * instead. 169 */ 170 _thread_kern_sched(scp); 171 172 /* 173 * This point should not be reached, so abort the 174 * process: 175 */ 176 PANIC("Returned to signal function from scheduler"); 177 } 178 } else { 179 /* Check if a child has terminated: */ 180 if (sig == SIGCHLD) { 181 /* 182 * Go through the file list and set all files 183 * to non-blocking again in case the child 184 * set some of them to block. Sigh. 185 */ 186 for (i = 0; i < _thread_dtablesize; i++) { 187 /* Check if this file is used: */ 188 if (_thread_fd_table[i] != NULL) { 189 /* 190 * Set the file descriptor to 191 * non-blocking: 192 */ 193 _thread_sys_fcntl(i, F_SETFL, 194 _thread_fd_table[i]->flags | 195 O_NONBLOCK); 196 } 197 } 198 } 199 200 /* 201 * POSIX says that pending SIGCONT signals are 202 * discarded when one of there signals occurs. 203 */ 204 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { 205 /* 206 * Enter a loop to discard pending SIGCONT 207 * signals: 208 */ 209 for (pthread = _thread_link_list; 210 pthread != NULL; 211 pthread = pthread->nxt) 212 sigdelset(&pthread->sigpend,SIGCONT); 213 } 214
|
215 /* Check if the signal is not being ignored: */ 216 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) 217 /* 218 * Enter a loop to process each thread in the linked 219 * list: 220 */ 221 for (pthread = _thread_link_list; pthread != NULL; 222 pthread = pthread->nxt) 223 _thread_signal(pthread,sig); 224 225 /* Dispatch pending signals to the running thread: */ 226 _dispatch_signals(); 227 } 228 229 /* Returns nothing. */ 230 return; 231} 232 233/* Perform thread specific actions in response to a signal: */ 234void 235_thread_signal(pthread_t pthread, int sig) 236{ 237 pthread_t saved; 238 struct sigaction act; 239 240 /* 241 * Flag the signal as pending. It will be dispatched later. 242 */ 243 sigaddset(&pthread->sigpend,sig); 244 245 /* 246 * Process according to thread state: 247 */ 248 switch (pthread->state) { 249 /* 250 * States which do not change when a signal is trapped: 251 */ 252 case PS_COND_WAIT: 253 case PS_DEAD: 254 case PS_FDLR_WAIT: 255 case PS_FDLW_WAIT: 256 case PS_FILE_WAIT: 257 case PS_JOIN: 258 case PS_MUTEX_WAIT: 259 case PS_RUNNING: 260 case PS_STATE_MAX: 261 case PS_SIGTHREAD:
| 240 /* Check if the signal is not being ignored: */ 241 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) 242 /* 243 * Enter a loop to process each thread in the linked 244 * list: 245 */ 246 for (pthread = _thread_link_list; pthread != NULL; 247 pthread = pthread->nxt) 248 _thread_signal(pthread,sig); 249 250 /* Dispatch pending signals to the running thread: */ 251 _dispatch_signals(); 252 } 253 254 /* Returns nothing. */ 255 return; 256} 257 258/* Perform thread specific actions in response to a signal: */ 259void 260_thread_signal(pthread_t pthread, int sig) 261{ 262 pthread_t saved; 263 struct sigaction act; 264 265 /* 266 * Flag the signal as pending. It will be dispatched later. 267 */ 268 sigaddset(&pthread->sigpend,sig); 269 270 /* 271 * Process according to thread state: 272 */ 273 switch (pthread->state) { 274 /* 275 * States which do not change when a signal is trapped: 276 */ 277 case PS_COND_WAIT: 278 case PS_DEAD: 279 case PS_FDLR_WAIT: 280 case PS_FDLW_WAIT: 281 case PS_FILE_WAIT: 282 case PS_JOIN: 283 case PS_MUTEX_WAIT: 284 case PS_RUNNING: 285 case PS_STATE_MAX: 286 case PS_SIGTHREAD:
|
294 case PS_SELECT_WAIT: 295 if (sig != SIGCHLD || 296 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 297 /* Flag the operation as interrupted: */ 298 pthread->interrupted = 1; 299 300 /* Change the state of the thread to run: */ 301 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 302 303 /* Return the signal number: */ 304 pthread->signo = sig; 305 } 306 break; 307 } 308} 309 310/* Dispatch pending signals to the running thread: */ 311void 312_dispatch_signals() 313{ 314 int i; 315 316 /* 317 * Check if there are pending signals for the running 318 * thread that aren't blocked: 319 */ 320 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0) 321 /* Look for all possible pending signals: */ 322 for (i = 1; i < NSIG; i++) 323 /* 324 * Check that a custom handler is installed 325 * and if the signal is not blocked: 326 */ 327 if (_thread_sigact[i - 1].sa_handler != SIG_DFL && 328 _thread_sigact[i - 1].sa_handler != SIG_IGN && 329 sigismember(&_thread_run->sigpend,i) && 330 !sigismember(&_thread_run->sigmask,i)) { 331 /* Clear the pending signal: */ 332 sigdelset(&_thread_run->sigpend,i); 333 334 /* 335 * Dispatch the signal via the custom signal 336 * handler: 337 */ 338 (*(_thread_sigact[i - 1].sa_handler))(i); 339 } 340} 341#endif
| 319 case PS_SELECT_WAIT: 320 if (sig != SIGCHLD || 321 _thread_sigact[sig - 1].sa_handler != SIG_DFL) { 322 /* Flag the operation as interrupted: */ 323 pthread->interrupted = 1; 324 325 /* Change the state of the thread to run: */ 326 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 327 328 /* Return the signal number: */ 329 pthread->signo = sig; 330 } 331 break; 332 } 333} 334 335/* Dispatch pending signals to the running thread: */ 336void 337_dispatch_signals() 338{ 339 int i; 340 341 /* 342 * Check if there are pending signals for the running 343 * thread that aren't blocked: 344 */ 345 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0) 346 /* Look for all possible pending signals: */ 347 for (i = 1; i < NSIG; i++) 348 /* 349 * Check that a custom handler is installed 350 * and if the signal is not blocked: 351 */ 352 if (_thread_sigact[i - 1].sa_handler != SIG_DFL && 353 _thread_sigact[i - 1].sa_handler != SIG_IGN && 354 sigismember(&_thread_run->sigpend,i) && 355 !sigismember(&_thread_run->sigmask,i)) { 356 /* Clear the pending signal: */ 357 sigdelset(&_thread_run->sigpend,i); 358 359 /* 360 * Dispatch the signal via the custom signal 361 * handler: 362 */ 363 (*(_thread_sigact[i - 1].sa_handler))(i); 364 } 365} 366#endif
|