diff options
| author | Austin Foxley <austinf@cetoncorp.com> | 2009-09-18 22:01:24 -0700 | 
|---|---|---|
| committer | Austin Foxley <austinf@cetoncorp.com> | 2009-09-18 22:01:24 -0700 | 
| commit | 6a425eea7816aa21cfbef8bed33fde10b7a44bdf (patch) | |
| tree | eabc7d59f138fbdd4b24ddeb4e224ab1b59776a5 | |
| parent | 490db039f2961032240fdafcdd6a2fc06518e44c (diff) | |
| download | uClibc-alpine-6a425eea7816aa21cfbef8bed33fde10b7a44bdf.tar.bz2 uClibc-alpine-6a425eea7816aa21cfbef8bed33fde10b7a44bdf.tar.xz  | |
add non realtime sigwait from master and cleanup a bit
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
| -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)  | 
