2011-02-12 00:22:29 -05:00
|
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
2012-11-08 17:04:20 -05:00
|
|
|
#include <string.h>
|
2011-02-12 00:22:29 -05:00
|
|
|
#include "syscall.h"
|
|
|
|
#include "pthread_impl.h"
|
2012-02-27 18:51:02 -05:00
|
|
|
#include "libc.h"
|
2012-07-11 02:44:14 -04:00
|
|
|
#include "ksigaction.h"
|
2011-02-12 00:22:29 -05:00
|
|
|
|
2011-02-13 19:01:43 -05:00
|
|
|
void __restore(), __restore_rt();
|
2011-02-12 00:22:29 -05:00
|
|
|
|
always initialize thread pointer at program start
this is the first step in an overhaul aimed at greatly simplifying and
optimizing everything dealing with thread-local state.
previously, the thread pointer was initialized lazily on first access,
or at program startup if stack protector was in use, or at certain
random places where inconsistent state could be reached if it were not
initialized early. while believed to be fully correct, the logic was
fragile and non-obvious.
in the first phase of the thread pointer overhaul, support is retained
(and in some cases improved) for systems/situation where loading the
thread pointer fails, e.g. old kernels.
some notes on specific changes:
- the confusing use of libc.main_thread as an indicator that the
thread pointer is initialized is eliminated in favor of an explicit
has_thread_pointer predicate.
- sigaction no longer needs to ensure that the thread pointer is
initialized before installing a signal handler (this was needed to
prevent a situation where the signal handler caused the thread
pointer to be initialized and the subsequent sigreturn cleared it
again) but it still needs to ensure that implementation-internal
thread-related signals are not blocked.
- pthread tsd initialization for the main thread is deferred in a new
manner to minimize bloat in the static-linked __init_tp code.
- pthread_setcancelstate no longer needs special handling for the
situation before the thread pointer is initialized. it simply fails
on systems that cannot support a thread pointer, which are
non-conforming anyway.
- pthread_cleanup_push/pop now check for missing thread pointer and
nop themselves out in this case, so stdio no longer needs to avoid
the cancellable path when the thread pointer is not available.
a number of cases remain where certain interfaces may crash if the
system does not support a thread pointer. at this point, these should
be limited to pthread interfaces, and the number of such cases should
be fewer than before.
2014-03-24 16:57:11 -04:00
|
|
|
static int unmask_done;
|
2013-08-09 21:03:47 -04:00
|
|
|
static unsigned long handler_set[_NSIG/(8*sizeof(long))];
|
|
|
|
|
|
|
|
void __get_handler_set(sigset_t *set)
|
|
|
|
{
|
|
|
|
memcpy(set, handler_set, sizeof handler_set);
|
|
|
|
}
|
|
|
|
|
2012-09-06 22:44:55 -04:00
|
|
|
int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
|
2011-02-12 00:22:29 -05:00
|
|
|
{
|
2013-07-30 09:14:56 -04:00
|
|
|
struct k_sigaction ksa, ksa_old;
|
2013-08-09 21:03:47 -04:00
|
|
|
if (sig >= (unsigned)_NSIG) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
2011-02-12 00:22:29 -05:00
|
|
|
if (sa) {
|
2013-08-09 21:03:47 -04:00
|
|
|
if ((uintptr_t)sa->sa_handler > 1UL) {
|
|
|
|
a_or_l(handler_set+(sig-1)/(8*sizeof(long)),
|
|
|
|
1UL<<(sig-1)%(8*sizeof(long)));
|
always initialize thread pointer at program start
this is the first step in an overhaul aimed at greatly simplifying and
optimizing everything dealing with thread-local state.
previously, the thread pointer was initialized lazily on first access,
or at program startup if stack protector was in use, or at certain
random places where inconsistent state could be reached if it were not
initialized early. while believed to be fully correct, the logic was
fragile and non-obvious.
in the first phase of the thread pointer overhaul, support is retained
(and in some cases improved) for systems/situation where loading the
thread pointer fails, e.g. old kernels.
some notes on specific changes:
- the confusing use of libc.main_thread as an indicator that the
thread pointer is initialized is eliminated in favor of an explicit
has_thread_pointer predicate.
- sigaction no longer needs to ensure that the thread pointer is
initialized before installing a signal handler (this was needed to
prevent a situation where the signal handler caused the thread
pointer to be initialized and the subsequent sigreturn cleared it
again) but it still needs to ensure that implementation-internal
thread-related signals are not blocked.
- pthread tsd initialization for the main thread is deferred in a new
manner to minimize bloat in the static-linked __init_tp code.
- pthread_setcancelstate no longer needs special handling for the
situation before the thread pointer is initialized. it simply fails
on systems that cannot support a thread pointer, which are
non-conforming anyway.
- pthread_cleanup_push/pop now check for missing thread pointer and
nop themselves out in this case, so stdio no longer needs to avoid
the cancellable path when the thread pointer is not available.
a number of cases remain where certain interfaces may crash if the
system does not support a thread pointer. at this point, these should
be limited to pthread interfaces, and the number of such cases should
be fewer than before.
2014-03-24 16:57:11 -04:00
|
|
|
|
|
|
|
/* If pthread_create has not yet been called,
|
|
|
|
* implementation-internal signals might not
|
|
|
|
* yet have been unblocked. They must be
|
|
|
|
* unblocked before any signal handler is
|
|
|
|
* installed, so that an application cannot
|
|
|
|
* receive an illegal sigset_t (with them
|
|
|
|
* blocked) as part of the ucontext_t passed
|
|
|
|
* to the signal handler. */
|
|
|
|
if (!libc.threaded && !unmask_done) {
|
|
|
|
__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
|
|
|
|
SIGPT_SET, 0, _NSIG/8);
|
|
|
|
unmask_done = 1;
|
|
|
|
}
|
2013-08-09 21:03:47 -04:00
|
|
|
}
|
2011-02-12 00:22:29 -05:00
|
|
|
ksa.handler = sa->sa_handler;
|
2011-02-13 16:46:33 -05:00
|
|
|
ksa.flags = sa->sa_flags | SA_RESTORER;
|
2011-02-13 19:01:43 -05:00
|
|
|
ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
|
2012-07-11 02:44:14 -04:00
|
|
|
memcpy(&ksa.mask, &sa->sa_mask, sizeof ksa.mask);
|
2011-02-12 00:22:29 -05:00
|
|
|
}
|
2013-07-30 09:14:56 -04:00
|
|
|
if (syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, sizeof ksa.mask))
|
2011-02-12 00:22:29 -05:00
|
|
|
return -1;
|
|
|
|
if (old) {
|
2013-07-30 09:14:56 -04:00
|
|
|
old->sa_handler = ksa_old.handler;
|
|
|
|
old->sa_flags = ksa_old.flags;
|
|
|
|
memcpy(&old->sa_mask, &ksa_old.mask, sizeof ksa_old.mask);
|
2011-02-12 00:22:29 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-06 22:44:55 -04:00
|
|
|
int __sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
|
2011-02-12 00:22:29 -05:00
|
|
|
{
|
overhaul implementation-internal signal protections
the new approach relies on the fact that the only ways to create
sigset_t objects without invoking UB are to use the sig*set()
functions, or from the masks returned by sigprocmask, sigaction, etc.
or in the ucontext_t argument to a signal handler. thus, as long as
sigfillset and sigaddset avoid adding the "protected" signals, there
is no way the application will ever obtain a sigset_t including these
bits, and thus no need to add the overhead of checking/clearing them
when sigprocmask or sigaction is called.
note that the old code actually *failed* to remove the bits from
sa_mask when sigaction was called.
the new implementations are also significantly smaller, simpler, and
faster due to ignoring the useless "GNU HURD signals" 65-1024, which
are not used and, if there's any sanity in the world, never will be
used.
2011-05-07 23:23:58 -04:00
|
|
|
if (sig-32U < 3) {
|
2011-02-12 00:22:29 -05:00
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return __libc_sigaction(sig, sa, old);
|
|
|
|
}
|
|
|
|
|
|
|
|
weak_alias(__sigaction, sigaction);
|