Browse Source

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>
Peter S. Mazinger 13 years ago
parent
commit
b72b0b14d0

+ 2 - 1
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

+ 18 - 73
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))

+ 28 - 47
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

+ 8 - 70
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