summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libthr/thread/thr_cancel.c41
-rw-r--r--lib/libthr/thread/thr_cond.c4
-rw-r--r--lib/libthr/thread/thr_create.c13
-rw-r--r--lib/libthr/thread/thr_exit.c19
-rw-r--r--lib/libthr/thread/thr_fork.c6
-rw-r--r--lib/libthr/thread/thr_init.c8
-rw-r--r--lib/libthr/thread/thr_join.c4
-rw-r--r--lib/libthr/thread/thr_kern.c32
-rw-r--r--lib/libthr/thread/thr_private.h33
-rw-r--r--lib/libthr/thread/thr_rtld.c13
-rw-r--r--lib/libthr/thread/thr_sig.c518
-rw-r--r--lib/libthr/thread/thr_syscalls.c129
-rw-r--r--lib/libthr/thread/thr_umtx.c39
-rw-r--r--lib/libthr/thread/thr_umtx.h5
14 files changed, 591 insertions, 273 deletions
diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c
index 943d53c..e408e03 100644
--- a/lib/libthr/thread/thr_cancel.c
+++ b/lib/libthr/thread/thr_cancel.c
@@ -85,14 +85,11 @@ _pthread_setcancelstate(int state, int *oldstate)
oldval = curthread->cancel_enable;
switch (state) {
case PTHREAD_CANCEL_DISABLE:
- THR_LOCK(curthread);
curthread->cancel_enable = 0;
- THR_UNLOCK(curthread);
break;
case PTHREAD_CANCEL_ENABLE:
- THR_LOCK(curthread);
curthread->cancel_enable = 1;
- THR_UNLOCK(curthread);
+ testcancel(curthread);
break;
default:
return (EINVAL);
@@ -136,23 +133,22 @@ _pthread_testcancel(void)
{
struct pthread *curthread = _get_curthread();
- _thr_cancel_enter(curthread);
- _thr_cancel_leave(curthread);
+ curthread->cancel_point = 1;
+ testcancel(curthread);
+ curthread->cancel_point = 0;
}
void
_thr_cancel_enter(struct pthread *curthread)
{
- curthread->cancel_point++;
- if (curthread->cancel_enable)
- testcancel(curthread);
+ curthread->cancel_point = 1;
+ testcancel(curthread);
}
void
-_thr_cancel_enter_defer(struct pthread *curthread, int maycancel)
+_thr_cancel_enter2(struct pthread *curthread, int maycancel)
{
- curthread->cancel_defer++;
- curthread->cancel_point++;
+ curthread->cancel_point = 1;
if (__predict_false(SHOULD_CANCEL(curthread) &&
!THR_IN_CRITICAL(curthread))) {
if (!maycancel)
@@ -163,24 +159,9 @@ _thr_cancel_enter_defer(struct pthread *curthread, int maycancel)
}
void
-_thr_cancel_leave(struct pthread *curthread)
-{
- curthread->cancel_point--;
-}
-
-void
-_thr_cancel_leave2(struct pthread *curthread, int maycancel)
-{
- if (curthread->cancel_enable && maycancel)
- testcancel(curthread);
- curthread->cancel_point--;
-}
-
-void
-_thr_cancel_leave_defer(struct pthread *curthread, int maycancel)
+_thr_cancel_leave(struct pthread *curthread, int maycancel)
{
- if (curthread->cancel_enable && maycancel)
+ if (maycancel)
testcancel(curthread);
- curthread->cancel_point--;
- curthread->cancel_defer--;
+ curthread->cancel_point = 0;
}
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
index 95970d9..07f1b8b 100644
--- a/lib/libthr/thread/thr_cond.c
+++ b/lib/libthr/thread/thr_cond.c
@@ -210,10 +210,10 @@ cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
if (cancel) {
THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
- _thr_cancel_enter_defer(curthread, 0);
+ _thr_cancel_enter2(curthread, 0);
ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 1);
info.cond = NULL;
- _thr_cancel_leave_defer(curthread, (ret != 0));
+ _thr_cancel_leave(curthread, (ret != 0));
THR_CLEANUP_POP(curthread, 0);
} else {
ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 0);
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
index f73a6c9..2677571 100644
--- a/lib/libthr/thread/thr_create.c
+++ b/lib/libthr/thread/thr_create.c
@@ -127,11 +127,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED)
new_thread->tlflags |= TLFLAGS_DETACHED;
- if (curthread->in_sigcancel_handler)
- new_thread->unblock_sigcancel = 1;
- else
- new_thread->unblock_sigcancel = 0;
-
/* Add the new thread. */
new_thread->refcount = 1;
_thr_link(curthread, new_thread);
@@ -263,14 +258,6 @@ thread_start(struct pthread *curthread)
if (curthread->force_exit)
_pthread_exit(PTHREAD_CANCELED);
- if (curthread->unblock_sigcancel) {
- sigset_t set1;
-
- SIGEMPTYSET(set1);
- SIGADDSET(set1, SIGCANCEL);
- __sys_sigprocmask(SIG_UNBLOCK, &set1, NULL);
- }
-
if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
#if 0
/* Done in THR_UNLOCK() */
diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
index e6facd9..10581ab 100644
--- a/lib/libthr/thread/thr_exit.c
+++ b/lib/libthr/thread/thr_exit.c
@@ -34,6 +34,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
#include "un-namespace.h"
#include "libc_private.h"
@@ -58,6 +60,12 @@ _thread_exit(const char *fname, int lineno, const char *msg)
void
_pthread_exit(void *status)
{
+ _pthread_exit_mask(status, NULL);
+}
+
+void
+_pthread_exit_mask(void *status, sigset_t *mask)
+{
struct pthread *curthread = _get_curthread();
/* Check if this thread is already in the process of exiting: */
@@ -73,6 +81,17 @@ _pthread_exit(void *status)
curthread->cancelling = 1;
curthread->cancel_enable = 0;
curthread->cancel_async = 0;
+ curthread->cancel_point = 0;
+ if (mask != NULL)
+ __sys_sigprocmask(SIG_SETMASK, mask, NULL);
+ if (curthread->unblock_sigcancel) {
+ sigset_t set;
+
+ curthread->unblock_sigcancel = 0;
+ SIGEMPTYSET(set);
+ SIGADDSET(set, SIGCANCEL);
+ __sys_sigprocmask(SIG_UNBLOCK, mask, NULL);
+ }
/* Save the return value: */
curthread->ret = status;
diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c
index f20942d..8e1ea6a 100644
--- a/lib/libthr/thread/thr_fork.c
+++ b/lib/libthr/thread/thr_fork.c
@@ -115,6 +115,7 @@ __pthread_cxa_finalize(struct dl_phdr_info *phdr_info)
}
THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock);
_thr_tsd_unload(phdr_info);
+ _thr_sigact_unload(phdr_info);
}
__weak_reference(_fork, fork);
@@ -161,6 +162,7 @@ _fork(void)
* Block all signals until we reach a safe point.
*/
_thr_signal_block(curthread);
+ _thr_signal_prefork();
/* Fork a new process: */
if ((ret = __sys_fork()) == 0) {
@@ -182,6 +184,8 @@ _fork(void)
_thr_umutex_init(&curthread->lock);
_thr_umutex_init(&_thr_atfork_lock);
+ _thr_signal_postfork_child();
+
if (was_threaded)
_rtld_atfork_post(rtld_locks);
_thr_setthreaded(0);
@@ -211,6 +215,8 @@ _fork(void)
/* Parent process */
errsave = errno;
+ _thr_signal_postfork();
+
/* Ready to continue, unblock signals. */
_thr_signal_unblock(curthread);
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index 1bfdd28..ea567ee 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -289,7 +289,6 @@ void
_libpthread_init(struct pthread *curthread)
{
int fd, first = 0;
- sigset_t sigset, oldset;
/* Check if this function has already been called: */
if ((_thr_initial != NULL) && (curthread == NULL))
@@ -347,13 +346,8 @@ _libpthread_init(struct pthread *curthread)
_tcb_set(curthread->tcb);
if (first) {
- SIGFILLSET(sigset);
- SIGDELSET(sigset, SIGTRAP);
- __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
- _thr_signal_init();
_thr_initial = curthread;
- SIGDELSET(oldset, SIGCANCEL);
- __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ _thr_signal_init();
if (_thread_event_mask & TD_CREATE)
_thr_report_creation(curthread, curthread);
}
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
index 8201aba..d3c8367 100644
--- a/lib/libthr/thread/thr_join.c
+++ b/lib/libthr/thread/thr_join.c
@@ -107,7 +107,7 @@ join_common(pthread_t pthread, void **thread_return,
THREAD_LIST_UNLOCK(curthread);
THR_CLEANUP_PUSH(curthread, backout_join, pthread);
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
tid = pthread->tid;
while (pthread->tid != TID_TERMINATED) {
@@ -127,7 +127,7 @@ join_common(pthread_t pthread, void **thread_return,
break;
}
- _thr_cancel_leave_defer(curthread, 0);
+ _thr_cancel_leave(curthread, 0);
THR_CLEANUP_POP(curthread, 0);
if (ret == ETIMEDOUT) {
diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c
index 649a973..3ad33ad 100644
--- a/lib/libthr/thread/thr_kern.c
+++ b/lib/libthr/thread/thr_kern.c
@@ -61,38 +61,6 @@ _thr_setthreaded(int threaded)
}
void
-_thr_signal_block(struct pthread *curthread)
-{
- sigset_t set;
-
- if (curthread->sigblock > 0) {
- curthread->sigblock++;
- return;
- }
- SIGFILLSET(set);
- SIGDELSET(set, SIGBUS);
- SIGDELSET(set, SIGILL);
- SIGDELSET(set, SIGFPE);
- SIGDELSET(set, SIGSEGV);
- SIGDELSET(set, SIGTRAP);
- __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask);
- curthread->sigblock++;
-}
-
-void
-_thr_signal_unblock(struct pthread *curthread)
-{
- if (--curthread->sigblock == 0)
- __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
-}
-
-int
-_thr_send_sig(struct pthread *thread, int sig)
-{
- return thr_kill(thread->tid, sig);
-}
-
-void
_thr_assert_lock_level()
{
PANIC("locklevel <= 0");
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index f261810..492d58d 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -376,12 +376,21 @@ struct pthread {
/* Thread temporary signal mask. */
sigset_t sigmask;
- /* Thread is in SIGCANCEL handler. */
- int in_sigcancel_handler;
-
- /* New thread should unblock SIGCANCEL. */
+ /* Thread should unblock SIGCANCEL. */
int unblock_sigcancel;
+ /* In sigsuspend state */
+ int in_sigsuspend;
+
+ /* deferred signal info */
+ siginfo_t deferred_siginfo;
+
+ /* signal mask to restore. */
+ sigset_t deferred_sigmask;
+
+ /* the sigaction should be used for deferred signal. */
+ struct sigaction deferred_sigact;
+
/* Force new thread to exit. */
int force_exit;
@@ -629,6 +638,7 @@ void _thr_ref_delete_unlocked(struct pthread *, struct pthread *) __hidden;
int _thr_find_thread(struct pthread *, struct pthread *, int) __hidden;
void _thr_rtld_init(void) __hidden;
void _thr_rtld_fini(void) __hidden;
+void _thr_rtld_postfork_child(void) __hidden;
int _thr_stack_alloc(struct pthread_attr *) __hidden;
void _thr_stack_free(struct pthread_attr *) __hidden;
void _thr_free(struct pthread *, struct pthread *) __hidden;
@@ -637,10 +647,8 @@ void _thread_cleanupspecific(void) __hidden;
void _thread_printf(int, const char *, ...) __hidden;
void _thr_spinlock_init(void) __hidden;
void _thr_cancel_enter(struct pthread *) __hidden;
-void _thr_cancel_leave(struct pthread *) __hidden;
-void _thr_cancel_leave2(struct pthread *, int) __hidden;
-void _thr_cancel_enter_defer(struct pthread *, int) __hidden;
-void _thr_cancel_leave_defer(struct pthread *, int) __hidden;
+void _thr_cancel_enter2(struct pthread *, int) __hidden;
+void _thr_cancel_leave(struct pthread *, int) __hidden;
void _thr_testcancel(struct pthread *) __hidden;
void _thr_signal_block(struct pthread *) __hidden;
void _thr_signal_unblock(struct pthread *) __hidden;
@@ -653,7 +661,6 @@ void _thr_hash_remove(struct pthread *) __hidden;
struct pthread *_thr_hash_find(struct pthread *) __hidden;
void _thr_link(struct pthread *, struct pthread *) __hidden;
void _thr_unlink(struct pthread *, struct pthread *) __hidden;
-void _thr_suspend_check(struct pthread *) __hidden;
void _thr_assert_lock_level(void) __hidden __dead2;
void _thr_ast(struct pthread *) __hidden;
void _thr_once_init(void) __hidden;
@@ -662,6 +669,9 @@ void _thr_report_creation(struct pthread *curthread,
void _thr_report_death(struct pthread *curthread) __hidden;
int _thr_getscheduler(lwpid_t, int *, struct sched_param *) __hidden;
int _thr_setscheduler(lwpid_t, int, const struct sched_param *) __hidden;
+void _thr_signal_prefork(void) __hidden;
+void _thr_signal_postfork(void) __hidden;
+void _thr_signal_postfork_child(void) __hidden;
int _rtp_to_schedparam(const struct rtprio *rtp, int *policy,
struct sched_param *param) __hidden;
int _schedparam_to_rtp(int policy, const struct sched_param *param,
@@ -672,6 +682,8 @@ int _sched_yield(void);
void _pthread_cleanup_push(void (*)(void *), void *);
void _pthread_cleanup_pop(int);
+void _pthread_exit_mask(void *status, sigset_t *mask) __dead2 __hidden;
+
/* #include <fcntl.h> */
#ifdef _SYS_FCNTL_H_
@@ -687,7 +699,7 @@ int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
int __sys_sigpending(sigset_t *);
int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
int __sys_sigsuspend(const sigset_t *);
-int __sys_sigreturn(ucontext_t *);
+int __sys_sigreturn(const ucontext_t *);
int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
int __sys_sigwait(const sigset_t *, int *);
int __sys_sigtimedwait(const sigset_t *, siginfo_t *,
@@ -740,6 +752,7 @@ _thr_check_init(void)
struct dl_phdr_info;
void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
+void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
__END_DECLS
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
index d9041ad..e6af702 100644
--- a/lib/libthr/thread/thr_rtld.c
+++ b/lib/libthr/thread/thr_rtld.c
@@ -32,6 +32,7 @@
*/
#include <sys/cdefs.h>
#include <stdlib.h>
+#include <string.h>
#include "rtld_lock.h"
#include "thr_private.h"
@@ -132,7 +133,7 @@ _thr_rtld_wlock_acquire(void *lock)
SAVE_ERRNO();
l = (struct rtld_lock *)lock;
- _thr_signal_block(curthread);
+ THR_CRITICAL_ENTER(curthread);
while (_thr_rwlock_wrlock(&l->lock, NULL) != 0)
;
RESTORE_ERRNO();
@@ -152,12 +153,9 @@ _thr_rtld_lock_release(void *lock)
state = l->lock.rw_state;
if (_thr_rwlock_unlock(&l->lock) == 0) {
- if ((state & URWLOCK_WRITE_OWNER) == 0) {
+ if ((state & URWLOCK_WRITE_OWNER) == 0)
curthread->rdlock_count--;
- THR_CRITICAL_LEAVE(curthread);
- } else {
- _thr_signal_unblock(curthread);
- }
+ THR_CRITICAL_LEAVE(curthread);
}
RESTORE_ERRNO();
}
@@ -193,6 +191,9 @@ _thr_rtld_init(void)
/* force to resolve errno() PLT */
__error();
+ /* force to resolve memcpy PLT */
+ memcpy(&dummy, &dummy, sizeof(dummy));
+
li.lock_create = _thr_rtld_lock_create;
li.lock_destroy = _thr_rtld_lock_destroy;
li.rlock_acquire = _thr_rtld_rlock_acquire;
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
index 312c15f..382ff4f 100644
--- a/lib/libthr/thread/thr_sig.c
+++ b/lib/libthr/thread/thr_sig.c
@@ -32,11 +32,10 @@
#include <sys/signalvar.h>
#include <signal.h>
#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "un-namespace.h"
+#include "libc_private.h"
#include "thr_private.h"
@@ -47,7 +46,19 @@
#define DBG_MSG(x...)
#endif
-extern int __pause(void);
+struct usigaction {
+ struct sigaction sigact;
+ struct urwlock lock;
+};
+
+static struct usigaction _thr_sigact[_SIG_MAXSIG];
+
+static void thr_sighandler(int, siginfo_t *, void *);
+static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *);
+static void check_deferred_signal(struct pthread *);
+static void check_suspend(struct pthread *);
+static void check_cancel(struct pthread *curthread, ucontext_t *ucp);
+
int ___pause(void);
int _raise(int);
int __sigtimedwait(const sigset_t *set, siginfo_t *info,
@@ -59,10 +70,49 @@ int _sigwaitinfo(const sigset_t *set, siginfo_t *info);
int __sigwait(const sigset_t *set, int *sig);
int _sigwait(const sigset_t *set, int *sig);
int __sigsuspend(const sigset_t *sigmask);
+int _sigaction(int, const struct sigaction *, struct sigaction *);
int _setcontext(const ucontext_t *);
int _swapcontext(ucontext_t *, const ucontext_t *);
-static void
+static const sigset_t _thr_deferset={{
+ 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)|
+ _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)),
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff}};
+
+static const sigset_t _thr_maskset={{
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff}};
+
+void
+_thr_signal_block(struct pthread *curthread)
+{
+
+ if (curthread->sigblock > 0) {
+ curthread->sigblock++;
+ return;
+ }
+ __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask);
+ curthread->sigblock++;
+}
+
+void
+_thr_signal_unblock(struct pthread *curthread)
+{
+ if (--curthread->sigblock == 0)
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+}
+
+int
+_thr_send_sig(struct pthread *thread, int sig)
+{
+ return thr_kill(thread->tid, sig);
+}
+
+static inline void
remove_thr_signals(sigset_t *set)
{
if (SIGISMEMBER(*set, SIGCANCEL))
@@ -72,87 +122,244 @@ remove_thr_signals(sigset_t *set)
static const sigset_t *
thr_remove_thr_signals(const sigset_t *set, sigset_t *newset)
{
- const sigset_t *pset;
-
- if (SIGISMEMBER(*set, SIGCANCEL)) {
- *newset = *set;
- SIGDELSET(*newset, SIGCANCEL);
- pset = newset;
- } else
- pset = set;
- return (pset);
+ *newset = *set;
+ remove_thr_signals(newset);
+ return (newset);
}
static void
sigcancel_handler(int sig __unused,
- siginfo_t *info __unused, ucontext_t *ucp __unused)
+ siginfo_t *info __unused, ucontext_t *ucp)
{
struct pthread *curthread = _get_curthread();
+ int err;
- curthread->in_sigcancel_handler++;
- _thr_ast(curthread);
- curthread->in_sigcancel_handler--;
+ if (THR_IN_CRITICAL(curthread))
+ return;
+ err = errno;
+ check_suspend(curthread);
+ check_cancel(curthread, ucp);
+ errno = err;
+}
+
+typedef void (*ohandler)(int sig, int code,
+ struct sigcontext *scp, char *addr, __sighandler_t *catcher);
+
+/*
+ * The signal handler wrapper is entered with all signal masked.
+ */
+static void
+thr_sighandler(int sig, siginfo_t *info, void *_ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ ucontext_t *ucp = _ucp;
+ struct sigaction act;
+ int err;
+
+ err = errno;
+ _thr_rwl_rdlock(&_thr_sigact[sig-1].lock);
+ act = _thr_sigact[sig-1].sigact;
+ _thr_rwl_unlock(&_thr_sigact[sig-1].lock);
+ errno = err;
+
+ /*
+ * if a thread is in critical region, for example it holds low level locks,
+ * try to defer the signal processing, however if the signal is synchronous
+ * signal, it means a bad thing has happened, this is a programming error,
+ * resuming fault point can not help anything (normally causes deadloop),
+ * so here we let user code handle it immediately.
+ */
+ if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) {
+ memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction));
+ memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t));
+ curthread->deferred_sigmask = ucp->uc_sigmask;
+ /* mask all signals, we will restore it later. */
+ ucp->uc_sigmask = _thr_deferset;
+ return;
+ }
+
+ handle_signal(&act, sig, info, ucp);
+}
+
+static void
+handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ ucontext_t uc2;
+ __siginfohandler_t *sigfunc;
+ int cancel_defer;
+ int cancel_point;
+ int cancel_async;
+ int cancel_enable;
+ int in_sigsuspend;
+ int err;
+
+ /* add previous level mask */
+ SIGSETOR(actp->sa_mask, ucp->uc_sigmask);
+
+ /* add this signal's mask */
+ if (!(actp->sa_flags & SA_NODEFER))
+ SIGADDSET(actp->sa_mask, sig);
+
+ in_sigsuspend = curthread->in_sigsuspend;
+ curthread->in_sigsuspend = 0;
+
+ /*
+ * if thread is in deferred cancellation mode, disable cancellation
+ * in signal handler.
+ * if user signal handler calls a cancellation point function, e.g,
+ * it calls write() to write data to file, because write() is a
+ * cancellation point, the thread is immediately cancelled if
+ * cancellation is pending, to avoid this problem while thread is in
+ * deferring mode, cancellation is temporarily disabled.
+ */
+ cancel_defer = curthread->cancel_defer;
+ cancel_point = curthread->cancel_point;
+ cancel_async = curthread->cancel_async;
+ cancel_enable = curthread->cancel_enable;
+ curthread->cancel_point = 0;
+ curthread->cancel_defer = 0;
+ if (!cancel_async)
+ curthread->cancel_enable = 0;
+
+ /* restore correct mask before calling user handler */
+ __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL);
+
+ sigfunc = actp->sa_sigaction;
+
+ /*
+ * We have already reset cancellation point flags, so if user's code
+ * longjmp()s out of its signal handler, wish its jmpbuf was set
+ * outside of a cancellation point, in most cases, this would be
+ * true. however, ther is no way to save cancel_enable in jmpbuf,
+ * so after setjmps() returns once more, the user code may need to
+ * re-set cancel_enable flag by calling pthread_setcancelstate().
+ */
+ if ((actp->sa_flags & SA_SIGINFO) != 0)
+ (*(sigfunc))(sig, info, ucp);
+ else {
+ ((ohandler)(*sigfunc))(
+ sig, info->si_code, (struct sigcontext *)ucp,
+ info->si_addr, (__sighandler_t *)sigfunc);
+ }
+ err = errno;
+
+ curthread->in_sigsuspend = in_sigsuspend;
+ curthread->cancel_defer = cancel_defer;
+ curthread->cancel_point = cancel_point;
+ curthread->cancel_enable = cancel_enable;
+
+ memcpy(&uc2, ucp, sizeof(uc2));
+ SIGDELSET(uc2.uc_sigmask, SIGCANCEL);
+
+ /* reschedule cancellation */
+ check_cancel(curthread, &uc2);
+ errno = err;
+ __sys_sigreturn(&uc2);
}
void
_thr_ast(struct pthread *curthread)
{
- if (THR_IN_CRITICAL(curthread))
+ if (!THR_IN_CRITICAL(curthread)) {
+ check_deferred_signal(curthread);
+ check_suspend(curthread);
+ check_cancel(curthread, NULL);
+ }
+}
+
+/* reschedule cancellation */
+static void
+check_cancel(struct pthread *curthread, ucontext_t *ucp)
+{
+
+ if (__predict_true(!curthread->cancel_pending || !curthread->cancel_enable ||
+ curthread->cancelling))
return;
- if (curthread->cancel_pending && curthread->cancel_enable
- && !curthread->cancelling) {
- if (curthread->cancel_async) {
- /*
- * asynchronous cancellation mode, act upon
- * immediately.
- */
- _pthread_exit(PTHREAD_CANCELED);
- } else {
- /*
- * Otherwise, we are in defer mode, and we are at
- * cancel point, tell kernel to not block the current
- * thread on next cancelable system call.
- *
- * There are two cases we should call thr_wake() to
- * turn on TDP_WAKEUP in kernel:
- * 1) we are going to call a cancelable system call,
- * non-zero cancel_point means we are already in
- * cancelable state, next system call is cancelable.
- * 2) because _thr_ast() may be called by
- * THR_CRITICAL_LEAVE() which is used by rtld rwlock
- * and any libthr internal locks, when rtld rwlock
- * is used, it is mostly caused my an unresolved PLT.
- * those routines may clear the TDP_WAKEUP flag by
- * invoking some system calls, in those cases, we
- * also should reenable the flag.
- */
- if (curthread->cancel_point) {
- if (curthread->cancel_defer)
- thr_wake(curthread->tid);
- else
- _pthread_exit(PTHREAD_CANCELED);
- }
+ if (curthread->cancel_async) {
+ /*
+ * asynchronous cancellation mode, act upon
+ * immediately.
+ */
+ _pthread_exit_mask(PTHREAD_CANCELED,
+ ucp? &ucp->uc_sigmask : NULL);
+ } else {
+ /*
+ * Otherwise, we are in defer mode, and we are at
+ * cancel point, tell kernel to not block the current
+ * thread on next cancelable system call.
+ *
+ * There are three cases we should call thr_wake() to
+ * turn on TDP_WAKEUP or send SIGCANCEL in kernel:
+ * 1) we are going to call a cancelable system call,
+ * non-zero cancel_point means we are already in
+ * cancelable state, next system call is cancelable.
+ * 2) because _thr_ast() may be called by
+ * THR_CRITICAL_LEAVE() which is used by rtld rwlock
+ * and any libthr internal locks, when rtld rwlock
+ * is used, it is mostly caused my an unresolved PLT.
+ * those routines may clear the TDP_WAKEUP flag by
+ * invoking some system calls, in those cases, we
+ * also should reenable the flag.
+ * 3) thread is in sigsuspend(), and the syscall insists
+ * on getting a signal before it agrees to return.
+ */
+ if (curthread->cancel_point) {
+ if (curthread->in_sigsuspend && ucp) {
+ SIGADDSET(ucp->uc_sigmask, SIGCANCEL);
+ curthread->unblock_sigcancel = 1;
+ _thr_send_sig(curthread, SIGCANCEL);
+ } else
+ thr_wake(curthread->tid);
}
}
+}
+
+static void
+check_deferred_signal(struct pthread *curthread)
+{
+ ucontext_t uc;
+ struct sigaction act;
+ siginfo_t info;
+ volatile int first;
- if (__predict_false((curthread->flags &
- (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
- == THR_FLAGS_NEED_SUSPEND))
- _thr_suspend_check(curthread);
+ if (__predict_true(curthread->deferred_siginfo.si_signo == 0))
+ return;
+ first = 1;
+ getcontext(&uc);
+ if (first) {
+ first = 0;
+ act = curthread->deferred_sigact;
+ uc.uc_sigmask = curthread->deferred_sigmask;
+ memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t));
+ /* remove signal */
+ curthread->deferred_siginfo.si_signo = 0;
+ if (act.sa_flags & SA_RESETHAND) {
+ struct sigaction tact;
+
+ tact = act;
+ tact.sa_handler = SIG_DFL;
+ _sigaction(info.si_signo, &tact, NULL);
+ }
+ handle_signal(&act, info.si_signo, &info, &uc);
+ }
}
-void
-_thr_suspend_check(struct pthread *curthread)
+static void
+check_suspend(struct pthread *curthread)
{
uint32_t cycle;
- int err;
+
+ if (__predict_true((curthread->flags &
+ (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
+ != THR_FLAGS_NEED_SUSPEND))
+ return;
if (curthread->force_exit)
return;
- err = errno;
/*
* Blocks SIGCANCEL which other threads must send.
*/
@@ -188,15 +395,7 @@ _thr_suspend_check(struct pthread *curthread)
THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
curthread->critical_count--;
- /*
- * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
- * a new signal frame will nest us, this seems a problem because
- * stack will grow and overflow, but because kernel will automatically
- * mask the SIGCANCEL when delivering the signal, so we at most only
- * have one nesting signal frame, this should be fine.
- */
_thr_signal_unblock(curthread);
- errno = err;
}
void
@@ -204,11 +403,80 @@ _thr_signal_init(void)
{
struct sigaction act;
- /* Install cancel handler. */
- SIGEMPTYSET(act.sa_mask);
- act.sa_flags = SA_SIGINFO | SA_RESTART;
+ /* Install SIGCANCEL handler. */
+ SIGFILLSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
__sys_sigaction(SIGCANCEL, &act, NULL);
+
+ /* Unblock SIGCANCEL */
+ SIGEMPTYSET(act.sa_mask);
+ SIGADDSET(act.sa_mask, SIGCANCEL);
+ __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
+}
+
+/*
+ * called from rtld with rtld_lock locked, because rtld_lock is
+ * a critical region, so all signals have already beeen masked.
+ */
+void
+_thr_sigact_unload(struct dl_phdr_info *phdr_info)
+{
+ struct urwlock *rwlp;
+ struct sigaction *actp;
+ struct sigaction kact;
+ void (*handler)(int);
+ int sig;
+
+ for (sig = 1; sig < _SIG_MAXSIG; sig++) {
+ actp = &_thr_sigact[sig].sigact;
+retry:
+ handler = actp->sa_handler;
+ if (handler != SIG_DFL && handler != SIG_IGN &&
+ __elf_phdr_match_addr(phdr_info, handler)) {
+ rwlp = &_thr_sigact[sig].lock;
+ _thr_rwl_wrlock(rwlp);
+ if (handler != actp->sa_handler) {
+ _thr_rwl_unlock(rwlp);
+ goto retry;
+ }
+ actp->sa_handler = SIG_DFL;
+ actp->sa_flags = SA_SIGINFO;
+ SIGEMPTYSET(actp->sa_mask);
+ if (__sys_sigaction(sig, NULL, &kact) == 0 &&
+ kact.sa_handler != SIG_DFL &&
+ kact.sa_handler != SIG_IGN)
+ __sys_sigaction(sig, actp, NULL);
+ _thr_rwl_unlock(rwlp);
+ }
+ }
+}
+
+void
+_thr_signal_prefork(void)
+{
+ int i;
+
+ for (i = 1; i < _SIG_MAXSIG; ++i)
+ _thr_rwl_rdlock(&_thr_sigact[i-1].lock);
+}
+
+void
+_thr_signal_postfork(void)
+{
+ int i;
+
+ for (i = 1; i < _SIG_MAXSIG; ++i)
+ _thr_rwl_unlock(&_thr_sigact[i-1].lock);
+}
+
+void
+_thr_signal_postfork_child(void)
+{
+ int i;
+
+ for (i = 1; i < _SIG_MAXSIG; ++i)
+ bzero(&_thr_sigact[i-1].lock, sizeof(struct urwlock));
}
void
@@ -221,14 +489,11 @@ __weak_reference(___pause, pause);
int
___pause(void)
{
- struct pthread *curthread = _get_curthread();
- int ret;
+ sigset_t oset;
- _thr_cancel_enter(curthread);
- ret = __pause();
- _thr_cancel_leave(curthread);
-
- return ret;
+ if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1)
+ return (-1);
+ return (__sigsuspend(&oset));
}
__weak_reference(_raise, raise);
@@ -236,13 +501,7 @@ __weak_reference(_raise, raise);
int
_raise(int sig)
{
- int ret;
-
- if (!_thr_isthreaded())
- ret = kill(getpid(), sig);
- else
- ret = _thr_send_sig(_get_curthread(), sig);
- return (ret);
+ return _thr_send_sig(_get_curthread(), sig);
}
__weak_reference(_sigaction, sigaction);
@@ -250,14 +509,65 @@ __weak_reference(_sigaction, sigaction);
int
_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{
- /* Check if the signal number is out of range: */
+ struct sigaction newact, oldact, oldact2;
+ sigset_t oldset;
+ int ret = 0, err = 0;
+
if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
- /* Return an invalid argument: */
errno = EINVAL;
return (-1);
}
- return __sys_sigaction(sig, act, oact);
+ if (act)
+ newact = *act;
+
+ __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset);
+ _thr_rwl_wrlock(&_thr_sigact[sig-1].lock);
+
+ if (act != NULL) {
+ oldact2 = _thr_sigact[sig-1].sigact;
+
+ /*
+ * if a new sig handler is SIG_DFL or SIG_IGN,
+ * don't remove old handler from _thr_sigact[],
+ * so deferred signals still can use the handlers,
+ * multiple threads invoking sigaction itself is
+ * a race condition, so it is not a problem.
+ */
+ if (newact.sa_handler != SIG_DFL &&
+ newact.sa_handler != SIG_IGN) {
+ _thr_sigact[sig-1].sigact = newact;
+ remove_thr_signals(
+ &_thr_sigact[sig-1].sigact.sa_mask);
+ newact.sa_flags &= ~SA_NODEFER;
+ newact.sa_flags |= SA_SIGINFO;
+ newact.sa_sigaction = thr_sighandler;
+ newact.sa_mask = _thr_maskset; /* mask all signals */
+ }
+ if ((ret = __sys_sigaction(sig, &newact, &oldact))) {
+ err = errno;
+ _thr_sigact[sig-1].sigact = oldact2;
+ }
+ } else if (oact != NULL) {
+ ret = __sys_sigaction(sig, NULL, &oldact);
+ err = errno;
+ }
+
+ if (oldact.sa_handler != SIG_DFL &&
+ oldact.sa_handler != SIG_IGN) {
+ oldact = _thr_sigact[sig-1].sigact;
+ }
+
+ _thr_rwl_unlock(&_thr_sigact[sig-1].lock);
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+ if (ret == 0) {
+ if (oact != NULL)
+ *oact = oldact;
+ } else {
+ errno = err;
+ }
+ return (ret);
}
__weak_reference(_sigprocmask, sigprocmask);
@@ -301,13 +611,24 @@ _sigsuspend(const sigset_t * set)
int
__sigsuspend(const sigset_t * set)
{
- struct pthread *curthread = _get_curthread();
+ struct pthread *curthread;
sigset_t newset;
- int ret;
+ int ret, old;
+ curthread = _get_curthread();
+
+ old = curthread->in_sigsuspend;
+ curthread->in_sigsuspend = 1;
_thr_cancel_enter(curthread);
ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset));
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
+ curthread->in_sigsuspend = old;
+ if (curthread->unblock_sigcancel) {
+ curthread->unblock_sigcancel = 0;
+ SIGEMPTYSET(newset);
+ SIGADDSET(newset, SIGCANCEL);
+ __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL);
+ }
return (ret);
}
@@ -339,10 +660,10 @@ __sigtimedwait(const sigset_t *set, siginfo_t *info,
sigset_t newset;
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info,
timeout);
- _thr_cancel_leave_defer(curthread, (ret == -1));
+ _thr_cancel_leave(curthread, (ret == -1));
return (ret);
}
@@ -366,9 +687,9 @@ __sigwaitinfo(const sigset_t *set, siginfo_t *info)
sigset_t newset;
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -392,9 +713,9 @@ __sigwait(const sigset_t *set, int *sig)
sigset_t newset;
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig);
- _thr_cancel_leave_defer(curthread, (ret != 0));
+ _thr_cancel_leave(curthread, (ret != 0));
return (ret);
}
@@ -404,9 +725,8 @@ _setcontext(const ucontext_t *ucp)
{
ucontext_t uc;
- (void) memcpy(&uc, ucp, sizeof (uc));
+ (void) memcpy(&uc, ucp, sizeof(uc));
remove_thr_signals(&uc.uc_sigmask);
-
return __sys_setcontext(&uc);
}
@@ -416,7 +736,7 @@ _swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
{
ucontext_t uc;
- (void) memcpy(&uc, ucp, sizeof (uc));
+ (void) memcpy(&uc, ucp, sizeof(uc));
remove_thr_signals(&uc.uc_sigmask);
return __sys_swapcontext(oucp, &uc);
}
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
index 73fa56f..2327d74 100644
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -169,9 +169,9 @@ __accept(int s, struct sockaddr *addr, socklen_t *addrlen)
int ret;
curthread = _get_curthread();
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_accept(s, addr, addrlen);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -187,7 +187,7 @@ __aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
_thr_cancel_enter(curthread);
ret = __sys_aio_suspend(iocbs, niocb, timeout);
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -207,9 +207,9 @@ __close(int fd)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 0);
+ _thr_cancel_enter2(curthread, 0);
ret = __sys_close(fd);
- _thr_cancel_leave_defer(curthread, 1);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -226,9 +226,9 @@ __connect(int fd, const struct sockaddr *name, socklen_t namelen)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 0);
+ _thr_cancel_enter(curthread);
ret = __sys_connect(fd, name, namelen);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -245,9 +245,9 @@ ___creat(const char *path, mode_t mode)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __creat(path, mode);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -269,30 +269,15 @@ __fcntl(int fd, int cmd,...)
va_list ap;
va_start(ap, cmd);
- switch (cmd) {
- case F_DUPFD:
- case F_DUP2FD:
- ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
- break;
- case F_SETFD:
- case F_SETFL:
- ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
- break;
- case F_GETFD:
- case F_GETFL:
- ret = __sys_fcntl(fd, cmd);
- break;
- case F_OSETLKW:
- case F_SETLKW:
- _thr_cancel_enter_defer(curthread, 1);
+ if (cmd == F_OSETLKW || cmd == F_SETLKW) {
+ _thr_cancel_enter(curthread);
#ifdef SYSCALL_COMPAT
ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
#else
ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
#endif
- _thr_cancel_leave_defer(curthread, ret == -1);
- break;
- default:
+ _thr_cancel_leave(curthread, ret == -1);
+ } else {
#ifdef SYSCALL_COMPAT
ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
#else
@@ -316,9 +301,9 @@ __fsync(int fd)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 0);
+ _thr_cancel_enter2(curthread, 0);
ret = __sys_fsync(fd);
- _thr_cancel_leave_defer(curthread, 1);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -335,9 +320,9 @@ __msync(void *addr, size_t len, int flags)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 0);
+ _thr_cancel_enter2(curthread, 0);
ret = __sys_msync(addr, len, flags);
- _thr_cancel_leave_defer(curthread, 1);
+ _thr_cancel_leave(curthread, 1);
return ret;
}
@@ -353,7 +338,7 @@ __nanosleep(const struct timespec *time_to_sleep,
_thr_cancel_enter(curthread);
ret = __sys_nanosleep(time_to_sleep, time_remaining);
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -380,9 +365,9 @@ __open(const char *path, int flags,...)
va_end(ap);
}
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_open(path, flags, mode);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -410,9 +395,9 @@ __openat(int fd, const char *path, int flags, ...)
va_end(ap);
}
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_openat(fd, path, flags, mode);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -430,9 +415,9 @@ __poll(struct pollfd *fds, unsigned int nfds, int timeout)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_poll(fds, nfds, timeout);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -451,9 +436,9 @@ ___pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_pselect(count, rfds, wfds, efds, timo, mask);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -471,9 +456,9 @@ __read(int fd, void *buf, size_t nbytes)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_read(fd, buf, nbytes);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -491,9 +476,9 @@ __readv(int fd, const struct iovec *iov, int iovcnt)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_readv(fd, iov, iovcnt);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -511,9 +496,9 @@ __recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_recvfrom(s, b, l, f, from, fl);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -530,9 +515,9 @@ __recvmsg(int s, struct msghdr *m, int f)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_recvmsg(s, m, f);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -550,9 +535,9 @@ __select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return ret;
}
@@ -569,9 +554,9 @@ __sendmsg(int s, const struct msghdr *m, int f)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_sendmsg(s, m, f);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return (ret);
}
@@ -589,9 +574,9 @@ __sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_sendto(s, m, l, f, t, tl);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return (ret);
}
@@ -605,7 +590,7 @@ ___sleep(unsigned int seconds)
_thr_cancel_enter(curthread);
ret = __sleep(seconds);
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -620,7 +605,7 @@ ___system(const char *string)
_thr_cancel_enter(curthread);
ret = __system(string);
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
return ret;
}
@@ -638,9 +623,9 @@ ___tcdrain(int fd)
struct pthread *curthread = _get_curthread();
int ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __tcdrain(fd);
- _thr_cancel_leave_defer(curthread, ret == -1);
+ _thr_cancel_leave(curthread, ret == -1);
return (ret);
}
@@ -654,7 +639,7 @@ ___usleep(useconds_t useconds)
_thr_cancel_enter(curthread);
ret = __usleep(useconds);
- _thr_cancel_leave(curthread);
+ _thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -672,9 +657,9 @@ ___wait(int *istat)
struct pthread *curthread = _get_curthread();
pid_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __wait(istat);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return ret;
}
@@ -692,9 +677,9 @@ __wait3(int *status, int options, struct rusage *rusage)
struct pthread *curthread = _get_curthread();
pid_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = _wait4(WAIT_ANY, status, options, rusage);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return (ret);
}
@@ -712,9 +697,9 @@ __wait4(pid_t pid, int *status, int options, struct rusage *rusage)
struct pthread *curthread = _get_curthread();
pid_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_wait4(pid, status, options, rusage);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return ret;
}
@@ -732,9 +717,9 @@ ___waitpid(pid_t wpid, int *status, int options)
struct pthread *curthread = _get_curthread();
pid_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __waitpid(wpid, status, options);
- _thr_cancel_leave_defer(curthread, ret <= 0);
+ _thr_cancel_leave(curthread, ret <= 0);
return ret;
}
@@ -752,9 +737,9 @@ __write(int fd, const void *buf, size_t nbytes)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_write(fd, buf, nbytes);
- _thr_cancel_leave_defer(curthread, (ret <= 0));
+ _thr_cancel_leave(curthread, (ret <= 0));
return ret;
}
@@ -771,8 +756,8 @@ __writev(int fd, const struct iovec *iov, int iovcnt)
struct pthread *curthread = _get_curthread();
ssize_t ret;
- _thr_cancel_enter_defer(curthread, 1);
+ _thr_cancel_enter(curthread);
ret = __sys_writev(fd, iov, iovcnt);
- _thr_cancel_leave_defer(curthread, (ret <= 0));
+ _thr_cancel_leave(curthread, (ret <= 0));
return ret;
}
diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c
index 5af923d..b712b7a 100644
--- a/lib/libthr/thread/thr_umtx.c
+++ b/lib/libthr/thread/thr_umtx.c
@@ -217,3 +217,42 @@ __thr_rwlock_unlock(struct urwlock *rwlock)
{
return _umtx_op_err(rwlock, UMTX_OP_RW_UNLOCK, 0, NULL, NULL);
}
+
+void
+_thr_rwl_rdlock(struct urwlock *rwlock)
+{
+ int ret;
+
+ for (;;) {
+ if (_thr_rwlock_tryrdlock(rwlock, URWLOCK_PREFER_READER) == 0)
+ return;
+ ret = __thr_rwlock_rdlock(rwlock, URWLOCK_PREFER_READER, NULL);
+ if (ret == 0)
+ return;
+ if (ret != EINTR)
+ PANIC("rdlock error");
+ }
+}
+
+void
+_thr_rwl_wrlock(struct urwlock *rwlock)
+{
+ int ret;
+
+ for (;;) {
+ if (_thr_rwlock_trywrlock(rwlock) == 0)
+ return;
+ ret = __thr_rwlock_wrlock(rwlock, NULL);
+ if (ret == 0)
+ return;
+ if (ret != EINTR)
+ PANIC("wrlock error");
+ }
+}
+
+void
+_thr_rwl_unlock(struct urwlock *rwlock)
+{
+ if (_thr_rwlock_unlock(rwlock))
+ PANIC("unlock error");
+}
diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h
index a6e462e..2048984 100644
--- a/lib/libthr/thread/thr_umtx.h
+++ b/lib/libthr/thread/thr_umtx.h
@@ -58,6 +58,11 @@ int __thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp)
int __thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) __hidden;
int __thr_rwlock_unlock(struct urwlock *rwlock) __hidden;
+/* Internal used only */
+void _thr_rwl_rdlock(struct urwlock *rwlock) __hidden;
+void _thr_rwl_wrlock(struct urwlock *rwlock) __hidden;
+void _thr_rwl_unlock(struct urwlock *rwlock) __hidden;
+
static inline int
_thr_umutex_trylock(struct umutex *mtx, uint32_t id)
{
OpenPOWER on IntegriCloud