diff options
author | Peter S. Mazinger <ps.m@gmx.net> | 2011-04-22 00:33:48 +0200 |
---|---|---|
committer | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2012-06-15 14:00:41 +0200 |
commit | b72b0b14d0da0b506fbddf755cc8c7d0cd813287 (patch) | |
tree | 844a9b81562265974b81f3a21af413c07cd7f349 | |
parent | 24edbbd53a382f35a4365ae065f61d56579f52f1 (diff) |
rework cancellation for sigwait, sigtimedwait and sigwaitinfo
sigtimedwait:
- provide __sigtimedwait_nocancel
- use __SYSCALL_SIGSET_T_SIZE instead of _NSIG / 8
- do not provide __sigtimedwait
- guard a section to avoid failure on archs if SI_TKILL/SI_USER are not defined
sigwaitinfo:
- simply use sigtimedwait since that handles cancellation already
sigwait:
- use non-cancellable functions (sigtimedwait, sigsuspend)
- get rid of code already done in __sigtimedwait_nocancel
Signed-off-by: Peter S. Mazinger <ps.m@gmx.net>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
-rw-r--r-- | include/signal.h | 3 | ||||
-rw-r--r-- | libc/signal/sigwait.c | 91 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/__rt_sigtimedwait.c | 75 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/__rt_sigwaitinfo.c | 78 |
4 files changed, 56 insertions, 191 deletions
diff --git a/include/signal.h b/include/signal.h index 09f06f95b..052467758 100644 --- a/include/signal.h +++ b/include/signal.h @@ -372,7 +372,8 @@ extern int sigtimedwait (__const sigset_t *__restrict __set, __const struct timespec *__restrict __timeout) __nonnull ((1)); #ifdef _LIBC -extern __typeof(sigtimedwait) __sigtimedwait attribute_hidden; +extern __typeof(sigtimedwait) __sigtimedwait_nocancel attribute_hidden; +libc_hidden_proto(sigtimedwait) #endif /* Send signal SIG to the process PID. Associate data in VAL with the diff --git a/libc/signal/sigwait.c b/libc/signal/sigwait.c index 5e9c4275f..7d47f99de 100644 --- a/libc/signal/sigwait.c +++ b/libc/signal/sigwait.c @@ -21,92 +21,36 @@ #define __need_NULL #include <stddef.h> +#include <sys/syscall.h> #include <signal.h> +#include <cancel.h> -#ifdef __UCLIBC_HAS_THREADS_NATIVE__ -# include <sysdep-cancel.h> +#if defined __NR_rt_sigtimedwait && defined __UCLIBC_HAS_REALTIME__ -# ifdef __NR_rt_sigtimedwait -# include <string.h> +#include <string.h> /* Return any pending signal or wait for one for the given time. */ -static int do_sigwait(const sigset_t *set, int *sig) +static int __NC(sigwait)(const sigset_t *set, int *sig) { int ret; -# ifdef SIGCANCEL - sigset_t tmpset; - if (set != NULL - && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) -# ifdef SIGSETXID - || __builtin_expect (__sigismember (set, SIGSETXID), 0) -# endif - )) - { - /* Create a temporary mask without the bit for SIGCANCEL set. */ - // We are not copying more than we have to. - memcpy(&tmpset, set, _NSIG / 8); - __sigdelset(&tmpset, SIGCANCEL); -# ifdef SIGSETXID - __sigdelset(&tmpset, SIGSETXID); -# endif - set = &tmpset; - } -# endif - - /* XXX The size argument hopefully will have to be changed to the - real size of the user-level sigset_t. */ - INTERNAL_SYSCALL_DECL(err); do - ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set, NULL, - NULL, _NSIG / 8); - while (INTERNAL_SYSCALL_ERROR_P (ret, err) - && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR); - if (! INTERNAL_SYSCALL_ERROR_P (ret, err)) - { + /* we might as well use sigtimedwait and do not care about cancellation */ + ret = __NC(sigtimedwait)(set, NULL, NULL); + while (ret == -1 && errno == EINTR); + if (ret != -1) { *sig = ret; ret = 0; - } -else - ret = INTERNAL_SYSCALL_ERRNO (ret, err); + } else + ret = errno; return ret; } -int sigwait (const sigset_t *set, int *sig) -{ - if(SINGLE_THREAD_P) - return do_sigwait(set, sig); - - int oldtype = LIBC_CANCEL_ASYNC(); - - int result = do_sigwait(set, sig); - - LIBC_CANCEL_RESET(oldtype); - - return result; -} -# else /* __NR_rt_sigtimedwait */ -# error We must have rt_sigtimedwait defined!!! -# endif -#else /* __UCLIBC_HAS_THREADS_NATIVE__ */ +#else /* __NR_rt_sigtimedwait */ -# if defined __UCLIBC_HAS_REALTIME__ - -int sigwait (const sigset_t *set, int *sig) -{ - int ret = 1; - if ((ret = __sigwaitinfo(set, NULL)) != -1) { - *sig = ret; - return 0; - } - return 1; -} - -# else /* __UCLIBC_HAS_REALTIME__ */ -# include <errno.h> -# include <unistd.h> /* smallint */ /* variant without REALTIME extensions */ +#include <unistd.h> /* smallint */ static smallint was_sig; /* obviously not thread-safe */ @@ -115,7 +59,7 @@ static void ignore_signal(int sig) was_sig = sig; } -int sigwait (const sigset_t *set, int *sig) +static int __NC(sigwait)(const sigset_t *set, int *sig) { sigset_t tmp_mask; struct sigaction saved[NSIG]; @@ -149,7 +93,7 @@ int sigwait (const sigset_t *set, int *sig) } /* Now we can wait for signals. */ - sigsuspend (&tmp_mask); + __NC(sigsuspend)(&tmp_mask); restore_handler: save_errno = errno; @@ -165,5 +109,6 @@ int sigwait (const sigset_t *set, int *sig) *sig = was_sig; return was_sig == -1 ? -1 : 0; } -# endif /* __UCLIBC_HAS_REALTIME__ */ -#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ +#endif /* __NR_rt_sigtimedwait */ + +CANCELLABLE_SYSCALL(int, sigwait, (const sigset_t *set, int *sig), (set, sig)) diff --git a/libc/sysdeps/linux/common/__rt_sigtimedwait.c b/libc/sysdeps/linux/common/__rt_sigtimedwait.c index 168e38071..962ccb04b 100644 --- a/libc/sysdeps/linux/common/__rt_sigtimedwait.c +++ b/libc/sysdeps/linux/common/__rt_sigtimedwait.c @@ -9,41 +9,46 @@ */ #include <sys/syscall.h> -#include <signal.h> -#include <string.h> #ifdef __NR_rt_sigtimedwait +# include <signal.h> +# include <cancel.h> +# ifdef SIGCANCEL /* defined only in NPTL's pthreadP.h */ +# define __need_NULL +# include <stddef.h> +# include <string.h> +# endif -# ifdef __UCLIBC_HAS_THREADS_NATIVE__ -# include <sysdep-cancel.h> - -static int do_sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec *timeout) +int __NC(sigtimedwait)(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) { -# ifdef SIGCANCEL +# ifdef SIGCANCEL sigset_t tmpset; if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) -# ifdef SIGSETXID +# ifdef SIGSETXID || __builtin_expect (__sigismember (set, SIGSETXID), 0) -# endif +# endif )) { /* Create a temporary mask without the bit for SIGCANCEL set. */ // We are not copying more than we have to. memcpy (&tmpset, set, _NSIG / 8); __sigdelset (&tmpset, SIGCANCEL); -# ifdef SIGSETXID +# ifdef SIGSETXID __sigdelset (&tmpset, SIGSETXID); -# endif +# endif set = &tmpset; } -# endif +# endif +/* if this is enabled, enable the disabled section in sigwait.c */ +# if defined SI_TKILL && defined SI_USER /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ - int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, - timeout, _NSIG / 8); + /* on uClibc we use the kernel sigset_t size */ + int result = INLINE_SYSCALL(rt_sigtimedwait, 4, set, info, + timeout, __SYSCALL_SIGSET_T_SIZE); /* The kernel generates a SI_TKILL code in si_code in case tkill is used. tkill is transparently used in raise(). Since having @@ -53,38 +58,14 @@ static int do_sigtimedwait(const sigset_t *set, siginfo_t *info, info->si_code = SI_USER; return result; -} - -/* Return any pending signal or wait for one for the given time. */ -int __sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec *timeout) -{ - if(SINGLE_THREAD_P) - return do_sigtimedwait(set, info, timeout); - - int oldtype = LIBC_CANCEL_ASYNC(); - - /* XXX The size argument hopefully will have to be changed to the - real size of the user-level sigset_t. */ - int result = do_sigtimedwait(set, info, timeout); - - LIBC_CANCEL_RESET(oldtype); - - return result; -} # else -# define __need_NULL -# include <stddef.h> -# define __NR___rt_sigtimedwait __NR_rt_sigtimedwait -static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, - siginfo_t *, info, const struct timespec *, timeout, - size_t, setsize); - -int __sigtimedwait(const sigset_t * set, siginfo_t * info, - const struct timespec *timeout) -{ - return __rt_sigtimedwait(set, info, timeout, _NSIG / 8); + /* on uClibc we use the kernel sigset_t size */ + return INLINE_SYSCALL(rt_sigtimedwait, 4, set, info, + timeout, __SYSCALL_SIGSET_T_SIZE); +# endif } -# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */ -weak_alias(__sigtimedwait,sigtimedwait) +CANCELLABLE_SYSCALL(int, sigtimedwait, + (const sigset_t *set, siginfo_t *info, const struct timespec *timeout), + (set, info, timeout)) +lt_libc_hidden(sigtimedwait) #endif diff --git a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c index 74db6d6f9..ad1a7a890 100644 --- a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c +++ b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c @@ -9,79 +9,17 @@ */ #include <sys/syscall.h> -#include <signal.h> -#include <string.h> #ifdef __NR_rt_sigtimedwait +# define __need_NULL +# include <stddef.h> +# include <signal.h> +# include <cancel.h> -# ifdef __UCLIBC_HAS_THREADS_NATIVE__ -# include <sysdep-cancel.h> - -static int do_sigwaitinfo(const sigset_t *set, siginfo_t *info) -{ -# ifdef SIGCANCEL - sigset_t tmpset; - - if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) -# ifdef SIGSETXID - || __builtin_expect (__sigismember (set, SIGSETXID), 0) -# endif - )) - { - /* Create a temporary mask without the bit for SIGCANCEL set. */ - // We are not copying more than we have to. - memcpy (&tmpset, set, _NSIG / 8); - __sigdelset (&tmpset, SIGCANCEL); -# ifdef SIGSETXID - __sigdelset (&tmpset, SIGSETXID); -# endif - set = &tmpset; - } -# endif - - /* XXX The size argument hopefully will have to be changed to the - real size of the user-level sigset_t. */ - int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, - NULL, _NSIG / 8); - - /* The kernel generates a SI_TKILL code in si_code in case tkill is - used. tkill is transparently used in raise(). Since having - SI_TKILL as a code is useful in general we fold the results - here. */ - if (result != -1 && info != NULL && info->si_code == SI_TKILL) - info->si_code = SI_USER; - - return result; -} - -/* Return any pending signal or wait for one for the given time. */ -int __sigwaitinfo(const sigset_t *set, siginfo_t *info) -{ - if(SINGLE_THREAD_P) - return do_sigwaitinfo(set, info); - - int oldtype = LIBC_CANCEL_ASYNC(); - - /* XXX The size argument hopefully will have to be changed to the - real size of the user-level sigset_t. */ - int result = do_sigwaitinfo(set, info); - - LIBC_CANCEL_RESET(oldtype); - - return result; -} -# else -# define __need_NULL -# include <stddef.h> -# define __NR___rt_sigwaitinfo __NR_rt_sigtimedwait -static _syscall4(int, __rt_sigwaitinfo, const sigset_t *, set, - siginfo_t *, info, const struct timespec *, timeout, - size_t, setsize); - -int __sigwaitinfo(const sigset_t * set, siginfo_t * info) +int sigwaitinfo(const sigset_t *set, siginfo_t *info) { - return __rt_sigwaitinfo(set, info, NULL, _NSIG / 8); + return sigtimedwait(set, info, NULL); } -# endif -weak_alias (__sigwaitinfo, sigwaitinfo) +/* cancellation handled by sigtimedwait, noop on uClibc */ +LIBC_CANCEL_HANDLED(); #endif |