| |
| |
| |
| |
| |
| |
|
|
| #include <assert.h> |
| #include <math.h> |
| #include <pthread.h> |
| #include <stdatomic.h> |
|
|
| #include "em_task_queue.h" |
| #include "pthread_impl.h" |
| #include "thread_mailbox.h" |
| #include "threading_internal.h" |
|
|
| int emscripten_thread_mailbox_ref(pthread_t thread) { |
| |
| |
| int prev_count = thread->mailbox_refcount; |
| while (1) { |
| if (prev_count == 0) { |
| |
| return 0; |
| } |
| int desired_count = prev_count + 1; |
| if (atomic_compare_exchange_weak( |
| &thread->mailbox_refcount, &prev_count, desired_count)) { |
| return 1; |
| } |
| } |
| } |
|
|
| |
| void emscripten_thread_mailbox_unref(pthread_t thread) { |
| int new_count = atomic_fetch_sub(&thread->mailbox_refcount, 1) - 1; |
| assert(new_count >= 0); |
| if (new_count == 0) { |
| |
| |
| |
| emscripten_futex_wake(&thread->mailbox_refcount, INT_MAX); |
| } |
| } |
|
|
| void _emscripten_thread_mailbox_shutdown(pthread_t thread) { |
| assert(thread == pthread_self()); |
|
|
| |
| assert(thread->mailbox_refcount > 0); |
| int count = atomic_fetch_sub(&thread->mailbox_refcount, 1) - 1; |
|
|
| while (count != 0) { |
| emscripten_futex_wait(&thread->mailbox_refcount, count, INFINITY); |
| count = thread->mailbox_refcount; |
| } |
|
|
| |
| |
| em_task_queue_cancel(thread->mailbox); |
|
|
| |
| em_task_queue_destroy(thread->mailbox); |
| } |
|
|
| void _emscripten_thread_mailbox_init(pthread_t thread) { |
| thread->mailbox = em_task_queue_create(thread); |
| thread->mailbox_refcount = 1; |
| thread->waiting_async = 0; |
| } |
|
|
| |
| void _emscripten_check_mailbox() { |
| |
| |
| |
| |
| |
| DBG("_emscripten_check_mailbox"); |
| assert(pthread_self()); |
| em_task_queue* mailbox = pthread_self()->mailbox; |
| mailbox->notification = NOTIFICATION_RECEIVED; |
| em_task_queue_execute(pthread_self()->mailbox); |
| notification_state expected = NOTIFICATION_RECEIVED; |
| atomic_compare_exchange_strong( |
| &mailbox->notification, &expected, NOTIFICATION_NONE); |
| |
| |
| __pthread_testcancel(); |
| } |
|
|
| void emscripten_thread_mailbox_send(pthread_t thread, task t) { |
| assert(thread->mailbox_refcount > 0); |
|
|
| pthread_mutex_lock(&thread->mailbox->mutex); |
| if (!em_task_queue_enqueue(thread->mailbox, t)) { |
| assert(0 && "No way to correctly recover from allocation failure"); |
| } |
| pthread_mutex_unlock(&thread->mailbox->mutex); |
|
|
| |
| |
| |
| |
| notification_state previous = |
| atomic_exchange(&thread->mailbox->notification, NOTIFICATION_PENDING); |
| if (previous != NOTIFICATION_PENDING) { |
| if (thread->waiting_async) { |
| __builtin_wasm_memory_atomic_notify((int*)thread, -1); |
| } else { |
| _emscripten_notify_mailbox_postmessage(thread, pthread_self()); |
| } |
| } |
| } |
|
|