Deleted Added
sdiff udiff text old ( 211737 ) new ( 212076 )
full compact
1/*
2 * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
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 unchanged lines hidden (view full) ---

18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD: head/lib/libthr/thread/thr_sig.c 211737 2010-08-24 09:57:06Z davidxu $
27 */
28
29#include "namespace.h"
30#include <sys/param.h>
31#include <sys/types.h>
32#include <sys/signalvar.h>
33#include <signal.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <string.h>
38#include <pthread.h>
39#include "un-namespace.h"
40
41#include "thr_private.h"
42
43/* #define DEBUG_SIGNAL */
44#ifdef DEBUG_SIGNAL
45#define DBG_MSG stdout_debug
46#else
47#define DBG_MSG(x...)
48#endif
49
50extern int __pause(void);
51int ___pause(void);
52int _raise(int);
53int __sigtimedwait(const sigset_t *set, siginfo_t *info,
54 const struct timespec * timeout);
55int _sigtimedwait(const sigset_t *set, siginfo_t *info,
56 const struct timespec * timeout);
57int __sigwaitinfo(const sigset_t *set, siginfo_t *info);
58int _sigwaitinfo(const sigset_t *set, siginfo_t *info);
59int __sigwait(const sigset_t *set, int *sig);
60int _sigwait(const sigset_t *set, int *sig);
61int __sigsuspend(const sigset_t *sigmask);
62int _setcontext(const ucontext_t *);
63int _swapcontext(ucontext_t *, const ucontext_t *);
64
65static void
66remove_thr_signals(sigset_t *set)
67{
68 if (SIGISMEMBER(*set, SIGCANCEL))
69 SIGDELSET(*set, SIGCANCEL);
70}
71
72static const sigset_t *
73thr_remove_thr_signals(const sigset_t *set, sigset_t *newset)
74{
75 const sigset_t *pset;
76
77 if (SIGISMEMBER(*set, SIGCANCEL)) {
78 *newset = *set;
79 SIGDELSET(*newset, SIGCANCEL);
80 pset = newset;
81 } else
82 pset = set;
83 return (pset);
84}
85
86static void
87sigcancel_handler(int sig __unused,
88 siginfo_t *info __unused, ucontext_t *ucp __unused)
89{
90 struct pthread *curthread = _get_curthread();
91
92 curthread->in_sigcancel_handler++;
93 _thr_ast(curthread);
94 curthread->in_sigcancel_handler--;
95}
96
97void
98_thr_ast(struct pthread *curthread)
99{
100
101 if (THR_IN_CRITICAL(curthread))
102 return;
103
104 if (curthread->cancel_pending && curthread->cancel_enable
105 && !curthread->cancelling) {
106 if (curthread->cancel_async) {
107 /*
108 * asynchronous cancellation mode, act upon
109 * immediately.
110 */
111 _pthread_exit(PTHREAD_CANCELED);
112 } else {
113 /*
114 * Otherwise, we are in defer mode, and we are at
115 * cancel point, tell kernel to not block the current
116 * thread on next cancelable system call.
117 *
118 * There are two cases we should call thr_wake() to
119 * turn on TDP_WAKEUP in kernel:
120 * 1) we are going to call a cancelable system call,
121 * non-zero cancel_point means we are already in
122 * cancelable state, next system call is cancelable.
123 * 2) because _thr_ast() may be called by
124 * THR_CRITICAL_LEAVE() which is used by rtld rwlock
125 * and any libthr internal locks, when rtld rwlock
126 * is used, it is mostly caused my an unresolved PLT.
127 * those routines may clear the TDP_WAKEUP flag by
128 * invoking some system calls, in those cases, we
129 * also should reenable the flag.
130 */
131 if (curthread->cancel_point) {
132 if (curthread->cancel_defer)
133 thr_wake(curthread->tid);
134 else
135 _pthread_exit(PTHREAD_CANCELED);
136 }
137 }
138 }
139
140 if (__predict_false((curthread->flags &
141 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
142 == THR_FLAGS_NEED_SUSPEND))
143 _thr_suspend_check(curthread);
144}
145
146void
147_thr_suspend_check(struct pthread *curthread)
148{
149 uint32_t cycle;
150 int err;
151
152 if (curthread->force_exit)
153 return;
154
155 err = errno;
156 /*
157 * Blocks SIGCANCEL which other threads must send.
158 */
159 _thr_signal_block(curthread);
160
161 /*
162 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
163 * because we are leaf code, we don't want to recursively call

--- 19 unchanged lines hidden (view full) ---

183 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
184 _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0);
185 THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
186 curthread->flags &= ~THR_FLAGS_SUSPENDED;
187 }
188 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
189 curthread->critical_count--;
190
191 /*
192 * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
193 * a new signal frame will nest us, this seems a problem because
194 * stack will grow and overflow, but because kernel will automatically
195 * mask the SIGCANCEL when delivering the signal, so we at most only
196 * have one nesting signal frame, this should be fine.
197 */
198 _thr_signal_unblock(curthread);
199 errno = err;
200}
201
202void
203_thr_signal_init(void)
204{
205 struct sigaction act;
206
207 /* Install cancel handler. */
208 SIGEMPTYSET(act.sa_mask);
209 act.sa_flags = SA_SIGINFO | SA_RESTART;
210 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
211 __sys_sigaction(SIGCANCEL, &act, NULL);
212}
213
214void
215_thr_signal_deinit(void)
216{
217}
218
219__weak_reference(___pause, pause);
220
221int
222___pause(void)
223{
224 struct pthread *curthread = _get_curthread();
225 int ret;
226
227 _thr_cancel_enter(curthread);
228 ret = __pause();
229 _thr_cancel_leave(curthread);
230
231 return ret;
232}
233
234__weak_reference(_raise, raise);
235
236int
237_raise(int sig)
238{
239 int ret;
240
241 if (!_thr_isthreaded())
242 ret = kill(getpid(), sig);
243 else
244 ret = _thr_send_sig(_get_curthread(), sig);
245 return (ret);
246}
247
248__weak_reference(_sigaction, sigaction);
249
250int
251_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
252{
253 /* Check if the signal number is out of range: */
254 if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
255 /* Return an invalid argument: */
256 errno = EINVAL;
257 return (-1);
258 }
259
260 return __sys_sigaction(sig, act, oact);
261}
262
263__weak_reference(_sigprocmask, sigprocmask);
264
265int
266_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
267{
268 const sigset_t *p = set;

--- 27 unchanged lines hidden (view full) ---

296 sigset_t newset;
297
298 return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset)));
299}
300
301int
302__sigsuspend(const sigset_t * set)
303{
304 struct pthread *curthread = _get_curthread();
305 sigset_t newset;
306 int ret;
307
308 _thr_cancel_enter(curthread);
309 ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset));
310 _thr_cancel_leave(curthread);
311
312 return (ret);
313}
314
315__weak_reference(__sigwait, sigwait);
316__weak_reference(__sigtimedwait, sigtimedwait);
317__weak_reference(__sigwaitinfo, sigwaitinfo);
318

--- 15 unchanged lines hidden (view full) ---

334int
335__sigtimedwait(const sigset_t *set, siginfo_t *info,
336 const struct timespec * timeout)
337{
338 struct pthread *curthread = _get_curthread();
339 sigset_t newset;
340 int ret;
341
342 _thr_cancel_enter_defer(curthread, 1);
343 ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
344 timeout);
345 _thr_cancel_leave_defer(curthread, (ret == -1));
346 return (ret);
347}
348
349int
350_sigwaitinfo(const sigset_t *set, siginfo_t *info)
351{
352 sigset_t newset;
353

--- 7 unchanged lines hidden (view full) ---

361 */
362int
363__sigwaitinfo(const sigset_t *set, siginfo_t *info)
364{
365 struct pthread *curthread = _get_curthread();
366 sigset_t newset;
367 int ret;
368
369 _thr_cancel_enter_defer(curthread, 1);
370 ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info);
371 _thr_cancel_leave_defer(curthread, ret == -1);
372 return (ret);
373}
374
375int
376_sigwait(const sigset_t *set, int *sig)
377{
378 sigset_t newset;
379

--- 7 unchanged lines hidden (view full) ---

387 */
388int
389__sigwait(const sigset_t *set, int *sig)
390{
391 struct pthread *curthread = _get_curthread();
392 sigset_t newset;
393 int ret;
394
395 _thr_cancel_enter_defer(curthread, 1);
396 ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig);
397 _thr_cancel_leave_defer(curthread, (ret != 0));
398 return (ret);
399}
400
401__weak_reference(_setcontext, setcontext);
402int
403_setcontext(const ucontext_t *ucp)
404{
405 ucontext_t uc;
406
407 (void) memcpy(&uc, ucp, sizeof (uc));
408 remove_thr_signals(&uc.uc_sigmask);
409
410 return __sys_setcontext(&uc);
411}
412
413__weak_reference(_swapcontext, swapcontext);
414int
415_swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
416{
417 ucontext_t uc;
418
419 (void) memcpy(&uc, ucp, sizeof (uc));
420 remove_thr_signals(&uc.uc_sigmask);
421 return __sys_swapcontext(oucp, &uc);
422}