1 | /* Implementation of sigtimedwait function from POSIX.1b. |
2 | Copyright (C) 1996-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <hurd.h> |
21 | #include <hurd/signal.h> |
22 | #include <hurd/msg.h> |
23 | #include <hurd/sigpreempt.h> |
24 | #include <assert.h> |
25 | #include <sysdep-cancel.h> |
26 | |
27 | int |
28 | __sigtimedwait (const sigset_t *set, siginfo_t *info, |
29 | const struct timespec *timeout) |
30 | { |
31 | struct hurd_sigstate *ss; |
32 | sigset_t mask, ready, blocked; |
33 | int signo = 0; |
34 | struct hurd_signal_preemptor preemptor; |
35 | jmp_buf buf; |
36 | mach_port_t wait; |
37 | mach_msg_header_t msg; |
38 | int cancel_oldtype; |
39 | mach_msg_option_t option = 0; |
40 | mach_msg_timeout_t ms = MACH_MSG_TIMEOUT_NONE; |
41 | |
42 | sighandler_t |
43 | preempt_fun (struct hurd_signal_preemptor *pe, |
44 | struct hurd_sigstate *ss, |
45 | int *sigp, |
46 | struct hurd_signal_detail *detail) |
47 | { |
48 | if (signo) |
49 | /* We've already been run; don't interfere. */ |
50 | return SIG_ERR; |
51 | |
52 | signo = *sigp; |
53 | |
54 | if (info) |
55 | { |
56 | info->si_signo = signo; |
57 | info->si_errno = detail->error; |
58 | info->si_code = detail->code; |
59 | |
60 | /* XXX */ |
61 | info->si_pid = -1; |
62 | info->si_uid = -1; |
63 | info->si_addr = (void *) NULL; |
64 | info->si_status = 0; |
65 | info->si_band = 0; |
66 | info->si_value.sival_int = 0; |
67 | } |
68 | |
69 | /* Make sure this is all kosher */ |
70 | assert (__sigismember (&mask, signo)); |
71 | |
72 | /* Restore the blocking mask. */ |
73 | ss->blocked = blocked; |
74 | |
75 | return pe->handler; |
76 | } |
77 | |
78 | void |
79 | handler (int sig) |
80 | { |
81 | assert (sig == signo); |
82 | longjmp (buf, 1); |
83 | } |
84 | |
85 | wait = __mach_reply_port (); |
86 | |
87 | if (set != NULL) |
88 | /* Crash before locking */ |
89 | mask = *set; |
90 | else |
91 | __sigemptyset (set: &mask); |
92 | |
93 | ss = _hurd_self_sigstate (); |
94 | cancel_oldtype = LIBC_CANCEL_ASYNC(); |
95 | _hurd_sigstate_lock (ss); |
96 | |
97 | /* See if one of these signals is currently pending. */ |
98 | sigset_t pending = _hurd_sigstate_pending (ss); |
99 | __sigandset (dest: &ready, left: &pending, right: &mask); |
100 | if (! __sigisemptyset (set: &ready)) |
101 | { |
102 | for (signo = 1; signo < NSIG; signo++) |
103 | if (__sigismember (set: &ready, sig: signo)) |
104 | { |
105 | __sigdelset (set: &ready, sig: signo); |
106 | goto all_done; |
107 | } |
108 | /* Huh? Where'd it go? */ |
109 | abort (); |
110 | } |
111 | |
112 | /* Wait for one of them to show up. */ |
113 | |
114 | if (!setjmp (buf)) |
115 | { |
116 | /* Make the preemptor */ |
117 | preemptor.signals = mask; |
118 | preemptor.first = 0; |
119 | preemptor.last = -1; |
120 | preemptor.preemptor = preempt_fun; |
121 | preemptor.handler = handler; |
122 | |
123 | /* Install this preemptor */ |
124 | preemptor.next = ss->preemptors; |
125 | ss->preemptors = &preemptor; |
126 | |
127 | /* Unblock the expected signals */ |
128 | blocked = ss->blocked; |
129 | ss->blocked &= ~mask; |
130 | |
131 | _hurd_sigstate_unlock (ss); |
132 | |
133 | if (timeout) |
134 | { |
135 | option |= MACH_RCV_TIMEOUT, |
136 | ms = timeout->tv_sec * 1000 |
137 | + (timeout->tv_nsec + 999999) / 1000000; |
138 | } |
139 | |
140 | /* Wait. */ |
141 | __mach_msg (&msg, MACH_RCV_MSG | option, 0, sizeof (msg), wait, |
142 | ms, MACH_PORT_NULL); |
143 | |
144 | if (!(option & MACH_RCV_TIMEOUT)) |
145 | abort (); |
146 | |
147 | /* Timed out. */ |
148 | signo = __hurd_fail (EAGAIN); |
149 | } |
150 | else |
151 | { |
152 | assert (signo); |
153 | |
154 | _hurd_sigstate_lock (ss); |
155 | |
156 | /* Delete our preemptor. */ |
157 | assert (ss->preemptors == &preemptor); |
158 | ss->preemptors = preemptor.next; |
159 | } |
160 | |
161 | |
162 | all_done: |
163 | _hurd_sigstate_unlock (ss); |
164 | LIBC_CANCEL_RESET (cancel_oldtype); |
165 | |
166 | __mach_port_destroy (__mach_task_self (), wait); |
167 | return signo; |
168 | } |
169 | libc_hidden_def (__sigtimedwait) |
170 | weak_alias (__sigtimedwait, sigtimedwait) |
171 | |