summaryrefslogtreecommitdiffstats
path: root/lib/libpthread
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-12-29 23:21:09 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-12-29 23:21:09 +0000
commit8d750bfb1bf0228b6e58e834f4842c7080398d13 (patch)
treee2ab7b024b94d440af7be0888fe6e9a4498d59b5 /lib/libpthread
parent2d0145273e128a3db5439ade8d7f54ab879fffef (diff)
downloadFreeBSD-src-8d750bfb1bf0228b6e58e834f4842c7080398d13.zip
FreeBSD-src-8d750bfb1bf0228b6e58e834f4842c7080398d13.tar.gz
Implement sigaltstack() as per-threaded. Current only scope process thread
is supported, for scope system process, kernel signal bits need to be changed. Reviewed by: deischen Tested on : i386 amd64 ia64
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/pthread.map2
-rw-r--r--lib/libpthread/thread/Makefile.inc1
-rw-r--r--lib/libpthread/thread/thr_create.c3
-rw-r--r--lib/libpthread/thread/thr_sig.c147
-rw-r--r--lib/libpthread/thread/thr_sigaltstack.c104
5 files changed, 233 insertions, 24 deletions
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
index 04b308c..e3cc71d 100644
--- a/lib/libpthread/pthread.map
+++ b/lib/libpthread/pthread.map
@@ -154,6 +154,7 @@ global:
_sem_unlink;
_sem_wait;
_sigaction;
+ _sigaltstack;
_sigpending;
_sigprocmask;
_sigsuspend;
@@ -308,6 +309,7 @@ global:
sem_unlink;
sem_wait;
sigaction;
+ sigaltstack;
sigpending;
sigprocmask;
sigsuspend;
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
index 0a9da84..fb11adb 100644
--- a/lib/libpthread/thread/Makefile.inc
+++ b/lib/libpthread/thread/Makefile.inc
@@ -89,6 +89,7 @@ SRCS+= \
thr_setschedparam.c \
thr_sig.c \
thr_sigaction.c \
+ thr_sigaltstack.c \
thr_sigmask.c \
thr_sigpending.c \
thr_sigprocmask.c \
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
index eef5806..b82f1809 100644
--- a/lib/libpthread/thread/thr_create.c
+++ b/lib/libpthread/thread/thr_create.c
@@ -252,6 +252,9 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
sigemptyset(&new_thread->sigpend);
new_thread->check_pending = 0;
new_thread->locklevel = 0;
+ new_thread->sigstk.ss_sp = 0;
+ new_thread->sigstk.ss_size = 0;
+ new_thread->sigstk.ss_flags = SS_DISABLE;
if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
new_thread->state = PS_SUSPENDED;
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index 8759f20..a817371 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -399,16 +399,31 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
}
+struct sighandle_info {
+ __siginfohandler_t *sigfunc;
+ int sa_flags;
+ int sig;
+ siginfo_t *info;
+ ucontext_t *ucp;
+};
+
+static void handle_signal(struct pthread *curthread,
+ struct sighandle_info *shi);
+static void handle_signal_altstack(struct pthread *curthread,
+ struct sighandle_info *shi);
+
/* Must be called with signal lock and schedule lock held in order */
static void
thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
ucontext_t *ucp)
{
- void (*sigfunc)(int, siginfo_t *, void *);
+ __siginfohandler_t *sigfunc;
sigset_t sigmask;
int sa_flags;
+ int onstack;
struct sigaction act;
struct kse *curkse;
+ struct sighandle_info shi;
/*
* Invoke the signal handler without going through the scheduler:
@@ -444,31 +459,29 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
*/
if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
- _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+ onstack = _thr_sigonstack(&sigfunc);
+ ucp->uc_stack = curthread->sigstk;
+ ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0);
ucp->uc_sigmask = sigmask;
- if (((__sighandler_t *)sigfunc != SIG_DFL) &&
- ((__sighandler_t *)sigfunc != SIG_IGN)) {
- if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
- (*(sigfunc))(sig, info, ucp);
- else {
- ((ohandler)(*sigfunc))(
- sig, info->si_code, (struct sigcontext *)ucp,
- info->si_addr, (__sighandler_t *)sigfunc);
- }
+ shi.sigfunc = sigfunc;
+ shi.sig = sig;
+ shi.sa_flags = sig;
+ shi.info = info;
+ shi.ucp = ucp;
+ /*
+ * XXX Not ready for scope system thread, kernel bits
+ * should involve in
+ */
+ if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0 &&
+ (curthread->sigstk.ss_flags & SS_DISABLE) == 0) {
+ /* Deliver signal on alternative stack */
+ if (sa_flags & SA_ONSTACK && !onstack)
+ handle_signal_altstack(curthread, &shi);
+ else
+ handle_signal(curthread, &shi);
} else {
- if ((__sighandler_t *)sigfunc == SIG_DFL) {
- if (sigprop(sig) & SA_KILL) {
- if (_kse_isthreaded())
- kse_thr_interrupt(NULL,
- KSE_INTR_SIGEXIT, sig);
- else
- kill(getpid(), sig);
- }
-#ifdef NOTYET
- else if (sigprop(sig) & SA_STOP)
- kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig);
-#endif
- }
+ handle_signal(curthread, &shi);
}
_kse_critical_enter();
@@ -488,6 +501,89 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
}
+static void
+handle_signal(struct pthread *curthread, struct sighandle_info *shi)
+{
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ if (((__sighandler_t *)shi->sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)shi->sigfunc != SIG_IGN)) {
+ if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL)
+ (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp);
+ else {
+ ((ohandler)(*shi->sigfunc))(
+ shi->sig, shi->info->si_code,
+ (struct sigcontext *)shi->ucp,
+ shi->info->si_addr,
+ (__sighandler_t *)shi->sigfunc);
+ }
+ } else {
+ if ((__sighandler_t *)shi->sigfunc == SIG_DFL) {
+ if (sigprop(shi->sig) & SA_KILL) {
+ if (_kse_isthreaded())
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, shi->sig);
+ else
+ kill(getpid(), shi->sig);
+ }
+#ifdef NOTYET
+ else if (sigprop(shi->sig) & SA_STOP)
+ kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP,
+ shi->sig);
+#endif
+ }
+ }
+}
+
+static void
+handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc,
+ struct sighandle_info *shi)
+{
+ shi->ucp->uc_stack.ss_flags = SS_ONSTACK;
+ handle_signal(curthread, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(ret_uc);
+ else {
+ /* Work around for ia64, THR_SETCONTEXT does not work */
+ _kse_critical_enter();
+ curthread->tcb->tcb_tmbx.tm_context = *ret_uc;
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT */
+ }
+}
+
+/*
+ * Jump to stack set by sigaltstack before invoking signal handler
+ */
+static void
+handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi)
+{
+ volatile int once;
+ ucontext_t uc1, *uc2;
+
+ THR_ASSERT(_kse_in_critical(), "Not in critical");
+
+ once = 0;
+ THR_GETCONTEXT(&uc1);
+ if (once == 0) {
+ once = 1;
+ /* XXX
+ * We are still in critical region, it is safe to operate thread
+ * context
+ */
+ uc2 = &curthread->tcb->tcb_tmbx.tm_context;
+ uc2->uc_stack = curthread->sigstk;
+ makecontext(uc2, (void (*)(void))handle_signal_wrapper,
+ 3, curthread, &uc1, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(uc2);
+ else {
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT(uc2); */
+ }
+ }
+}
+
int
_thr_getprocsig(int sig, siginfo_t *siginfo)
{
@@ -1144,12 +1240,14 @@ _thr_signal_init(void)
PANIC("Cannot initialize signal handler");
}
__sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL);
+ __sys_sigaltstack(NULL, &_thr_initial->sigstk);
}
void
_thr_signal_deinit(void)
{
int i;
+ struct pthread *curthread = _get_curthread();
/* Enter a loop to get the existing signal status: */
for (i = 1; i <= _SIG_MAXSIG; i++) {
@@ -1167,5 +1265,6 @@ _thr_signal_deinit(void)
PANIC("Cannot set signal handler info");
}
}
+ __sys_sigaltstack(&curthread->sigstk, NULL);
}
diff --git a/lib/libpthread/thread/thr_sigaltstack.c b/lib/libpthread/thread/thr_sigaltstack.c
new file mode 100644
index 0000000..8a4a457
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigaltstack.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <signal.h>
+#include "thr_private.h"
+
+__weak_reference(_sigaltstack, sigaltstack);
+
+int
+_sigaltstack(stack_t *_ss, stack_t *_oss)
+{
+ struct pthread *curthread = _get_curthread();
+ stack_t ss, oss;
+ int oonstack, errsave, ret;
+ kse_critical_t crit;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ crit = _kse_critical_enter();
+ ret = __sys_sigaltstack(_ss, _oss);
+ errsave = errno;
+ /* Get a copy */
+ if (ret == 0 && _ss != NULL)
+ curthread->sigstk = *_ss;
+ _kse_critical_leave(crit);
+ errno = errsave;
+ return (ret);
+ }
+
+ if (_ss)
+ ss = *_ss;
+ if (_oss)
+ oss = *_oss;
+
+ /* Should get and set stack in atomic way */
+ crit = _kse_critical_enter();
+ oonstack = _thr_sigonstack(&ss);
+ if (_oss != NULL) {
+ oss = curthread->sigstk;
+ oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0);
+ }
+
+ if (_ss != NULL) {
+ if (oonstack) {
+ _kse_critical_leave(crit);
+ return (EPERM);
+ }
+ if ((ss.ss_flags & ~SS_DISABLE) != 0) {
+ _kse_critical_leave(crit);
+ return (EINVAL);
+ }
+ if (!(ss.ss_flags & SS_DISABLE)) {
+ if (ss.ss_size < MINSIGSTKSZ) {
+ _kse_critical_leave(crit);
+ return (ENOMEM);
+ }
+ curthread->sigstk = ss;
+ } else {
+ curthread->sigstk.ss_flags |= SS_DISABLE;
+ }
+ }
+ _kse_critical_leave(crit);
+ if (_oss != NULL)
+ *_oss = oss;
+ return (0);
+}
+
+int
+_thr_sigonstack(void *sp)
+{
+ struct pthread *curthread = _get_curthread();
+
+ return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ?
+ (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size)
+ : 0);
+}
+
OpenPOWER on IntegriCloud