diff options
author | mtm <mtm@FreeBSD.org> | 2003-12-09 11:04:36 +0000 |
---|---|---|
committer | mtm <mtm@FreeBSD.org> | 2003-12-09 11:04:36 +0000 |
commit | 3fb7bc9aecff9a81307b8f072d11a18f9f34f8c9 (patch) | |
tree | e35c66d6530f0338c08ba206317bc1a8c857e006 /lib/libthr/thread/thr_syscalls.c | |
parent | 4e519fdfebb52ed6f448915d27a897f1740451c8 (diff) | |
download | FreeBSD-src-3fb7bc9aecff9a81307b8f072d11a18f9f34f8c9.zip FreeBSD-src-3fb7bc9aecff9a81307b8f072d11a18f9f34f8c9.tar.gz |
o Add a wrapper around sigaction(2), so we can insert our own wrapper
around signals.
o Lock the process global signal action table.
Diffstat (limited to 'lib/libthr/thread/thr_syscalls.c')
-rw-r--r-- | lib/libthr/thread/thr_syscalls.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c index 1f11e82..badd7cb 100644 --- a/lib/libthr/thread/thr_syscalls.c +++ b/lib/libthr/thread/thr_syscalls.c @@ -94,6 +94,7 @@ extern int __creat(const char *, mode_t); extern int __sleep(unsigned int); extern int __sys_nanosleep(const struct timespec *, struct timespec *); extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int __sys_sigaction(int, const struct sigaction *, struct sigaction *); extern int __system(const char *); extern int __tcdrain(int); extern pid_t __wait(int *); @@ -314,6 +315,63 @@ _select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, return ret; } +__weak_reference(_sigaction, sigaction); + +int +_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) +{ + struct sigaction *tmpact; + struct sigaction oldact, wrapperact; + int error; + + /* Detect invalid signals. Signal SIGTHR is silently ignored */ + if (sig < 1 || sig > NSIG) { + errno = EINVAL; + return (-1); + } + if (sig == SIGTHR) + return (0); + + /* + * If act is not NULL the library's signal wrapper is passed into the + * kernel only if the action is not SIG_DFL or SIG_IGN. + * On the other hand if act is NULL the caller only wants + * the old value so there is no need to call into the kernel. + */ + error = 0; + tmpact = NULL; + proc_sigact_copyout(sig, &oldact); + if (act != NULL) { + proc_sigact_copyin(sig, act); + tmpact = proc_sigact_sigaction(sig); + if (tmpact->sa_handler != SIG_DFL && + tmpact->sa_handler != SIG_IGN) { + bcopy((const void *)tmpact, (void *)&wrapperact, + sizeof(struct sigaction)); + tmpact->sa_flags &= SA_SIGINFO; + wrapperact.sa_sigaction = &_thread_sig_wrapper; + tmpact = &wrapperact; + } + error = __sys_sigaction(sig, tmpact, NULL); + } + if (error == 0) { + + /* If successful, return the old sigaction to the user */ + if (oact != NULL ) + bcopy((const void *)&oldact, (void *)oact, + sizeof(struct sigaction)); + } else { + + /* + * The only time error is non-zero is if the syscall failed, + * which means the sigaction in the process global list + * was altered before the syscall. Return it to it's old value. + */ + proc_sigact_copyin(sig, &oldact); + } + return (error); +} + __weak_reference(_sleep, sleep); unsigned int |