thr_sigwait.c revision 116977
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 116977 2003-06-28 09:55:02Z davidxu $ 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__weak_reference(__sigtimedwait, sigtimedwait); 44__weak_reference(__sigwaitinfo, sigwaitinfo); 45 46static int 47lib_sigtimedwait(const sigset_t *set, siginfo_t *info, 48 const struct timespec * timeout) 49{ 50 struct pthread *curthread = _get_curthread(); 51 int ret = 0; 52 int i; 53 sigset_t tempset, waitset; 54 struct sigaction act; 55 kse_critical_t crit; 56 siginfo_t siginfo; 57 58 if (!_kse_isthreaded()) { 59 if (info == NULL) 60 info = &siginfo; 61 return __sys_sigtimedwait((sigset_t *)set, info, 62 (struct timespec *)timeout); 63 } 64 65 /* 66 * Specify the thread kernel signal handler. 67 */ 68 act.sa_handler = (void (*) ()) _thr_sig_handler; 69 act.sa_flags = SA_RESTART | SA_SIGINFO; 70 /* Ensure the signal handler cannot be interrupted by other signals: */ 71 SIGFILLSET(act.sa_mask); 72 73 /* 74 * Initialize the set of signals that will be waited on: 75 */ 76 waitset = *set; 77 78 /* These signals can't be waited on. */ 79 SIGDELSET(waitset, SIGKILL); 80 SIGDELSET(waitset, SIGSTOP); 81 82 crit = _kse_critical_enter(); 83 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); 84 85 /* 86 * Enter a loop to find the signals that are SIG_DFL. For 87 * these signals we must install a dummy signal handler in 88 * order for the kernel to pass them in to us. POSIX says 89 * that the _application_ must explicitly install a dummy 90 * handler for signals that are SIG_IGN in order to sigwait 91 * on them. Note that SIG_IGN signals are left in the 92 * mask because a subsequent sigaction could enable an 93 * ignored signal. 94 */ 95 SIGEMPTYSET(tempset); 96 for (i = 1; i <= _SIG_MAXSIG; i++) { 97 if (SIGISMEMBER(waitset, i) && 98 (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { 99 _thread_dfl_count[i - 1]++; 100 SIGADDSET(tempset, i); 101 if (_thread_dfl_count[i - 1] == 1) { 102 if (__sys_sigaction(i, &act, NULL) != 0) 103 /* ret = -1 */; 104 } 105 } 106 } 107 108 if (ret == 0) { 109 /* Done accessing _thread_dfl_count for now. */ 110 KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); 111 KSE_SCHED_LOCK(curthread->kse, curthread->kseg); 112 for (i = 1; i <= _SIG_MAXSIG; ++i) { 113 if (SIGISMEMBER(waitset, i) && 114 SIGISMEMBER(curthread->sigpend, i)) { 115 SIGDELSET(curthread->sigpend, i); 116 *info = curthread->siginfo[i]; 117 KSE_SCHED_UNLOCK(curthread->kse, 118 curthread->kseg); 119 _kse_critical_leave(crit); 120 return (i); 121 } 122 } 123 curthread->timeout = 0; 124 _thr_set_timeout(timeout); 125 /* Wait for a signal: */ 126 curthread->oldsigmask = curthread->sigmask; 127 siginfo.si_signo = 0; 128 curthread->data.sigwaitinfo = &siginfo; 129 SIGFILLSET(curthread->sigmask); 130 SIGSETNAND(curthread->sigmask, waitset); 131 THR_SET_STATE(curthread, PS_SIGWAIT); 132 _thr_sched_switch_unlocked(curthread); 133 /* 134 * Return the signal number to the caller: 135 * XXX Here is race, how about a signal come in before 136 * we reach here? so we might got an incorrect timeout 137 * status. 138 */ 139 if (siginfo.si_signo > 0) { 140 if (info) 141 *info = siginfo; 142 ret = siginfo.si_signo; 143 } else { 144 if (curthread->timeout) 145 errno = EAGAIN; 146 ret = -1; 147 } 148 149 /* 150 * Probably unnecessary, but since it's in a union struct 151 * we don't know how it could be used in the future. 152 */ 153 crit = _kse_critical_enter(); 154 curthread->data.sigwaitinfo = NULL; 155 /* 156 * Relock the array of SIG_DFL wait counts. 157 */ 158 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); 159 } 160 161 /* Restore the sigactions: */ 162 act.sa_handler = SIG_DFL; 163 for (i = 1; i <= _SIG_MAXSIG; i++) { 164 if (SIGISMEMBER(tempset, i)) { 165 _thread_dfl_count[i - 1]--; 166 if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && 167 (_thread_dfl_count[i - 1] == 0)) { 168 if (__sys_sigaction(i, &act, NULL) != 0) 169 /* ret = -1 */ ; 170 } 171 } 172 } 173 /* Done accessing _thread_dfl_count. */ 174 KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); 175 _kse_critical_leave(crit); 176 177 return (ret); 178} 179 180int 181__sigtimedwait(const sigset_t *set, siginfo_t *info, 182 const struct timespec * timeout) 183{ 184 struct pthread *curthread = _get_curthread(); 185 int ret; 186 187 _thr_enter_cancellation_point(curthread); 188 ret = lib_sigtimedwait(set, info, timeout); 189 _thr_leave_cancellation_point(curthread); 190 return (ret); 191} 192 193int _sigtimedwait(const sigset_t *set, siginfo_t *info, 194 const struct timespec * timeout) 195{ 196 return lib_sigtimedwait(set, info, timeout); 197} 198 199int 200__sigwaitinfo(const sigset_t *set, siginfo_t *info) 201{ 202 struct pthread *curthread = _get_curthread(); 203 int ret; 204 205 _thr_enter_cancellation_point(curthread); 206 ret = lib_sigtimedwait(set, info, NULL); 207 _thr_leave_cancellation_point(curthread); 208 return (ret); 209} 210 211int 212_sigwaitinfo(const sigset_t *set, siginfo_t *info) 213{ 214 return lib_sigtimedwait(set, info, NULL); 215} 216 217int 218__sigwait(const sigset_t *set, int *sig) 219{ 220 struct pthread *curthread = _get_curthread(); 221 int ret; 222 223 _thr_enter_cancellation_point(curthread); 224 ret = lib_sigtimedwait(set, NULL, NULL); 225 if (ret > 0) { 226 *sig = ret; 227 ret = 0; 228 } 229 else 230 ret = -1; 231 _thr_leave_cancellation_point(curthread); 232 return (ret); 233} 234 235int 236_sigwait(const sigset_t *set, int *sig) 237{ 238 int ret; 239 240 ret = lib_sigtimedwait(set, NULL, NULL); 241 if (ret > 0) { 242 *sig = ret; 243 ret = 0; 244 } else { 245 ret = -1; 246 } 247 return (ret); 248} 249 250