1 #include "pthread_impl.h"
5 static void dummy_0(void)
9 weak_alias(dummy_0
, __tl_lock
);
10 weak_alias(dummy_0
, __tl_unlock
);
12 static int target_tid
;
13 static void (*callback
)(void *), *context
;
14 static sem_t target_sem
, caller_sem
, exit_sem
;
16 static void dummy(void *p
)
20 static void handler(int sig
)
22 if (__pthread_self()->tid
!= target_tid
) return;
24 int old_errno
= errno
;
26 /* Inform caller we have received signal and wait for
27 * the caller to let us make the callback. */
28 sem_post(&caller_sem
);
29 sem_wait(&target_sem
);
33 /* Inform caller we've complered the callback and wait
34 * for the caller to release us to return. */
35 sem_post(&caller_sem
);
38 /* Inform caller we are returning and state is destroyable. */
39 sem_post(&caller_sem
);
44 void __synccall(void (*func
)(void *), void *ctx
)
48 struct sigaction sa
= { .sa_flags
= SA_RESTART
| SA_ONSTACK
, .sa_handler
= handler
};
49 pthread_t self
= __pthread_self(), td
;
52 /* Blocking signals in two steps, first only app-level signals
53 * before taking the lock, then all signals after taking the lock,
54 * is necessary to achieve AS-safety. Blocking them all first would
55 * deadlock if multiple threads called __synccall. Waiting to block
56 * any until after the lock would allow re-entry in the same thread
57 * with the lock already held. */
58 __block_app_sigs(&oldmask
);
61 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
63 sem_init(&target_sem
, 0, 0);
64 sem_init(&caller_sem
, 0, 0);
65 sem_init(&exit_sem
, 0, 0);
67 if (!libc
.threads_minus_1
|| __syscall(SYS_gettid
) != self
->tid
)
73 /* Block even implementation-internal signals, so that nothing
74 * interrupts the SIGSYNCCALL handlers. The main possible source
75 * of trouble is asynchronous cancellation. */
76 memset(&sa
.sa_mask
, -1, sizeof sa
.sa_mask
);
77 __libc_sigaction(SIGSYNCCALL
, &sa
, 0);
80 for (td
=self
->next
; td
!=self
; td
=td
->next
) {
82 while ((r
= -__syscall(SYS_tkill
, td
->tid
, SIGSYNCCALL
)) == EAGAIN
);
84 /* If we failed to signal any thread, nop out the
85 * callback to abort the synccall and just release
86 * any threads already caught. */
87 callback
= func
= dummy
;
90 sem_wait(&caller_sem
);
95 /* Serialize execution of callback in caught threads, or just
96 * release them all if synccall is being aborted. */
97 for (i
=0; i
<count
; i
++) {
98 sem_post(&target_sem
);
99 sem_wait(&caller_sem
);
102 sa
.sa_handler
= SIG_IGN
;
103 __libc_sigaction(SIGSYNCCALL
, &sa
, 0);
108 /* Only release the caught threads once all threads, including the
109 * caller, have returned from the callback function. */
110 for (i
=0; i
<count
; i
++)
112 for (i
=0; i
<count
; i
++)
113 sem_wait(&caller_sem
);
115 sem_destroy(&caller_sem
);
116 sem_destroy(&target_sem
);
117 sem_destroy(&exit_sem
);
119 pthread_setcancelstate(cs
, 0);
121 __restore_sigs(&oldmask
);