Skip to content

Commit f4a1fce

Browse files
authored
Convert JS function proxying to use new proxying API. NFC (#19947)
1 parent 8bb1d1b commit f4a1fce

13 files changed

+95
-70
lines changed

emcc.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,6 @@ def setup_pthreads(target):
17061706

17071707
# Functions needs to be exported from the module since they are used in worker.js
17081708
settings.REQUIRED_EXPORTS += [
1709-
'emscripten_dispatch_to_thread_',
17101709
'_emscripten_thread_free_data',
17111710
'emscripten_main_runtime_thread_id',
17121711
'emscripten_main_thread_process_queued_calls',

src/generated_struct_info32.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@
230230
"EM_PROMISE_MATCH_RELEASE": 2,
231231
"EM_PROMISE_REJECT": 3,
232232
"EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424,
233-
"EM_QUEUED_JS_CALL_MAX_ARGS": 20,
234233
"EM_TIMING_RAF": 1,
235234
"EM_TIMING_SETIMMEDIATE": 2,
236235
"EM_TIMING_SETTIMEOUT": 0,

src/generated_struct_info64.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@
230230
"EM_PROMISE_MATCH_RELEASE": 2,
231231
"EM_PROMISE_REJECT": 3,
232232
"EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424,
233-
"EM_QUEUED_JS_CALL_MAX_ARGS": 20,
234233
"EM_TIMING_RAF": 1,
235234
"EM_TIMING_SETIMMEDIATE": 2,
236235
"EM_TIMING_SETTIMEOUT": 0,

src/library_html5.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
*/
66

77
var LibraryHTML5 = {
8-
$JSEvents__deps: ['$withStackSave'],
8+
$JSEvents__deps: ['$withStackSave',
9+
#if PTHREADS
10+
'emscripten_dispatch_to_thread_',
11+
#endif
12+
],
913
$JSEvents: {
1014

1115
/* We do not depend on the exact initial values of falsey member fields - these fields can be populated on-demand

src/library_pthread.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -965,12 +965,6 @@ var LibraryPThread = {
965965
// We also pass 'sync' to C separately, since C needs to look at it.
966966
var numCallArgs = arguments.length - 2;
967967
var outerArgs = arguments;
968-
#if ASSERTIONS
969-
var maxArgs = {{{ cDefs.EM_QUEUED_JS_CALL_MAX_ARGS - 1 }}};
970-
if (numCallArgs > maxArgs) {
971-
throw 'proxyToMainThread: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + maxArgs;
972-
}
973-
#endif
974968
// Allocate a buffer, which will be copied by the C code.
975969
return withStackSave(() => {
976970
// First passed parameter specifies the number of arguments to the function.

src/struct_info_internal.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@
2424
"SIGCANCEL"
2525
]
2626
},
27-
{
28-
"file": "threading_internal.h",
29-
"defines": [
30-
"EM_QUEUED_JS_CALL_MAX_ARGS"
31-
]
32-
},
3327
{
3428
"file": "dynlink.h",
3529
"structs": {

system/include/emscripten/threading_legacy.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ typedef struct em_queued_call em_queued_call;
2727
// in the future. Do not depend on the exact numbers in this scheme.
2828
#define EM_FUNC_SIGNATURE unsigned int
2929

30+
// Proxied JS function can support a few more arguments than proxied C/C++
31+
// functions, because the dispatch is variadic and signature independent.
32+
#define EM_QUEUED_JS_CALL_MAX_ARGS 20
33+
3034
// The encoding scheme is as follows:
3135
// - highest three bits identify the type of the return value
3236
#define EM_FUNC_SIG_RETURN_VALUE_MASK (0x7U << 29)
@@ -115,7 +119,6 @@ typedef struct em_queued_call em_queued_call;
115119
#define EM_PROXIED_FUNC_SPECIAL(x) (EM_FUNC_SIG_SPECIAL_INTERNAL | ((x) << 20))
116120

117121
#define EM_PROXIED_RESIZE_OFFSCREENCANVAS (EM_PROXIED_FUNC_SPECIAL(0) | EM_FUNC_SIG_IIII)
118-
#define EM_PROXIED_JS_FUNCTION (EM_PROXIED_FUNC_SPECIAL(1) | EM_FUNC_SIG_D)
119122

120123
// Runs the given function synchronously on the main Emscripten runtime thread.
121124
// If this thread is the main thread, the operation is immediately performed,

system/lib/pthread/proxying.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
#include <emscripten/threading.h>
1111
#include <pthread.h>
1212
#include <stdatomic.h>
13+
#include <stdbool.h>
1314
#include <stdlib.h>
1415
#include <string.h>
1516

1617
#include "em_task_queue.h"
1718
#include "thread_mailbox.h"
19+
#include "threading_internal.h"
1820

1921
struct em_proxying_queue {
2022
// Protects all accesses to em_task_queues, size, and capacity.
@@ -580,3 +582,60 @@ em_promise_t emscripten_proxy_promise(em_proxying_queue* q,
580582
&block->ctx,
581583
&block->promise_ctx);
582584
}
585+
586+
typedef struct proxied_js_func_t {
587+
int funcIndex;
588+
pthread_t callingThread;
589+
int numArgs;
590+
double* argBuffer;
591+
double result;
592+
bool owned;
593+
} proxied_js_func_t;
594+
595+
static void run_js_func(void* arg) {
596+
proxied_js_func_t* f = (proxied_js_func_t*)arg;
597+
f->result = _emscripten_receive_on_main_thread_js(
598+
f->funcIndex, f->callingThread, f->numArgs, f->argBuffer);
599+
if (f->owned) {
600+
free(f->argBuffer);
601+
free(f);
602+
}
603+
}
604+
605+
double _emscripten_run_on_main_thread_js(int index,
606+
int num_args,
607+
double* buffer,
608+
int sync) {
609+
proxied_js_func_t f = {
610+
.funcIndex = index,
611+
.callingThread = pthread_self(),
612+
.numArgs = num_args,
613+
.argBuffer = buffer,
614+
.owned = false,
615+
};
616+
617+
em_proxying_queue* q = emscripten_proxy_get_system_queue();
618+
pthread_t target = emscripten_main_runtime_thread_id();
619+
620+
if (sync) {
621+
if (!emscripten_proxy_sync(q, target, run_js_func, &f)) {
622+
assert(false && "emscripten_proxy_sync failed");
623+
return 0;
624+
}
625+
return f.result;
626+
}
627+
628+
// Make a heap-heap allocated copy of the proxied_js_func_t
629+
proxied_js_func_t* arg = malloc(sizeof(proxied_js_func_t));
630+
*arg = f;
631+
arg->owned = true;
632+
633+
// Also make a copyh of the argBuffer.
634+
arg->argBuffer = malloc(num_args*sizeof(double));
635+
memcpy(arg->argBuffer, buffer, num_args*sizeof(double));
636+
637+
if (!emscripten_proxy_async(q, target, run_js_func, arg)) {
638+
assert(false && "emscripten_proxy_async failed");
639+
}
640+
return 0;
641+
}

system/lib/pthread/proxying_legacy.c

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,6 @@ static void _do_call(void* arg) {
153153
q->returnValue.i =
154154
_emscripten_set_offscreencanvas_size(q->args[0].cp, q->args[1].i, q->args[2].i);
155155
break;
156-
case EM_PROXIED_JS_FUNCTION:
157-
q->returnValue.d =
158-
_emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d);
159-
break;
160156
case EM_FUNC_SIG_V:
161157
((em_func_v)q->functionPtr)();
162158
break;
@@ -413,44 +409,6 @@ int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* fun
413409
return q.returnValue.i;
414410
}
415411

416-
double _emscripten_run_on_main_thread_js(int index, int num_args, int64_t* buffer, int sync) {
417-
em_queued_call q;
418-
em_queued_call *c;
419-
if (sync) {
420-
q.operationDone = 0;
421-
q.satelliteData = 0;
422-
c = &q;
423-
} else {
424-
c = em_queued_call_malloc();
425-
}
426-
c->calleeDelete = !sync;
427-
c->functionEnum = EM_PROXIED_JS_FUNCTION;
428-
// Index not needed to ever be more than 32-bit.
429-
c->functionPtr = (void*)(intptr_t)index;
430-
c->callingThread = pthread_self();
431-
assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS);
432-
// The types are only known at runtime in these calls, so we store values that
433-
// must be able to contain any valid JS value, including a 64-bit BigInt if
434-
// BigInt support is enabled. We store to an i64, which can contain both a
435-
// BigInt and a JS Number which is a 64-bit double.
436-
c->args[0].i = num_args;
437-
for (int i = 0; i < num_args; i++) {
438-
c->args[i+1].i64 = buffer[i];
439-
}
440-
441-
if (sync) {
442-
sync_run_in_main_thread(&q);
443-
// TODO: support BigInt return values somehow.
444-
return q.returnValue.d;
445-
} else {
446-
// 'async' runs are fire and forget, where the caller detaches itself from the call object after
447-
// returning here, and it is the callee's responsibility to free up the memory after the call
448-
// has been performed.
449-
emscripten_async_run_in_main_thread(c);
450-
return 0;
451-
}
452-
}
453-
454412
void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
455413
em_queued_call* q = em_queued_call_malloc();
456414
if (!q)

system/lib/pthread/threading_internal.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99

1010
#include <pthread.h>
1111

12-
// Proxied JS function can support a few more arguments than proxied C/C++
13-
// functions, because the dispatch is variadic and signature independent.
14-
#define EM_QUEUED_JS_CALL_MAX_ARGS 20
15-
1612
#define EM_THREAD_NAME_MAX 32
1713

1814
#define EM_THREAD_STATUS int

0 commit comments

Comments
 (0)