Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/pthread/proxying_legacy.c
6174 views
1
/*
2
* Copyright 2023 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*/
7
#include <assert.h>
8
#include <math.h>
9
#include <stdatomic.h>
10
11
#include <emscripten/threading.h>
12
#include <emscripten/console.h>
13
14
#include "../internal/pthread_impl.h"
15
16
#include "threading_internal.h"
17
#include "emscripten_internal.h"
18
19
typedef union em_variant_val {
20
int i;
21
int64_t j;
22
float f;
23
double d;
24
void *vp;
25
char *cp;
26
} em_variant_val;
27
28
typedef struct em_queued_call {
29
int functionEnum;
30
void *functionPtr;
31
_Atomic uint32_t operationDone;
32
em_variant_val args[EM_QUEUED_JS_CALL_MAX_ARGS];
33
em_variant_val returnValue;
34
35
// Sets the PThread.currentProxiedOperationCallerThread global for the
36
// duration of the proxied call.
37
pthread_t callingThread;
38
39
// An optional pointer to a secondary data block that should be free()d when
40
// this queued call is freed.
41
void *satelliteData;
42
43
// If true, the caller has "detached" itself from this call object and the
44
// Emscripten main runtime thread should free up this em_queued_call object
45
// after it has been executed. If false, the caller is in control of the
46
// memory.
47
int calleeDelete;
48
} em_queued_call;
49
50
// Proxied C/C++ functions support at most this many arguments. Dispatch is
51
// static/strongly typed by signature.
52
#define EM_QUEUED_CALL_MAX_ARGS 11
53
54
typedef void (*em_func_v)(void);
55
typedef void (*em_func_vi)(int);
56
typedef void (*em_func_vf)(float);
57
typedef void (*em_func_vii)(int, int);
58
typedef void (*em_func_vif)(int, float);
59
typedef void (*em_func_vff)(float, float);
60
typedef void (*em_func_viii)(int, int, int);
61
typedef void (*em_func_viij)(int, int, uint64_t);
62
typedef void (*em_func_viif)(int, int, float);
63
typedef void (*em_func_viff)(int, float, float);
64
typedef void (*em_func_vfff)(float, float, float);
65
typedef void (*em_func_viiii)(int, int, int, int);
66
typedef void (*em_func_viifi)(int, int, float, int);
67
typedef void (*em_func_vifff)(int, float, float, float);
68
typedef void (*em_func_vffff)(float, float, float, float);
69
typedef void (*em_func_viiiii)(int, int, int, int, int);
70
typedef void (*em_func_viffff)(int, float, float, float, float);
71
typedef void (*em_func_viiiiii)(int, int, int, int, int, int);
72
typedef void (*em_func_viiiiiii)(int, int, int, int, int, int, int);
73
typedef void (*em_func_viiiiiiii)(int, int, int, int, int, int, int, int);
74
typedef void (*em_func_viiiiiiiii)(int, int, int, int, int, int, int, int, int);
75
typedef void (*em_func_viiiiiiiiii)(int, int, int, int, int, int, int, int, int, int);
76
typedef void (*em_func_viiiiiiiiiii)(int, int, int, int, int, int, int, int, int, int, int);
77
typedef int (*em_func_i)(void);
78
typedef int (*em_func_ii)(int);
79
typedef int (*em_func_iii)(int, int);
80
typedef int (*em_func_iiij)(int, int, uint64_t);
81
typedef int (*em_func_iiii)(int, int, int);
82
typedef int (*em_func_iiiii)(int, int, int, int);
83
typedef int (*em_func_iiiiii)(int, int, int, int, int);
84
typedef int (*em_func_iiiiiii)(int, int, int, int, int, int);
85
typedef int (*em_func_iiiiiiii)(int, int, int, int, int, int, int);
86
typedef int (*em_func_iiiiiiiii)(int, int, int, int, int, int, int, int);
87
typedef int (*em_func_iiiiiiiiii)(int, int, int, int, int, int, int, int, int);
88
89
#ifdef __wasm64__
90
typedef int (*em_func_ij)(uint64_t);
91
typedef uint64_t (*em_func_ji)(int);
92
typedef int (*em_func_ijj)(uint64_t, uint64_t);
93
typedef int (*em_func_iij)(int, uint64_t);
94
typedef int (*em_func_iijj)(int, uint64_t, uint64_t);
95
typedef uint64_t (*em_func_jjj)(uint64_t, uint64_t);
96
typedef void (*em_func_vij)(int, uint64_t);
97
typedef void (*em_func_viji)(int, uint64_t, int);
98
typedef void (*em_func_vijji)(int, uint64_t, uint64_t, int);
99
typedef void (*em_func_viijj)(int, int, uint64_t, uint64_t);
100
typedef void (*em_func_viiij)(int, int, int, uint64_t);
101
typedef void (*em_func_viiiiij)(int, int, int, int, int, uint64_t);
102
typedef void (*em_func_viiiiiij)(int, int, int, int, int, int, uint64_t);
103
typedef void (*em_func_viiiiiiiij)(int, int, int, int, int, int, int, int, uint64_t);
104
#endif
105
106
// Allocator and deallocator for em_queued_call objects.
107
static em_queued_call* em_queued_call_malloc() {
108
em_queued_call* call = (em_queued_call*)malloc(sizeof(em_queued_call));
109
assert(call); // Not a programming error, but use assert() in debug builds to catch OOM scenarios.
110
if (call) {
111
call->operationDone = 0;
112
call->functionPtr = 0;
113
call->satelliteData = 0;
114
}
115
return call;
116
}
117
118
static void em_queued_call_free(em_queued_call* call) {
119
if (call)
120
free(call->satelliteData);
121
free(call);
122
}
123
124
static void init_em_queued_call_args(em_queued_call* q,
125
EM_FUNC_SIGNATURE sig,
126
va_list args) {
127
EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK;
128
int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig);
129
for (int i = 0; i < numArguments; ++i) {
130
switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) {
131
case EM_FUNC_SIG_PARAM_I:
132
q->args[i].i = va_arg(args, int);
133
break;
134
case EM_FUNC_SIG_PARAM_J:
135
q->args[i].j = va_arg(args, int64_t);
136
break;
137
case EM_FUNC_SIG_PARAM_F:
138
q->args[i].f = (float)va_arg(args, double);
139
break;
140
case EM_FUNC_SIG_PARAM_D:
141
q->args[i].d = va_arg(args, double);
142
break;
143
default:
144
assert(false && "unknown proxy param type");
145
}
146
argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT;
147
}
148
}
149
150
static em_queued_call* em_queued_call_create(EM_FUNC_SIGNATURE sig,
151
void* func,
152
void* satellite,
153
va_list args) {
154
em_queued_call* call = em_queued_call_malloc();
155
if (call) {
156
call->functionEnum = sig;
157
call->functionPtr = func;
158
call->satelliteData = satellite;
159
init_em_queued_call_args(call, sig, args);
160
}
161
return call;
162
}
163
164
void emscripten_async_waitable_close(em_queued_call* call) {
165
assert(call->operationDone);
166
em_queued_call_free(call);
167
}
168
169
static void _do_call(void* arg) {
170
em_queued_call* q = (em_queued_call*)arg;
171
// C function pointer
172
assert(EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(q->functionEnum) <= EM_QUEUED_CALL_MAX_ARGS);
173
switch (q->functionEnum) {
174
case EM_FUNC_SIG_V:
175
((em_func_v)q->functionPtr)();
176
break;
177
case EM_FUNC_SIG_VI:
178
((em_func_vi)q->functionPtr)(q->args[0].i);
179
break;
180
case EM_FUNC_SIG_VF:
181
((em_func_vf)q->functionPtr)(q->args[0].f);
182
break;
183
case EM_FUNC_SIG_VII:
184
((em_func_vii)q->functionPtr)(q->args[0].i, q->args[1].i);
185
break;
186
case EM_FUNC_SIG_VIF:
187
((em_func_vif)q->functionPtr)(q->args[0].i, q->args[1].f);
188
break;
189
case EM_FUNC_SIG_VFF:
190
((em_func_vff)q->functionPtr)(q->args[0].f, q->args[1].f);
191
break;
192
case EM_FUNC_SIG_VIII:
193
((em_func_viii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i);
194
break;
195
case EM_FUNC_SIG_VIIJ:
196
((em_func_viij)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].j);
197
break;
198
case EM_FUNC_SIG_VIIF:
199
((em_func_viif)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f);
200
break;
201
case EM_FUNC_SIG_VIFF:
202
((em_func_viff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f);
203
break;
204
case EM_FUNC_SIG_VFFF:
205
((em_func_vfff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f);
206
break;
207
case EM_FUNC_SIG_VIIII:
208
((em_func_viiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i);
209
break;
210
case EM_FUNC_SIG_VIIFI:
211
((em_func_viifi)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f, q->args[3].i);
212
break;
213
case EM_FUNC_SIG_VIFFF:
214
((em_func_vifff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f);
215
break;
216
case EM_FUNC_SIG_VFFFF:
217
((em_func_vffff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f, q->args[3].f);
218
break;
219
case EM_FUNC_SIG_VIIIII:
220
((em_func_viiiii)q->functionPtr)(
221
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i);
222
break;
223
case EM_FUNC_SIG_VIFFFF:
224
((em_func_viffff)q->functionPtr)(
225
q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f, q->args[4].f);
226
break;
227
case EM_FUNC_SIG_VIIIIII:
228
((em_func_viiiiii)q->functionPtr)(
229
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i);
230
break;
231
case EM_FUNC_SIG_VIIIIIII:
232
((em_func_viiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
233
q->args[4].i, q->args[5].i, q->args[6].i);
234
break;
235
case EM_FUNC_SIG_VIIIIIIII:
236
((em_func_viiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
237
q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i);
238
break;
239
case EM_FUNC_SIG_VIIIIIIIII:
240
((em_func_viiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
241
q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i);
242
break;
243
case EM_FUNC_SIG_VIIIIIIIIII:
244
((em_func_viiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
245
q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i,
246
q->args[9].i);
247
break;
248
case EM_FUNC_SIG_VIIIIIIIIIII:
249
((em_func_viiiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
250
q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i,
251
q->args[9].i, q->args[10].i);
252
break;
253
#ifdef __wasm64__
254
case EM_FUNC_SIG_IP:
255
q->returnValue.i = ((em_func_ij)q->functionPtr)(q->args[0].j);
256
break;
257
case EM_FUNC_SIG_IIPP:
258
q->returnValue.i = ((em_func_iijj)q->functionPtr)(q->args[0].i, q->args[1].j, q->args[2].j);
259
break;
260
case EM_FUNC_SIG_PI:
261
q->returnValue.j = ((em_func_ji)q->functionPtr)(q->args[0].i);
262
break;
263
case EM_FUNC_SIG_IIP:
264
q->returnValue.i = ((em_func_iij)q->functionPtr)(q->args[0].i, q->args[1].j);
265
break;
266
case EM_FUNC_SIG_PPP:
267
q->returnValue.j = ((em_func_jjj)q->functionPtr)(q->args[0].j, q->args[1].j);
268
break;
269
case EM_FUNC_SIG_VIP:
270
((em_func_vij)q->functionPtr)(q->args[0].i, q->args[1].j);
271
break;
272
case EM_FUNC_SIG_VIIPP:
273
((em_func_viijj)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].j, q->args[3].j);
274
break;
275
case EM_FUNC_SIG_VIIIP:
276
((em_func_viiij)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].j);
277
break;
278
case EM_FUNC_SIG_VIPPI:
279
((em_func_vijji)q->functionPtr)(q->args[0].i, q->args[1].j, q->args[2].j, q->args[3].i);
280
break;
281
case EM_FUNC_SIG_VIPI:
282
((em_func_viji)q->functionPtr)(q->args[0].i, q->args[1].j, q->args[3].i);
283
break;
284
case EM_FUNC_SIG_VIIIIIP:
285
((em_func_viiiiij)q->functionPtr)(
286
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].j);
287
break;
288
case EM_FUNC_SIG_VIIIIIIP:
289
((em_func_viiiiiij)q->functionPtr)(
290
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].j);
291
break;
292
case EM_FUNC_SIG_VIIIIIIIIP:
293
((em_func_viiiiiiiij)q->functionPtr)(
294
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].j);
295
break;
296
#endif
297
case EM_FUNC_SIG_I:
298
q->returnValue.i = ((em_func_i)q->functionPtr)();
299
break;
300
case EM_FUNC_SIG_II:
301
q->returnValue.i = ((em_func_ii)q->functionPtr)(q->args[0].i);
302
break;
303
case EM_FUNC_SIG_III:
304
q->returnValue.i = ((em_func_iii)q->functionPtr)(q->args[0].i, q->args[1].i);
305
break;
306
case EM_FUNC_SIG_IIII:
307
q->returnValue.i = ((em_func_iiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i);
308
break;
309
case EM_FUNC_SIG_IIIJ:
310
q->returnValue.i = ((em_func_iiij)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].j);
311
break;
312
case EM_FUNC_SIG_IIIII:
313
q->returnValue.i =
314
((em_func_iiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i);
315
break;
316
case EM_FUNC_SIG_IIIIII:
317
q->returnValue.i = ((em_func_iiiiii)q->functionPtr)(
318
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i);
319
break;
320
case EM_FUNC_SIG_IIIIIII:
321
q->returnValue.i = ((em_func_iiiiiii)q->functionPtr)(
322
q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i);
323
break;
324
case EM_FUNC_SIG_IIIIIIII:
325
q->returnValue.i = ((em_func_iiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i,
326
q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i);
327
break;
328
case EM_FUNC_SIG_IIIIIIIII:
329
q->returnValue.i = ((em_func_iiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i,
330
q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i);
331
break;
332
case EM_FUNC_SIG_IIIIIIIIII:
333
q->returnValue.i =
334
((em_func_iiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
335
q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i);
336
break;
337
default:
338
assert(0 && "Invalid Emscripten pthread _do_call opcode!");
339
}
340
341
// If the caller is detached from this operation, it is the main thread's responsibility to free
342
// up the call object.
343
if (q->calleeDelete) {
344
em_queued_call_free(q);
345
// No need to wake a listener, nothing is listening to this since the call object is detached.
346
} else {
347
// The caller owns this call object, it is listening to it and will free it up.
348
q->operationDone = 1;
349
emscripten_futex_wake(&q->operationDone, INT_MAX);
350
}
351
}
352
353
static pthread_t normalize_thread(pthread_t target_thread) {
354
assert(target_thread);
355
if (target_thread == EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD) {
356
return emscripten_main_runtime_thread_id();
357
}
358
if (target_thread == EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) {
359
return pthread_self();
360
}
361
return target_thread;
362
}
363
364
// Execute `call` and return 1 only if already on the `target_thread`. Otherwise
365
// return 0.
366
static int maybe_call_on_current_thread(pthread_t target_thread,
367
em_queued_call* call) {
368
if (pthread_equal(target_thread, pthread_self())) {
369
_do_call(call);
370
return 1;
371
}
372
return 0;
373
}
374
375
// Execute or proxy `call`. Return 1 if the work was executed or otherwise
376
// return 0.
377
static int do_dispatch_to_thread(pthread_t target_thread,
378
em_queued_call* call) {
379
target_thread = normalize_thread(target_thread);
380
if (maybe_call_on_current_thread(target_thread, call)) {
381
return 1;
382
}
383
emscripten_proxy_async(
384
emscripten_proxy_get_system_queue(), target_thread, _do_call, call);
385
return 0;
386
}
387
388
int emscripten_dispatch_to_thread_args(pthread_t target_thread,
389
EM_FUNC_SIGNATURE sig,
390
void* func_ptr,
391
void* satellite,
392
va_list args) {
393
em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args);
394
assert(q);
395
// TODO: handle errors in a better way, this pattern appears in several places
396
// in this file. The current behavior makes the calling thread hang as
397
// it waits (for synchronous calls).
398
// If we failed to allocate, return 0 which means we did not execute anything
399
// (we also never will in that case).
400
if (!q)
401
return 0;
402
403
// `q` will not be used after it is called, so let the call clean it up.
404
q->calleeDelete = 1;
405
return do_dispatch_to_thread(target_thread, q);
406
}
407
408
void emscripten_async_run_in_main_thread(em_queued_call* call) {
409
do_dispatch_to_thread(emscripten_main_runtime_thread_id(), call);
410
}
411
412
int emscripten_dispatch_to_thread_(pthread_t target_thread,
413
EM_FUNC_SIGNATURE sig,
414
void* func_ptr,
415
void* satellite,
416
...) {
417
va_list args;
418
va_start(args, satellite);
419
int ret = emscripten_dispatch_to_thread_args(
420
target_thread, sig, func_ptr, satellite, args);
421
va_end(args);
422
return ret;
423
}
424
425
int emscripten_dispatch_to_thread_async_args(pthread_t target_thread,
426
EM_FUNC_SIGNATURE sig,
427
void* func_ptr,
428
void* satellite,
429
va_list args) {
430
// Check if we are already on the target thread.
431
if (pthread_equal(target_thread, pthread_self())) {
432
// Setup is the same as in emscripten_dispatch_to_thread_args.
433
em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args);
434
assert(q);
435
if (!q)
436
return 0;
437
q->calleeDelete = 1;
438
439
// Schedule the call to run later on this thread.
440
emscripten_set_timeout(_do_call, 0, q);
441
return 0;
442
}
443
444
// Otherwise, dispatch as usual.
445
return emscripten_dispatch_to_thread_args(
446
target_thread, sig, func_ptr, satellite, args);
447
}
448
449
int emscripten_dispatch_to_thread_async_(pthread_t target_thread,
450
EM_FUNC_SIGNATURE sig,
451
void* func_ptr,
452
void* satellite,
453
...) {
454
va_list args;
455
va_start(args, satellite);
456
int ret = emscripten_dispatch_to_thread_async_args(
457
target_thread, sig, func_ptr, satellite, args);
458
va_end(args);
459
return ret;
460
}
461
462
static void sync_run_in_main_thread(em_queued_call* call) {
463
emscripten_async_run_in_main_thread(call);
464
465
// Enter to wait for the operation to complete.
466
emscripten_wait_for_call_v(call, INFINITY);
467
}
468
469
int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
470
em_queued_call q = {sig, func_ptr};
471
472
va_list args;
473
va_start(args, func_ptr);
474
init_em_queued_call_args(&q, sig, args);
475
va_end(args);
476
sync_run_in_main_thread(&q);
477
return q.returnValue.i;
478
}
479
480
#ifdef __wasm64__
481
void* emscripten_sync_run_in_main_runtime_thread_ptr_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
482
em_queued_call q = {sig, func_ptr};
483
484
va_list args;
485
va_start(args, func_ptr);
486
init_em_queued_call_args(&q, sig, args);
487
va_end(args);
488
sync_run_in_main_thread(&q);
489
emscripten_outf("sync_run_in_main_ptr: %p\n", q.returnValue.vp);
490
return q.returnValue.vp;
491
}
492
#endif
493
494
void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
495
em_queued_call* q = em_queued_call_malloc();
496
if (!q)
497
return;
498
q->functionEnum = sig;
499
q->functionPtr = func_ptr;
500
501
va_list args;
502
va_start(args, func_ptr);
503
init_em_queued_call_args(q, sig, args);
504
va_end(args);
505
// 'async' runs are fire and forget, where the caller detaches itself from the call object after
506
// returning here, and it is the callee's responsibility to free up the memory after the call has
507
// been performed.
508
q->calleeDelete = 1;
509
emscripten_async_run_in_main_thread(q);
510
}
511
512
em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_(
513
EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
514
em_queued_call* q = em_queued_call_malloc();
515
if (!q)
516
return NULL;
517
q->functionEnum = sig;
518
q->functionPtr = func_ptr;
519
520
va_list args;
521
va_start(args, func_ptr);
522
init_em_queued_call_args(q, sig, args);
523
va_end(args);
524
// 'async waitable' runs are waited on by the caller, so the call object needs to remain alive for
525
// the caller to access it after the operation is done. The caller is responsible in cleaning up
526
// the object after done.
527
q->calleeDelete = 0;
528
emscripten_async_run_in_main_thread(q);
529
return q;
530
}
531
532
EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) {
533
int r;
534
535
int done = atomic_load(&call->operationDone);
536
if (!done) {
537
double now = emscripten_get_now();
538
double waitEndTime = now + timeoutMSecs;
539
emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY);
540
while (!done && now < waitEndTime) {
541
r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now);
542
done = atomic_load(&call->operationDone);
543
now = emscripten_get_now();
544
}
545
emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING);
546
}
547
if (done)
548
return EMSCRIPTEN_RESULT_SUCCESS;
549
else
550
return EMSCRIPTEN_RESULT_TIMED_OUT;
551
}
552
553
EMSCRIPTEN_RESULT emscripten_wait_for_call_i(
554
em_queued_call* call, double timeoutMSecs, int* outResult) {
555
EMSCRIPTEN_RESULT res = emscripten_wait_for_call_v(call, timeoutMSecs);
556
if (res == EMSCRIPTEN_RESULT_SUCCESS && outResult)
557
*outResult = call->returnValue.i;
558
return res;
559
}
560
561