@@ -389,7 +389,7 @@ int emscripten_proxy_sync_with_ctx(em_proxying_queue* q,
389389}
390390
391391// Helper for signaling the end of the task after the user function returns.
392- static void call_then_finish_sync (em_proxying_ctx * ctx , void * arg ) {
392+ static void call_then_finish_task (em_proxying_ctx * ctx , void * arg ) {
393393 task * t = arg ;
394394 t -> func (t -> arg );
395395 emscripten_proxy_finish (ctx );
@@ -401,7 +401,7 @@ int emscripten_proxy_sync(em_proxying_queue* q,
401401 void * arg ) {
402402 task t = {.func = func , .arg = arg };
403403 return emscripten_proxy_sync_with_ctx (
404- q , target_thread , call_then_finish_sync , & t );
404+ q , target_thread , call_then_finish_task , & t );
405405}
406406
407407static int do_proxy_callback (em_proxying_queue * q ,
@@ -465,7 +465,8 @@ int emscripten_proxy_callback(em_proxying_queue* q,
465465 void (* callback )(void * ),
466466 void (* cancel )(void * ),
467467 void * arg ) {
468- // Allocate the em_proxying_ctx and the user ctx as a single block.
468+ // Allocate the em_proxying_ctx and the user ctx as a single block that will
469+ // be freed when the `em_proxying_ctx` is freed.
469470 struct block {
470471 em_proxying_ctx ctx ;
471472 callback_ctx cb_ctx ;
@@ -483,3 +484,99 @@ int emscripten_proxy_callback(em_proxying_queue* q,
483484 & block -> cb_ctx ,
484485 & block -> ctx );
485486}
487+
488+ typedef struct promise_ctx {
489+ void (* func )(em_proxying_ctx * , void * );
490+ void * arg ;
491+ em_promise_t promise ;
492+ } promise_ctx ;
493+
494+ static void promise_call (em_proxying_ctx * ctx , void * arg ) {
495+ promise_ctx * promise_ctx = arg ;
496+ promise_ctx -> func (ctx , promise_ctx -> arg );
497+ }
498+
499+ static void promise_fulfill (void * arg ) {
500+ promise_ctx * promise_ctx = arg ;
501+ emscripten_promise_resolve (promise_ctx -> promise , EM_PROMISE_FULFILL , NULL );
502+ emscripten_promise_destroy (promise_ctx -> promise );
503+ }
504+
505+ static void promise_reject (void * arg ) {
506+ promise_ctx * promise_ctx = arg ;
507+ emscripten_promise_resolve (promise_ctx -> promise , EM_PROMISE_REJECT , NULL );
508+ emscripten_promise_destroy (promise_ctx -> promise );
509+ }
510+
511+ static em_promise_t do_proxy_promise (em_proxying_queue * q ,
512+ pthread_t target_thread ,
513+ void (* func )(em_proxying_ctx * , void * ),
514+ void * arg ,
515+ em_promise_t promise ,
516+ em_proxying_ctx * ctx ,
517+ promise_ctx * promise_ctx ) {
518+ * promise_ctx = (struct promise_ctx ){func , arg , promise };
519+ if (!do_proxy_callback (q ,
520+ target_thread ,
521+ promise_call ,
522+ promise_fulfill ,
523+ promise_reject ,
524+ promise_ctx ,
525+ ctx )) {
526+ emscripten_promise_resolve (promise , EM_PROMISE_REJECT , NULL );
527+ return promise ;
528+ }
529+ // Return a separate promise to ensure that the internal promise will stay
530+ // alive until the callbacks are called.
531+ em_promise_t ret = emscripten_promise_create ();
532+ emscripten_promise_resolve (ret , EM_PROMISE_MATCH , promise );
533+ return ret ;
534+ }
535+
536+ em_promise_t emscripten_proxy_promise_with_ctx (em_proxying_queue * q ,
537+ pthread_t target_thread ,
538+ void (* func )(em_proxying_ctx * ,
539+ void * ),
540+ void * arg ) {
541+ em_promise_t promise = emscripten_promise_create ();
542+ // Allocate the em_proxying_ctx and promise ctx as a single block that will be
543+ // freed when the `em_proxying_ctx` is freed.
544+ struct block {
545+ em_proxying_ctx ctx ;
546+ promise_ctx promise_ctx ;
547+ };
548+ struct block * block = malloc (sizeof (* block ));
549+ if (block == NULL ) {
550+ emscripten_promise_resolve (promise , EM_PROMISE_REJECT , NULL );
551+ return promise ;
552+ }
553+ return do_proxy_promise (
554+ q , target_thread , func , arg , promise , & block -> ctx , & block -> promise_ctx );
555+ }
556+
557+ em_promise_t emscripten_proxy_promise (em_proxying_queue * q ,
558+ pthread_t target_thread ,
559+ void (* func )(void * ),
560+ void * arg ) {
561+ em_promise_t promise = emscripten_promise_create ();
562+ // Allocate the em_proxying_ctx, promise ctx, and user task as a single block
563+ // that will be freed when the `em_proxying_ctx` is freed.
564+ struct block {
565+ em_proxying_ctx ctx ;
566+ promise_ctx promise_ctx ;
567+ task task ;
568+ };
569+ struct block * block = malloc (sizeof (* block ));
570+ if (block == NULL ) {
571+ emscripten_promise_resolve (promise , EM_PROMISE_REJECT , NULL );
572+ return promise ;
573+ }
574+ block -> task = (task ){.func = func , .arg = arg };
575+ return do_proxy_promise (q ,
576+ target_thread ,
577+ call_then_finish_task ,
578+ & block -> task ,
579+ promise ,
580+ & block -> ctx ,
581+ & block -> promise_ctx );
582+ }
0 commit comments