unix/mpthreadport: Remove busy wait loop in thread garbage collection.

One can't use pthread calls in a signal handler because they are not
async-signal-safe (see man signal-safety).  Instead, sem_post can be used
to post from within a signal handler and this should be more efficient than
using a busy wait loop, waiting on a volatile variable.
This commit is contained in:
Mikhail Zakharov 2019-01-02 10:44:52 -05:00 committed by Damien George
parent 1e7b422226
commit 18723e9889

View File

@ -36,6 +36,7 @@
#include <signal.h> #include <signal.h>
#include <sched.h> #include <sched.h>
#include <semaphore.h>
// this structure forms a linked list, one node per active thread // this structure forms a linked list, one node per active thread
typedef struct _thread_t { typedef struct _thread_t {
@ -53,7 +54,7 @@ STATIC thread_t *thread;
// this is used to synchronise the signal handler of the thread // this is used to synchronise the signal handler of the thread
// it's needed because we can't use any pthread calls in a signal handler // it's needed because we can't use any pthread calls in a signal handler
STATIC volatile int thread_signal_done; STATIC sem_t thread_signal_done;
// this signal handler is used to scan the regs and stack of a thread // this signal handler is used to scan the regs and stack of a thread
STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) {
@ -70,7 +71,7 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) {
void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start);
gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*));
#endif #endif
thread_signal_done = 1; sem_post(&thread_signal_done);
} }
} }
@ -84,6 +85,7 @@ void mp_thread_init(void) {
thread->ready = 1; thread->ready = 1;
thread->arg = NULL; thread->arg = NULL;
thread->next = NULL; thread->next = NULL;
sem_init(&thread_signal_done, 0, 0);
// enable signal handler for garbage collection // enable signal handler for garbage collection
struct sigaction sa; struct sigaction sa;
@ -122,11 +124,8 @@ void mp_thread_gc_others(void) {
if (!th->ready) { if (!th->ready) {
continue; continue;
} }
thread_signal_done = 0;
pthread_kill(th->id, SIGUSR1); pthread_kill(th->id, SIGUSR1);
while (thread_signal_done == 0) { sem_wait(&thread_signal_done);
sched_yield();
}
} }
pthread_mutex_unlock(&thread_mutex); pthread_mutex_unlock(&thread_mutex);
} }