diff options
-rw-r--r-- | libc/signal/sigwait.c | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/libc/signal/sigwait.c b/libc/signal/sigwait.c index f15208863..a47c37ce2 100644 --- a/libc/signal/sigwait.c +++ b/libc/signal/sigwait.c @@ -23,8 +23,6 @@ #include <signal.h> #include <string.h> -libc_hidden_proto(sigwaitinfo) - #ifdef __UCLIBC_HAS_THREADS_NATIVE__ # include <sysdep-cancel.h> @@ -57,7 +55,6 @@ static int do_sigwait(const sigset_t *set, int *sig) /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ -# ifdef INTERNAL_SYSCALL INTERNAL_SYSCALL_DECL(err); do ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set, NULL, @@ -71,9 +68,6 @@ static int do_sigwait(const sigset_t *set, int *sig) } else ret = INTERNAL_SYSCALL_ERRNO (ret, err); -# else -# error INTERNAL_SYSCALL must be defined!!! -# endif return ret; } @@ -92,11 +86,13 @@ int __sigwait (const sigset_t *set, int *sig) return result; } -# else +# else /* __NR_rt_sigtimedwait */ # error We must have rt_sigtimedwait defined!!! # endif -#else -# undef sigwait +#else /* __UCLIBC_HAS_THREADS_NATIVE__ */ + +# if define __UCLIBC_HAS_REALTIME__ + int __sigwait (const sigset_t *set, int *sig) attribute_hidden; int __sigwait (const sigset_t *set, int *sig) { @@ -107,7 +103,68 @@ int __sigwait (const sigset_t *set, int *sig) } return 1; } -#endif -libc_hidden_proto(sigwait) + +# else /* __UCLIBC_HAS_REALTIME__ */ +/* variant without REALTIME extensions */ + +static smallint was_sig; /* obviously not thread-safe */ + +static void ignore_signal(int sig) +{ + was_sig = sig; +} + +int sigwait (const sigset_t *set, int *sig) +{ + sigset_t tmp_mask; + struct sigaction saved[NSIG]; + struct sigaction action; + int save_errno; + int this; + + /* Prepare set. */ + __sigfillset (&tmp_mask); + + /* Unblock all signals in the SET and register our nice handler. */ + action.sa_handler = ignore_signal; + action.sa_flags = 0; + __sigfillset (&action.sa_mask); /* Block all signals for handler. */ + + /* Make sure we recognize error conditions by setting WAS_SIG to a + value which does not describe a legal signal number. */ + was_sig = -1; + + for (this = 1; this < NSIG; ++this) + if (__sigismember (set, this)) + { + /* Unblock this signal. */ + __sigdelset (&tmp_mask, this); + + /* Register temporary action handler. */ + /* In Linux (as of 2.6.25), fails only if sig is SIGKILL or SIGSTOP */ + /* (so, will it work correctly if set has, say, SIGSTOP?) */ + if (sigaction (this, &action, &saved[this]) != 0) + goto restore_handler; + } + + /* Now we can wait for signals. */ + sigsuspend (&tmp_mask); + + restore_handler: + save_errno = errno; + + while (--this >= 1) + if (__sigismember (set, this)) + /* We ignore errors here since we must restore all handlers. */ + sigaction (this, &saved[this], NULL); + + __set_errno (save_errno); + + /* Store the result and return. */ + *sig = was_sig; + return was_sig == -1 ? -1 : 0; +} +# endif /* __UCLIBC_HAS_REALTIME__ */ +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ weak_alias(__sigwait,sigwait) libc_hidden_def(sigwait) |