summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter S. Mazinger <ps.m@gmx.net>2011-04-22 00:33:48 +0200
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2012-06-15 14:00:41 +0200
commitb72b0b14d0da0b506fbddf755cc8c7d0cd813287 (patch)
tree844a9b81562265974b81f3a21af413c07cd7f349
parent24edbbd53a382f35a4365ae065f61d56579f52f1 (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.h3
-rw-r--r--libc/signal/sigwait.c91
-rw-r--r--libc/sysdeps/linux/common/__rt_sigtimedwait.c75
-rw-r--r--libc/sysdeps/linux/common/__rt_sigwaitinfo.c78
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