]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_sigwait.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc_r / uthread / uthread_sigwait.c
1 /*
2  * Copyright (c) 1997 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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #include <signal.h>
32 #include <sys/param.h>
33 #include <sys/signalvar.h>
34 #include <errno.h>
35 #include <pthread.h>
36 #include "pthread_private.h"
37
38 __weak_reference(_sigwait, sigwait);
39
40 int
41 _sigwait(const sigset_t * __restrict set, int * __restrict sig)
42 {
43         struct pthread  *curthread = _get_curthread();
44         int             ret = 0;
45         int             i;
46         sigset_t        tempset, waitset;
47         struct sigaction act;
48         
49         _thread_enter_cancellation_point();
50         /*
51          * Specify the thread kernel signal handler.
52          */
53         act.sa_handler = (void (*) ()) _thread_sig_handler;
54         act.sa_flags = SA_SIGINFO | SA_RESTART;
55         /* Ensure the signal handler cannot be interrupted by other signals: */
56         sigfillset(&act.sa_mask);
57
58         /*
59          * Initialize the set of signals that will be waited on:
60          */
61         waitset = *set;
62
63         /* These signals can't be waited on. */
64         sigdelset(&waitset, SIGKILL);
65         sigdelset(&waitset, SIGSTOP);
66         sigdelset(&waitset, _SCHED_SIGNAL);
67         sigdelset(&waitset, SIGCHLD);
68         sigdelset(&waitset, SIGINFO);
69
70         /* Check to see if a pending signal is in the wait mask. */
71         tempset = curthread->sigpend;
72         SIGSETOR(tempset, _process_sigpending);
73         SIGSETAND(tempset, waitset);
74         if (SIGNOTEMPTY(tempset)) {
75                 /* Enter a loop to find a pending signal: */
76                 for (i = 1; i < NSIG; i++) {
77                         if (sigismember (&tempset, i))
78                                 break;
79                 }
80
81                 /* Clear the pending signal: */
82                 if (sigismember(&curthread->sigpend,i))
83                         sigdelset(&curthread->sigpend,i);
84                 else
85                         sigdelset(&_process_sigpending,i);
86
87                 /* Return the signal number to the caller: */
88                 *sig = i;
89
90                 _thread_leave_cancellation_point();
91                 return (0);
92         }
93
94         /*
95          * Access the _thread_dfl_count array under the protection of signal
96          * deferral.
97          */
98         _thread_kern_sig_defer();
99
100         /*
101          * Enter a loop to find the signals that are SIG_DFL.  For
102          * these signals we must install a dummy signal handler in
103          * order for the kernel to pass them in to us.  POSIX says
104          * that the _application_ must explicitly install a dummy
105          * handler for signals that are SIG_IGN in order to sigwait
106          * on them.  Note that SIG_IGN signals are left in the
107          * mask because a subsequent sigaction could enable an
108          * ignored signal.
109          */
110         sigemptyset(&tempset);
111         for (i = 1; i < NSIG; i++) {
112                 if (sigismember(&waitset, i) &&
113                     (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
114                         _thread_dfl_count[i]++;
115                         sigaddset(&tempset, i);
116                         if (_thread_dfl_count[i] == 1) {
117                                 if (__sys_sigaction(i,&act,NULL) != 0)
118                                         ret = -1;
119                         }
120                 }
121         }
122         /* Done accessing _thread_dfl_count for now. */
123         _thread_kern_sig_undefer();
124
125         if (ret == 0) {
126                 /*
127                  * Save the wait signal mask.  The wait signal
128                  * mask is independent of the threads signal mask
129                  * and requires separate storage.
130                  */
131                 curthread->data.sigwait = &waitset;
132
133                 /* Wait for a signal: */
134                 _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
135
136                 /* Return the signal number to the caller: */
137                 *sig = curthread->signo;
138
139                 /*
140                  * Probably unnecessary, but since it's in a union struct
141                  * we don't know how it could be used in the future.
142                  */
143                 curthread->data.sigwait = NULL;
144         }
145
146         /*
147          * Access the _thread_dfl_count array under the protection of signal
148          * deferral.
149          */
150         _thread_kern_sig_defer();
151
152         /* Restore the sigactions: */
153         act.sa_handler = SIG_DFL;
154         for (i = 1; i < NSIG; i++) {
155                 if (sigismember(&tempset, i)) {
156                         _thread_dfl_count[i]--;
157                         if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
158                             (_thread_dfl_count[i] == 0)) {
159                                 if (__sys_sigaction(i,&act,NULL) != 0)
160                                         ret = -1;
161                         }
162                 }
163         }
164         /* Done accessing _thread_dfl_count. */
165         _thread_kern_sig_undefer();
166
167         _thread_leave_cancellation_point();
168         
169         /* Return the completion status: */
170         return (ret);
171 }