Skip to content

Commit db51a47

Browse files
authored
[Proxying] Add emscripten_proxy_callback_with_ctx (#18810)
This new proxying function is like `emscripten_proxy_callback`, but supports proxying of asynchronous work just like `emscripten_proxy_sync_with_ctx`. It uses the existing `em_proxying_ctx` type and `emscripten_proxy_finish` function to mark the work done, and that type and function are internally augmented to handle both synchronous and callback-based proxying. `emscripten_proxy_callback` is reimplemented to share most of its implementation with `emscripten_proxy_callback_with_ctx`, but it does break the abstraction slightly to avoid having to make an extra allocation.
1 parent 4589faa commit db51a47

File tree

9 files changed

+505
-165
lines changed

9 files changed

+505
-165
lines changed

site/source/docs/api_reference/proxying.h.rst

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ Functions
9090
9191
The same as ``emscripten_proxy_sync`` except that instead of waiting for the
9292
proxied function to return, it waits for the proxied task to be explicitly
93-
marked finished with ``emscripten_proxying_finish``. ``func`` need not call
94-
``emscripten_proxying_finish`` itself; it could instead store the context
95-
pointer and call ``emscripten_proxying_finish`` at an arbitrary later time.
93+
marked finished with ``emscripten_proxy_finish``. ``func`` need not call
94+
``emscripten_proxy_finish`` itself; it could instead store the context pointer
95+
and call ``emscripten_proxy_finish`` at an arbitrary later time.
9696

9797
.. c:function:: int emscripten_proxy_callback(em_proxying_queue* q, pthread_t target_thread, void (*func)(void*), void (*callback)(void*), void (*cancel)(void*), void* arg)
9898
@@ -103,6 +103,16 @@ Functions
103103
receive the same argument, ``arg``. Returns 1 if ``func`` was successfully
104104
enqueued and the target thread notified or 0 otherwise.
105105
106+
.. c:function:: int emscripten_proxy_callback_with_ctx(em_proxying_queue* q, pthread_t target_thread, void (*func)(em_proxying_ctx*, void*), void (*callback)(void*), void (*cancel)(void*), void* arg)
107+
108+
Enqueue ``func`` on the given queue and thread. Once (and if) it finishes the
109+
task by calling ``emscripten_proxy_finish`` on the given ``em_proxying_ctx``,
110+
it will asynchronously proxy ``callback`` back to the current thread on the
111+
same queue, or if the target thread dies before the work can be completed,
112+
``cancel`` will be proxied back instead. All three function will receive the
113+
same argument, ``arg``. Returns 1 if ``func`` was successfully enqueued and
114+
the target thread notified or 0 otherwise.
115+
106116
C++ API
107117
-------
108118
@@ -134,22 +144,29 @@ defined within namespace ``emscripten``.
134144
Calls ``emscripten_proxy_async`` to execute ``func``, returning ``true`` if the
135145
function was successfully enqueued and ``false`` otherwise.
136146
137-
.. cpp:member:: bool proxyCallback(pthread_t target, std::function<void()>&& func, std::function<void()>&& callback, std::function<void()>&& cancel)
138-
139-
Calls ``emscripten_proxy_callback`` to execute ``func`` and schedule either
140-
``callback`` or ``cancel``, returning ``true`` if the function was
141-
successfully enqueued and ``false`` otherwise.
142-
143147
.. cpp:member:: bool proxySync(const pthread_t target, const std::function<void()>& func)
144148
145149
Calls ``emscripten_proxy_sync`` to execute ``func``, returning ``true`` if the
146150
function was successfully completed or ``false`` otherwise.
147151
148152
.. cpp:member:: bool proxySyncWithCtx(const pthread_t target, const std::function<void(ProxyingCtx)>& func)
149153
150-
Calls ``emscripten_proxy_sync_with_ctx`` to execute ``func``, returning ``true``
151-
if the function was successfully marked done with
152-
``emscripten_proxying_finish`` or ``ProxyingCtx::finish`` and ``false`` otherwise.
154+
Calls ``emscripten_proxy_sync_with_ctx`` to execute ``func``, returning
155+
``true`` if the function was successfully marked done with
156+
``emscripten_proxy_finish`` or ``ProxyingCtx::finish`` and ``false``
157+
otherwise.
158+
159+
.. cpp:member:: bool proxyCallback(pthread_t target, std::function<void()>&& func, std::function<void()>&& callback, std::function<void()>&& cancel)
160+
161+
Calls ``emscripten_proxy_callback`` to execute ``func`` and schedule either
162+
``callback`` or ``cancel``, returning ``true`` if the function was
163+
successfully enqueued and ``false`` otherwise.
164+
165+
.. cpp:member:: bool proxyCallbackWithCtx(pthread_t target, std::function<void(ProxyingCtx)>&& func, std::function<void()>&& callback, std::function<void()>&& cancel)
166+
167+
Calls ``emscripten_proxy_callback_with_ctx`` to execute ``func`` and
168+
schedule either ``callback`` or ``cancel``, returning ``true`` if the
169+
function was successfully enqueued and ``false`` otherwise.
153170
154171
.. _proxying.h: https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/proxying.h
155172
.. _test_pthread_proxying.c: https://github.com/emscripten-core/emscripten/blob/main/test/pthread/test_pthread_proxying.c

system/include/emscripten/proxying.h

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ int emscripten_proxy_sync(em_proxying_queue* q,
6464
void* arg);
6565

6666
// Enqueue `func` on the given queue and thread and wait for it to be executed
67-
// and for the task to be marked finished with `emscripten_proxying_finish`
68-
// before returning. `func` need not call `emscripten_proxying_finish` itself;
69-
// it could instead store the context pointer and call
70-
// `emscripten_proxying_finish` at an arbitrary later time. Returns 1 if the
71-
// task was successfully completed and 0 otherwise, including if the target
72-
// thread is canceled or exits before the work is completed.
67+
// and for the task to be marked finished with `emscripten_proxy_finish` before
68+
// returning. `func` need not call `emscripten_proxy_finish` itself; it could
69+
// instead store the context pointer and call `emscripten_proxy_finish` at an
70+
// arbitrary later time. Returns 1 if the task was successfully completed and 0
71+
// otherwise, including if the target thread is canceled or exits before the
72+
// work is completed.
7373
int emscripten_proxy_sync_with_ctx(em_proxying_queue* q,
7474
pthread_t target_thread,
7575
void (*func)(em_proxying_ctx*, void*),
@@ -88,6 +88,20 @@ int emscripten_proxy_callback(em_proxying_queue* q,
8888
void (*cancel)(void*),
8989
void* arg);
9090

91+
// Enqueue `func` on the given queue and thread. Once (and if) it finishes the
92+
// task by calling `emscripten_proxy_finish` on the given `em_proxying_ctx`, it
93+
// will asynchronously proxy `callback` back to the current thread on the same
94+
// queue, or if the target thread dies before the work can be completed,
95+
// `cancel` will be proxied back instead. All three function will receive the
96+
// same argument, `arg`. Returns 1 if `func` was successfully enqueued and the
97+
// target thread notified or 0 otherwise.
98+
int emscripten_proxy_callback_with_ctx(em_proxying_queue* q,
99+
pthread_t target_thread,
100+
void (*func)(em_proxying_ctx*, void*),
101+
void (*callback)(void*),
102+
void (*cancel)(void*),
103+
void* arg);
104+
91105
#ifdef __cplusplus
92106
} // extern "C"
93107

@@ -103,6 +117,18 @@ namespace emscripten {
103117

104118
// A thin C++ wrapper around the underlying C API.
105119
class ProxyingQueue {
120+
public:
121+
// Simple wrapper around `em_proxying_ctx*` providing a `finish` method as an
122+
// alternative to `emscripten_proxy_finish`.
123+
struct ProxyingCtx {
124+
em_proxying_ctx* ctx;
125+
126+
ProxyingCtx() = default;
127+
ProxyingCtx(em_proxying_ctx* ctx) : ctx(ctx) {}
128+
void finish() { emscripten_proxy_finish(ctx); }
129+
};
130+
131+
private:
106132
static void runAndFree(void* arg) {
107133
auto* f = (std::function<void()>*)arg;
108134
(*f)();
@@ -150,6 +176,37 @@ class ProxyingQueue {
150176
delete info;
151177
}
152178

179+
struct CallbackWithCtxFuncs {
180+
std::function<void(ProxyingCtx)> func;
181+
std::function<void()> callback;
182+
std::function<void()> cancel;
183+
184+
CallbackWithCtxFuncs(std::function<void(ProxyingCtx)>&& func,
185+
std::function<void()>&& callback,
186+
std::function<void()>&& cancel)
187+
: func(std::move(func)), callback(std::move(callback)),
188+
cancel(std::move(cancel)) {}
189+
};
190+
191+
static void runFuncWithCtx(em_proxying_ctx* ctx, void* arg) {
192+
auto* info = (CallbackWithCtxFuncs*)arg;
193+
info->func(ProxyingCtx{ctx});
194+
}
195+
196+
static void runCallbackWithCtx(void* arg) {
197+
auto* info = (CallbackWithCtxFuncs*)arg;
198+
info->callback();
199+
delete info;
200+
}
201+
202+
static void runCancelWithCtx(void* arg) {
203+
auto* info = (CallbackWithCtxFuncs*)arg;
204+
if (info->cancel) {
205+
info->cancel();
206+
}
207+
delete info;
208+
}
209+
153210
public:
154211
em_proxying_queue* queue = em_proxying_queue_create();
155212

@@ -179,16 +236,6 @@ class ProxyingQueue {
179236
}
180237
}
181238

182-
// Simple wrapper around `em_proxying_ctx*` providing a `finish` method as an
183-
// alternative to `emscripten_proxy_finish`.
184-
struct ProxyingCtx {
185-
em_proxying_ctx* ctx;
186-
187-
ProxyingCtx() = default;
188-
ProxyingCtx(em_proxying_ctx* ctx) : ctx(ctx) {}
189-
void finish() { emscripten_proxy_finish(ctx); }
190-
};
191-
192239
void execute() { emscripten_proxy_execute_queue(queue); }
193240

194241
// Return true if the work was successfully enqueued and false otherwise.
@@ -225,6 +272,24 @@ class ProxyingQueue {
225272
}
226273
return true;
227274
}
275+
276+
bool proxyCallbackWithCtx(pthread_t target,
277+
std::function<void(ProxyingCtx)>&& func,
278+
std::function<void()>&& callback,
279+
std::function<void()>&& cancel) {
280+
CallbackWithCtxFuncs* info = new CallbackWithCtxFuncs(
281+
std::move(func), std::move(callback), std::move(cancel));
282+
if (!emscripten_proxy_callback_with_ctx(queue,
283+
target,
284+
runFuncWithCtx,
285+
runCallbackWithCtx,
286+
runCancelWithCtx,
287+
info)) {
288+
delete info;
289+
return false;
290+
}
291+
return true;
292+
}
228293
};
229294

230295
} // namespace emscripten

0 commit comments

Comments
 (0)