summaryrefslogtreecommitdiff
path: root/src/thread/synccall.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread/synccall.c')
-rw-r--r--src/thread/synccall.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/src/thread/synccall.c b/src/thread/synccall.c
index 648a6ad4..38597254 100644
--- a/src/thread/synccall.c
+++ b/src/thread/synccall.c
@@ -11,7 +11,7 @@ weak_alias(dummy_0, __tl_unlock);
static int target_tid;
static void (*callback)(void *), *context;
-static sem_t target_sem, caller_sem;
+static sem_t target_sem, caller_sem, exit_sem;
static void dummy(void *p)
{
@@ -33,7 +33,7 @@ static void handler(int sig)
/* Inform caller we've complered the callback and wait
* for the caller to release us to return. */
sem_post(&caller_sem);
- sem_wait(&target_sem);
+ sem_wait(&exit_sem);
/* Inform caller we are returning and state is destroyable. */
sem_post(&caller_sem);
@@ -45,7 +45,7 @@ void __synccall(void (*func)(void *), void *ctx)
{
sigset_t oldmask;
int cs, i, r;
- struct sigaction sa = { .sa_flags = SA_RESTART, .sa_handler = handler };
+ struct sigaction sa = { .sa_flags = SA_RESTART | SA_ONSTACK, .sa_handler = handler };
pthread_t self = __pthread_self(), td;
int count = 0;
@@ -62,8 +62,10 @@ void __synccall(void (*func)(void *), void *ctx)
sem_init(&target_sem, 0, 0);
sem_init(&caller_sem, 0, 0);
+ sem_init(&exit_sem, 0, 0);
- if (!libc.threads_minus_1) goto single_threaded;
+ if (!libc.threads_minus_1 || __syscall(SYS_gettid) != self->tid)
+ goto single_threaded;
callback = func;
context = ctx;
@@ -106,12 +108,13 @@ single_threaded:
/* Only release the caught threads once all threads, including the
* caller, have returned from the callback function. */
for (i=0; i<count; i++)
- sem_post(&target_sem);
+ sem_post(&exit_sem);
for (i=0; i<count; i++)
sem_wait(&caller_sem);
sem_destroy(&caller_sem);
sem_destroy(&target_sem);
+ sem_destroy(&exit_sem);
pthread_setcancelstate(cs, 0);
__tl_unlock();