]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc_r/uthread/uthread_sigwait.c
This commit was generated by cvs2svn to compensate for changes in r130614,
[FreeBSD/FreeBSD.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. 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 AUTHOR 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  * $FreeBSD$
33  */
34 #include <signal.h>
35 #include <sys/param.h>
36 #include <sys/signalvar.h>
37 #include <errno.h>
38 #include <pthread.h>
39 #include "pthread_private.h"
40
41 __weak_reference(_sigwait, sigwait);
42
43 int
44 _sigwait(const sigset_t * __restrict set, int * __restrict sig)
45 {
46         struct pthread  *curthread = _get_curthread();
47         int             ret = 0;
48         int             i;
49         sigset_t        tempset, waitset;
50         struct sigaction act;
51         
52         _thread_enter_cancellation_point();
53         /*
54          * Specify the thread kernel signal handler.
55          */
56         act.sa_handler = (void (*) ()) _thread_sig_handler;
57         act.sa_flags = SA_SIGINFO | SA_RESTART;
58         /* Ensure the signal handler cannot be interrupted by other signals: */
59         sigfillset(&act.sa_mask);
60
61         /*
62          * Initialize the set of signals that will be waited on:
63          */
64         waitset = *set;
65
66         /* These signals can't be waited on. */
67         sigdelset(&waitset, SIGKILL);
68         sigdelset(&waitset, SIGSTOP);
69         sigdelset(&waitset, _SCHED_SIGNAL);
70         sigdelset(&waitset, SIGCHLD);
71         sigdelset(&waitset, SIGINFO);
72
73         /* Check to see if a pending signal is in the wait mask. */
74         tempset = curthread->sigpend;
75         SIGSETOR(tempset, _process_sigpending);
76         SIGSETAND(tempset, waitset);
77         if (SIGNOTEMPTY(tempset)) {
78                 /* Enter a loop to find a pending signal: */
79                 for (i = 1; i < NSIG; i++) {
80                         if (sigismember (&tempset, i))
81                                 break;
82                 }
83
84                 /* Clear the pending signal: */
85                 if (sigismember(&curthread->sigpend,i))
86                         sigdelset(&curthread->sigpend,i);
87                 else
88                         sigdelset(&_process_sigpending,i);
89
90                 /* Return the signal number to the caller: */
91                 *sig = i;
92
93                 _thread_leave_cancellation_point();
94                 return (0);
95         }
96
97         /*
98          * Access the _thread_dfl_count array under the protection of signal
99          * deferral.
100          */
101         _thread_kern_sig_defer();
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         _thread_kern_sig_undefer();
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                 _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
138
139                 /* Return the signal number to the caller: */
140                 *sig = curthread->signo;
141
142                 /*
143                  * Probably unnecessary, but since it's in a union struct
144                  * we don't know how it could be used in the future.
145                  */
146                 curthread->data.sigwait = NULL;
147         }
148
149         /*
150          * Access the _thread_dfl_count array under the protection of signal
151          * deferral.
152          */
153         _thread_kern_sig_defer();
154
155         /* Restore the sigactions: */
156         act.sa_handler = SIG_DFL;
157         for (i = 1; i < NSIG; i++) {
158                 if (sigismember(&tempset, i)) {
159                         _thread_dfl_count[i]--;
160                         if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
161                             (_thread_dfl_count[i] == 0)) {
162                                 if (__sys_sigaction(i,&act,NULL) != 0)
163                                         ret = -1;
164                         }
165                 }
166         }
167         /* Done accessing _thread_dfl_count. */
168         _thread_kern_sig_undefer();
169
170         _thread_leave_cancellation_point();
171         
172         /* Return the completion status: */
173         return (ret);
174 }