Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
33b5c4a
[wasm] Bump emscripten to 3.1.34
radekdoulik Mar 27, 2023
dff44d4
Update emsdk deps
radekdoulik Mar 27, 2023
ce1a265
Update icu deps
radekdoulik Mar 27, 2023
ed96a04
Use new images
radekdoulik Mar 27, 2023
8e6a28c
Use emscripten_main_runtime_thread_id
radekdoulik Mar 27, 2023
81672f4
Ignore ExitStatus exceptions
radekdoulik Mar 28, 2023
c2cbb94
Handle UnhandledPromiseRejection for ExitStatus
radekdoulik Mar 28, 2023
f3edd6e
Merge branch 'main' into pr-wasm-emscripten-3-1-34
radekdoulik Mar 28, 2023
4c0cb9e
[wasm][threads] flip YieldFromDispatchLoop; specialize PortableThread…
lambdageek Mar 15, 2023
3d88608
[mono] Implement a LifoJSSemaphore
lambdageek Mar 20, 2023
55b4649
Make managed LowLevelJSSemaphore
lambdageek Mar 20, 2023
8c74dea
copy-paste PortableThreadPool.WorkerThread for threaded WASM
lambdageek Mar 20, 2023
b323f0e
fixup native code for lifo semaphore
lambdageek Mar 21, 2023
51b1fbf
fixup managed code for LowLevelJSSemaphore
lambdageek Mar 21, 2023
3727ff1
Implement PortableThreadPool loop using semaphore callbacks
lambdageek Mar 21, 2023
763edab
manage emscripten event loop from PortableThreadPool.WorkerThread
lambdageek Mar 22, 2023
b45d001
FIXME: thread equality assertion in timeout callback
lambdageek Mar 22, 2023
1f7620c
XXX REVERT ME - minimal async timeout test
lambdageek Mar 22, 2023
06a3cc1
BUGFIX: &wait_entry ===> wait_entry
lambdageek Mar 23, 2023
8574368
nit: log thread id as hex in .ts
lambdageek Mar 23, 2023
c86cb26
XXX minimal sample - fetch on a background thread works
lambdageek Mar 23, 2023
c3cad74
fix non-wasm non-threads builds
lambdageek Mar 24, 2023
e57b262
Add WebWorkerEventLoop internal class to managed event loop keepalive
lambdageek Mar 24, 2023
07eabcd
Start threadpool threads with keepalive checks
lambdageek Mar 24, 2023
474607e
HACK: kind of work around the emscripten_runtime_keepalive_push/pop n…
lambdageek Mar 24, 2023
9f45167
support JS Semaphore with --print-icall-table cross compiler
lambdageek Mar 27, 2023
2e1f31f
make minimal FetchBackground sample more like a unit test
lambdageek Mar 27, 2023
dacc0cb
Share PortableThreadPool.WorkerThread common code
lambdageek Mar 29, 2023
10ca330
make both kinds of lifo semaphore share a base struct
lambdageek Mar 30, 2023
f4a2c02
Unify LowLevelLifoSemaphore for normal and async waiting
lambdageek Mar 30, 2023
42388d8
WebWorkerEventLoop: remove dead code, update comments
lambdageek Mar 31, 2023
853938e
remove unused arg from async wait semaphore
lambdageek Mar 31, 2023
cb8b168
rename native semaphore to LifoSemaphoreAsyncWait
lambdageek Mar 31, 2023
3e8fee4
Rename managed file to LowLevelLifoSemaphore.AsyncWait.Browser.Thread…
lambdageek Mar 31, 2023
552f9a5
Remove unnecessary indirections and allocations from managed AsyncWai…
lambdageek Mar 31, 2023
812524f
fix non-browser+threads builds
lambdageek Mar 31, 2023
50c0f1a
Keep track of unsettled JS interop promises in threadpool workers
lambdageek Apr 3, 2023
c8afaba
change minimal sample's fetch helper to artificially delay
lambdageek Apr 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rename native semaphore to LifoSemaphoreAsyncWait
prefix functions with mono_lifo_semaphore_asyncwait_
  • Loading branch information
lambdageek committed Mar 31, 2023
commit cb8b1688d4e17f4eaa72955d0767232ca797631d
18 changes: 9 additions & 9 deletions src/mono/mono/metadata/threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -5005,8 +5005,8 @@ ves_icall_System_Threading_LowLevelLifoSemaphore_InitInternal (int32_t kind)
case LIFO_SEMAPHORE_NORMAL:
return (gpointer)mono_lifo_semaphore_init ();
#if defined(HOST_BROWSER) && !defined(DISABLE_THREADS)
case LIFO_SEMAPHORE_ASYNC_JS:
return (gpointer)mono_lifo_js_semaphore_init ();
case LIFO_SEMAPHORE_ASYNCWAIT:
return (gpointer)mono_lifo_semaphore_asyncwait_init ();
#endif
default:
g_error ("Invalid LowLevelLifoSemaphore kind %d\n", kind);
Expand All @@ -5023,8 +5023,8 @@ ves_icall_System_Threading_LowLevelLifoSemaphore_DeleteInternal (gpointer sem_pt
mono_lifo_semaphore_delete ((LifoSemaphore*)sem);
break;
#if defined(HOST_BROWSER) && !defined(DISABLE_THREADS)
case LIFO_SEMAPHORE_ASYNC_JS:
mono_lifo_js_semaphore_delete ((LifoJSSemaphore*)sem);
case LIFO_SEMAPHORE_ASYNCWAIT:
mono_lifo_semaphore_asyncwait_delete ((LifoSemaphoreAsyncWait*)sem);
break;
#endif
default:
Expand All @@ -5049,8 +5049,8 @@ ves_icall_System_Threading_LowLevelLifoSemaphore_ReleaseInternal (gpointer sem_p
mono_lifo_semaphore_release ((LifoSemaphore*)sem, count);
break;
#if defined(HOST_BROWSER) && !defined(DISABLE_THREADS)
case LIFO_SEMAPHORE_ASYNC_JS:
mono_lifo_js_semaphore_release ((LifoJSSemaphore*)sem, count);
case LIFO_SEMAPHORE_ASYNCWAIT:
mono_lifo_semaphore_asyncwait_release ((LifoSemaphoreAsyncWait*)sem, count);
break;
#endif
default:
Expand All @@ -5062,9 +5062,9 @@ ves_icall_System_Threading_LowLevelLifoSemaphore_ReleaseInternal (gpointer sem_p
void
ves_icall_System_Threading_LowLevelLifoSemaphore_PrepareAsyncWaitInternal (gpointer sem_ptr, gint32 timeout_ms, gpointer success_cb, gpointer timedout_cb, intptr_t user_data)
{
LifoJSSemaphore *sem = (LifoJSSemaphore *)sem_ptr;
g_assert (sem->base.kind == LIFO_SEMAPHORE_ASYNC_JS);
mono_lifo_js_semaphore_prepare_wait (sem, timeout_ms, (LifoJSSemaphoreCallbackFn)success_cb, (LifoJSSemaphoreCallbackFn)timedout_cb, user_data);
LifoSemaphoreAsyncWait *sem = (LifoSemaphoreAsyncWait *)sem_ptr;
g_assert (sem->base.kind == LIFO_SEMAPHORE_ASYNCWAIT);
mono_lifo_semaphore_asyncwait_prepare_wait (sem, timeout_ms, (LifoSemaphoreAsyncWaitCallbackFn)success_cb, (LifoSemaphoreAsyncWaitCallbackFn)timedout_cb, user_data);
}

void
Expand Down
64 changes: 32 additions & 32 deletions src/mono/mono/utils/lifo-semaphore.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ mono_lifo_semaphore_timed_wait (LifoSemaphore *semaphore, int32_t timeout_ms)
mono_coop_cond_init (&wait_entry.condition);
mono_coop_mutex_lock (&semaphore->base.mutex);

if (semaphore->pending_signals > 0) {
--semaphore->pending_signals;
if (semaphore->base.pending_signals > 0) {
--semaphore->base.pending_signals;
mono_coop_cond_destroy (&wait_entry.condition);
mono_coop_mutex_unlock (&semaphore->base.mutex);
return 1;
Expand Down Expand Up @@ -88,7 +88,7 @@ mono_lifo_semaphore_release (LifoSemaphore *semaphore, uint32_t count)
mono_coop_cond_signal (&wait_entry->condition);
--count;
} else {
semaphore->pending_signals += count;
semaphore->base.pending_signals += count;
count = 0;
}
}
Expand All @@ -98,21 +98,21 @@ mono_lifo_semaphore_release (LifoSemaphore *semaphore, uint32_t count)

#if defined(HOST_BROWSER) && !defined(DISABLE_THREADS)

LifoJSSemaphore *
mono_lifo_js_semaphore_init (void)
LifoSemaphoreAsyncWait *
mono_lifo_semaphore_asyncwait_init (void)
{
LifoJSSemaphore *sem = g_new0 (LifoJSSemaphore, 1);
LifoSemaphoreAsyncWait *sem = g_new0 (LifoSemaphoreAsyncWait, 1);
if (sem == NULL)
return NULL;
sem->base.kind = LIFO_SEMAPHORE_ASYNC_JS;
sem->base.kind = LIFO_SEMAPHORE_ASYNCWAIT;

mono_coop_mutex_init (&sem->base.mutex);

return sem;
}

void
mono_lifo_js_semaphore_delete (LifoJSSemaphore *sem)
mono_lifo_semaphore_asyncwait_delete (LifoSemaphoreAsyncWait *sem)
{
/* FIXME: this is probably hard to guarantee - in-flight signaled semaphores still have wait entries */
g_assert (sem->head == NULL);
Expand All @@ -134,18 +134,18 @@ lifo_js_wait_entry_on_success (void *wait_entry_as_user_data);


static void
lifo_js_wait_entry_push (LifoJSSemaphoreWaitEntry **head,
LifoJSSemaphoreWaitEntry *entry)
lifo_js_wait_entry_push (LifoSemaphoreAsyncWaitWaitEntry **head,
LifoSemaphoreAsyncWaitWaitEntry *entry)
{
LifoJSSemaphoreWaitEntry *next = *head;
LifoSemaphoreAsyncWaitWaitEntry *next = *head;
*head = entry;
entry->next = next;
next->previous = entry;
}

static void
lifo_js_wait_entry_unlink (LifoJSSemaphoreWaitEntry **head,
LifoJSSemaphoreWaitEntry *entry)
lifo_js_wait_entry_unlink (LifoSemaphoreAsyncWaitWaitEntry **head,
LifoSemaphoreAsyncWaitWaitEntry *entry)
{
if (*head == entry) {
*head = entry->next;
Expand All @@ -159,8 +159,8 @@ lifo_js_wait_entry_unlink (LifoJSSemaphoreWaitEntry **head,
}

/* LOCKING: assumes semaphore is locked */
static LifoJSSemaphoreWaitEntry *
lifo_js_find_waiter (LifoJSSemaphoreWaitEntry *entry)
static LifoSemaphoreAsyncWaitWaitEntry *
lifo_js_find_waiter (LifoSemaphoreAsyncWaitWaitEntry *entry)
{
while (entry) {
if (entry->state == LIFO_JS_WAITING)
Expand All @@ -171,7 +171,7 @@ lifo_js_find_waiter (LifoJSSemaphoreWaitEntry *entry)
}

static gboolean
lifo_js_wait_entry_no_thread (LifoJSSemaphoreWaitEntry *entry,
lifo_js_wait_entry_no_thread (LifoSemaphoreAsyncWaitWaitEntry *entry,
pthread_t cur)
{
while (entry) {
Expand All @@ -183,15 +183,15 @@ lifo_js_wait_entry_no_thread (LifoJSSemaphoreWaitEntry *entry,
}

void
mono_lifo_js_semaphore_prepare_wait (LifoJSSemaphore *sem,
mono_lifo_semaphore_asyncwait_prepare_wait (LifoSemaphoreAsyncWait *sem,
int32_t timeout_ms,
LifoJSSemaphoreCallbackFn success_cb,
LifoJSSemaphoreCallbackFn timeout_cb,
LifoSemaphoreAsyncWaitCallbackFn success_cb,
LifoSemaphoreAsyncWaitCallbackFn timeout_cb,
intptr_t user_data)
{
mono_coop_mutex_lock (&sem->base.mutex);
if (sem->pending_signals > 0) {
sem->pending_signals--;
if (sem->base.pending_signals > 0) {
sem->base.pending_signals--;
mono_coop_mutex_unlock (&sem->base.mutex);
success_cb (sem, user_data); // FIXME: queue microtask
return;
Expand All @@ -205,7 +205,7 @@ mono_lifo_js_semaphore_prepare_wait (LifoJSSemaphore *sem,
*/
g_assert (lifo_js_wait_entry_no_thread(sem->head, cur));

LifoJSSemaphoreWaitEntry *wait_entry = g_new0 (LifoJSSemaphoreWaitEntry, 1);
LifoSemaphoreAsyncWaitWaitEntry *wait_entry = g_new0 (LifoSemaphoreAsyncWaitWaitEntry, 1);
wait_entry->success_cb = success_cb;
wait_entry->timeout_cb = timeout_cb;
wait_entry->sem = sem;
Expand All @@ -220,13 +220,13 @@ mono_lifo_js_semaphore_prepare_wait (LifoJSSemaphore *sem,
}

void
mono_lifo_js_semaphore_release (LifoJSSemaphore *sem,
mono_lifo_semaphore_asyncwait_release (LifoSemaphoreAsyncWait *sem,
uint32_t count)
{
mono_coop_mutex_lock (&sem->base.mutex);

while (count > 0) {
LifoJSSemaphoreWaitEntry *wait_entry = lifo_js_find_waiter (sem->head);
LifoSemaphoreAsyncWaitWaitEntry *wait_entry = lifo_js_find_waiter (sem->head);
if (wait_entry != NULL) {
/* found one. set its status and queue some work to run on the signaled thread */
pthread_t target = wait_entry->thread;
Expand All @@ -238,7 +238,7 @@ mono_lifo_js_semaphore_release (LifoJSSemaphore *sem,
/* if we're on the same thread, don't run the callback while holding the lock */
emscripten_dispatch_to_thread_async (target, EM_FUNC_SIG_VI, lifo_js_wait_entry_on_success, NULL, wait_entry);
} else {
sem->pending_signals += count;
sem->base.pending_signals += count;
count = 0;
}
}
Expand All @@ -249,12 +249,12 @@ mono_lifo_js_semaphore_release (LifoJSSemaphore *sem,
static void
lifo_js_wait_entry_on_timeout (void *wait_entry_as_user_data)
{
LifoJSSemaphoreWaitEntry *wait_entry = (LifoJSSemaphoreWaitEntry *)wait_entry_as_user_data;
g_assert (pthread_equal (wait_entry->thread, pthread_self())); // FIXME: failing here sometimes - thread already exited?
LifoSemaphoreAsyncWaitWaitEntry *wait_entry = (LifoSemaphoreAsyncWaitWaitEntry *)wait_entry_as_user_data;
g_assert (pthread_equal (wait_entry->thread, pthread_self()));
g_assert (wait_entry->sem != NULL);
LifoJSSemaphore *sem = wait_entry->sem;
LifoSemaphoreAsyncWait *sem = wait_entry->sem;
gboolean call_timeout_cb = FALSE;
LifoJSSemaphoreCallbackFn timeout_cb = NULL;
LifoSemaphoreAsyncWaitCallbackFn timeout_cb = NULL;
intptr_t user_data = 0;
mono_coop_mutex_lock (&sem->base.mutex);
switch (wait_entry->state) {
Expand Down Expand Up @@ -288,12 +288,12 @@ lifo_js_wait_entry_on_timeout (void *wait_entry_as_user_data)
static void
lifo_js_wait_entry_on_success (void *wait_entry_as_user_data)
{
LifoJSSemaphoreWaitEntry *wait_entry = (LifoJSSemaphoreWaitEntry *)wait_entry_as_user_data;
LifoSemaphoreAsyncWaitWaitEntry *wait_entry = (LifoSemaphoreAsyncWaitWaitEntry *)wait_entry_as_user_data;
g_assert (pthread_equal (wait_entry->thread, pthread_self()));
g_assert (wait_entry->sem != NULL);
LifoJSSemaphore *sem = wait_entry->sem;
LifoSemaphoreAsyncWait *sem = wait_entry->sem;
gboolean call_success_cb = FALSE;
LifoJSSemaphoreCallbackFn success_cb = NULL;
LifoSemaphoreAsyncWaitCallbackFn success_cb = NULL;
intptr_t user_data = 0;
mono_coop_mutex_lock (&sem->base.mutex);
switch (wait_entry->state) {
Expand Down
41 changes: 20 additions & 21 deletions src/mono/mono/utils/lifo-semaphore.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ typedef struct _LifoSemaphoreBase LifoSemaphoreBase;
struct _LifoSemaphoreBase
{
MonoCoopMutex mutex;
uint32_t pending_signals;
uint8_t kind;
};

enum {
LIFO_SEMAPHORE_NORMAL = 1,
#if defined(HOST_BROWSER) && !defined(DISABLE_THREADS)
LIFO_SEMAPHORE_ASYNC_JS,
LIFO_SEMAPHORE_ASYNCWAIT,
#endif
};

Expand All @@ -31,7 +32,6 @@ struct _LifoSemaphoreWaitEntry {
struct _LifoSemaphore {
LifoSemaphoreBase base;
LifoSemaphoreWaitEntry *head;
uint32_t pending_signals;
};

LifoSemaphore *
Expand All @@ -53,22 +53,22 @@ mono_lifo_semaphore_release (LifoSemaphore *semaphore, uint32_t count);
* timeout callback. The wait function returns immediately and the callbacks will fire on the JS
* event loop when the semaphore is released or the timeout expires.
*/
typedef struct _LifoJSSemaphore LifoJSSemaphore;
typedef struct _LifoSemaphoreAsyncWait LifoSemaphoreAsyncWait;
/*
* Because the callbacks are asynchronous, it's possible for the same thread to attempt to wait
* multiple times for the same semaphore. For simplicity of reasoning, we dissallow that and
* assert. In principle we could support it, but we haven't implemented that.
*/
typedef struct _LifoJSSemaphoreWaitEntry LifoJSSemaphoreWaitEntry;
typedef struct _LifoSemaphoreAsyncWaitWaitEntry LifoSemaphoreAsyncWaitWaitEntry;

typedef void (*LifoJSSemaphoreCallbackFn)(LifoJSSemaphore *semaphore, intptr_t user_data);
typedef void (*LifoSemaphoreAsyncWaitCallbackFn)(LifoSemaphoreAsyncWait *semaphore, intptr_t user_data);

struct _LifoJSSemaphoreWaitEntry {
LifoJSSemaphoreWaitEntry *previous;
LifoJSSemaphoreWaitEntry *next;
LifoJSSemaphoreCallbackFn success_cb;
LifoJSSemaphoreCallbackFn timeout_cb;
LifoJSSemaphore *sem;
struct _LifoSemaphoreAsyncWaitWaitEntry {
LifoSemaphoreAsyncWaitWaitEntry *previous;
LifoSemaphoreAsyncWaitWaitEntry *next;
LifoSemaphoreAsyncWaitCallbackFn success_cb;
LifoSemaphoreAsyncWaitCallbackFn timeout_cb;
LifoSemaphoreAsyncWait *sem;
intptr_t user_data;
pthread_t thread;
int32_t js_timeout_id; // only valid to access from the waiting thread
Expand All @@ -77,20 +77,19 @@ struct _LifoJSSemaphoreWaitEntry {
uint16_t refcount; /* 1 if waiting, 2 if signaled, 1 if timeout fired while signaled and we're ignoring the timeout */
};

struct _LifoJSSemaphore {
struct _LifoSemaphoreAsyncWait {
LifoSemaphoreBase base;
LifoJSSemaphoreWaitEntry *head;
uint32_t pending_signals;
LifoSemaphoreAsyncWaitWaitEntry *head;
};

LifoJSSemaphore *
mono_lifo_js_semaphore_init (void);
LifoSemaphoreAsyncWait *
mono_lifo_semaphore_asyncwait_init (void);

/* what to do with waiters?
* might be kind of academic - we don't expect to destroy these
*/
void
mono_lifo_js_semaphore_delete (LifoJSSemaphore *semaphore);
mono_lifo_semaphore_asyncwait_delete (LifoSemaphoreAsyncWait *semaphore);

/*
* the timeout_cb is triggered by a JS setTimeout callback
Expand Down Expand Up @@ -127,13 +126,13 @@ mono_lifo_js_semaphore_delete (LifoJSSemaphore *semaphore);
* popped when the timeout runs. But emscripten_clear_timeout doesn't pop - we need to pop ourselves
*/
void
mono_lifo_js_semaphore_prepare_wait (LifoJSSemaphore *semaphore, int32_t timeout_ms,
LifoJSSemaphoreCallbackFn success_cb,
LifoJSSemaphoreCallbackFn timeout_cb,
mono_lifo_semaphore_asyncwait_prepare_wait (LifoSemaphoreAsyncWait *semaphore, int32_t timeout_ms,
LifoSemaphoreAsyncWaitCallbackFn success_cb,
LifoSemaphoreAsyncWaitCallbackFn timeout_cb,
intptr_t user_data);

void
mono_lifo_js_semaphore_release (LifoJSSemaphore *semaphore, uint32_t count);
mono_lifo_semaphore_asyncwait_release (LifoSemaphoreAsyncWait *semaphore, uint32_t count);

#endif /* HOST_BROWSER && !DISABLE_THREADS */

Expand Down