thr_sigwait.c revision 113658
1//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko) 2/* 3 * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. 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, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by John Birrell. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: head/lib/libkse/thread/thr_sigwait.c 113658 2003-04-18 05:04:16Z deischen $ 34 */ 35#include <signal.h> 36#include <sys/param.h> 37#include <sys/signalvar.h> 38#include <errno.h> 39#include <pthread.h> 40#include "thr_private.h" 41 42__weak_reference(_sigwait, sigwait); 43 44int 45_sigwait(const sigset_t *set, int *sig) 46{ 47 struct pthread *curthread = _get_curthread(); 48 int ret = 0; 49 int i; 50 sigset_t tempset, waitset; 51 struct sigaction act; 52 53 _thr_enter_cancellation_point(curthread); 54 55 /* 56 * Specify the thread kernel signal handler. 57 */ 58 act.sa_handler = (void (*) ()) _thr_sig_handler; 59 act.sa_flags = SA_RESTART | SA_SIGINFO; 60 /* Ensure the signal handler cannot be interrupted by other signals: */ 61 sigfillset(&act.sa_mask); 62 63 /* 64 * Initialize the set of signals that will be waited on: 65 */ 66 waitset = *set; 67 68 /* These signals can't be waited on. */ 69 sigdelset(&waitset, SIGKILL); 70 sigdelset(&waitset, SIGSTOP); 71 72 /* 73 * Check to see if a pending signal is in the wait mask. 74 * This has to be atomic. */ 75 tempset = curthread->sigpend; 76 SIGSETOR(tempset, _thr_proc_sigpending); 77 SIGSETAND(tempset, waitset); 78 if (SIGNOTEMPTY(tempset)) { 79 /* Enter a loop to find a pending signal: */ 80 for (i = 1; i < NSIG; i++) { 81 if (sigismember (&tempset, i)) 82 break; 83 } 84 85 /* Clear the pending signal: */ 86 if (sigismember(&curthread->sigpend,i)) 87 sigdelset(&curthread->sigpend,i); 88 else 89 sigdelset(&_thr_proc_sigpending,i); 90 91 /* Return the signal number to the caller: */ 92 *sig = i; 93 94 _thr_leave_cancellation_point(curthread); 95 return (0); 96 } 97 98 /* 99 * Lock the array of SIG_DFL wait counts. 100 */ 101 THR_LOCK_ACQUIRE(curthread, &_thread_signal_lock); 102 103 /* 104 * Enter a loop to find the signals that are SIG_DFL. For 105 * these signals we must install a dummy signal handler in 106 * order for the kernel to pass them in to us. POSIX says 107 * that the _application_ must explicitly install a dummy 108 * handler for signals that are SIG_IGN in order to sigwait 109 * on them. Note that SIG_IGN signals are left in the 110 * mask because a subsequent sigaction could enable an 111 * ignored signal. 112 */ 113 sigemptyset(&tempset); 114 for (i = 1; i < NSIG; i++) { 115 if (sigismember(&waitset, i) && 116 (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { 117 _thread_dfl_count[i]++; 118 sigaddset(&tempset, i); 119 if (_thread_dfl_count[i] == 1) { 120 if (__sys_sigaction(i, &act, NULL) != 0) 121 ret = -1; 122 } 123 } 124 } 125 /* Done accessing _thread_dfl_count for now. */ 126 THR_LOCK_RELEASE(curthread, &_thread_signal_lock); 127 128 if (ret == 0) { 129 /* 130 * Save the wait signal mask. The wait signal 131 * mask is independent of the threads signal mask 132 * and requires separate storage. 133 */ 134 curthread->data.sigwait = &waitset; 135 136 /* Wait for a signal: */ 137 THR_SCHED_LOCK(curthread, curthread); 138 THR_SET_STATE(curthread, PS_SIGWAIT); 139 THR_SCHED_UNLOCK(curthread, curthread); 140 _thr_sched_switch(curthread); 141 142 /* Return the signal number to the caller: */ 143 *sig = curthread->signo; 144 145 /* 146 * Probably unnecessary, but since it's in a union struct 147 * we don't know how it could be used in the future. 148 */ 149 curthread->data.sigwait = NULL; 150 } 151 152 /* 153 * Relock the array of SIG_DFL wait counts. 154 */ 155 THR_LOCK_ACQUIRE(curthread, &_thread_signal_lock); 156 157 /* Restore the sigactions: */ 158 act.sa_handler = SIG_DFL; 159 for (i = 1; i < NSIG; i++) { 160 if (sigismember(&tempset, i)) { 161 _thread_dfl_count[i]--; 162 if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && 163 (_thread_dfl_count[i] == 0)) { 164 if (__sys_sigaction(i, &act, NULL) != 0) 165 ret = -1; 166 } 167 } 168 } 169 /* Done accessing _thread_dfl_count. */ 170 THR_LOCK_RELEASE(curthread, &_thread_signal_lock); 171 172 _thr_leave_cancellation_point(curthread); 173 174 /* Return the completion status: */ 175 return (ret); 176} 177