1 /* vi: set sw=4 ts=4: */
2 /*
3  * __rt_sigtimedwait() for uClibc
4  *
5  * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com>
6  * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
7  *
8  * GNU Library General Public License (LGPL) version 2 or later.
9  */
10 
11 #include <sys/syscall.h>
12 
13 #ifdef __NR_rt_sigtimedwait
14 # include <signal.h>
15 # include <cancel.h>
16 # ifdef __UCLIBC_HAS_THREADS_NATIVE__
17 #  include <pthreadP.h>	/* SIGCANCEL */
18 # endif
19 # ifdef SIGCANCEL
20 #  define __need_NULL
21 #  include <stddef.h>
22 #  include <string.h>
23 # endif
24 
__NC(sigtimedwait)25 int __NC(sigtimedwait)(const sigset_t *set, siginfo_t *info,
26 		       const struct timespec *timeout)
27 {
28 # ifdef SIGCANCEL
29 	sigset_t tmpset;
30 
31 	if (set != NULL && (unlikely (__sigismember (set, SIGCANCEL))
32 #  ifdef SIGSETXID
33 		|| unlikely (__sigismember (set, SIGSETXID))
34 #  endif
35 		))
36 	{
37 		/* Create a temporary mask without the bit for SIGCANCEL set.  */
38 		// We are not copying more than we have to.
39 		memcpy (&tmpset, set, _NSIG / 8);
40 		__sigdelset (&tmpset, SIGCANCEL);
41 #  ifdef SIGSETXID
42 		__sigdelset (&tmpset, SIGSETXID);
43 #  endif
44 		set = &tmpset;
45 	}
46 # endif
47 
48 /* if this is enabled, enable the disabled section in sigwait.c */
49 # if defined SI_TKILL && defined SI_USER
50 	/* XXX The size argument hopefully will have to be changed to the
51 	   real size of the user-level sigset_t.  */
52 	/* on uClibc we use the kernel sigset_t size */
53 	int result = INLINE_SYSCALL(rt_sigtimedwait, 4, set, info,
54 				    timeout, __SYSCALL_SIGSET_T_SIZE);
55 
56 	/* The kernel generates a SI_TKILL code in si_code in case tkill is
57 	   used.  tkill is transparently used in raise().  Since having
58 	   SI_TKILL as a code is useful in general we fold the results
59 	   here.  */
60 	if (result != -1 && info != NULL && info->si_code == SI_TKILL)
61 		info->si_code = SI_USER;
62 
63 	return result;
64 # else
65 	/* on uClibc we use the kernel sigset_t size */
66 	return INLINE_SYSCALL(rt_sigtimedwait, 4, set, info,
67 			      timeout, __SYSCALL_SIGSET_T_SIZE);
68 # endif
69 }
70 CANCELLABLE_SYSCALL(int, sigtimedwait,
71 		    (const sigset_t *set, siginfo_t *info, const struct timespec *timeout),
72 		    (set, info, timeout))
73 lt_libc_hidden(sigtimedwait)
74 #endif
75