77
88#pragma once
99
10- #include < mutex >
10+ #include < future >
1111#include < thread>
1212
1313#include < jsi/jsi.h>
@@ -26,71 +26,61 @@ using RuntimeExecutor =
2626 std::function<void (std::function<void (jsi::Runtime& runtime)>&& callback)>;
2727
2828/*
29- * Executes a `callback` in a *synchronous* manner on the same thread using
30- * given `RuntimeExecutor`.
31- * Use this method when the caller needs to *be blocked* by executing the
32- * `callback` and requires that the callback will be executed on the same
33- * thread.
34- * Example order of events (when not a sync call in runtimeExecutor callback):
35- * - [UI thread] Lock all mutexes at start
36- * - [UI thread] runtimeCaptured.lock before callback
37- * - [JS thread] Set runtimePtr in runtimeExecutor callback
38- * - [JS thread] runtimeCaptured.unlock in runtimeExecutor callback
39- * - [UI thread] Call callback
40- * - [JS thread] callbackExecuted.lock in runtimeExecutor callback
41- * - [UI thread] callbackExecuted.unlock after callback
42- * - [UI thread] jsBlockExecuted.lock after callback
43- * - [JS thread] jsBlockExecuted.unlock in runtimeExecutor callback
29+ * Schedules `runtimeWork` to be executed on the same thread using the
30+ * `RuntimeExecutor`, and blocks on its completion.
31+ *
32+ * Example:
33+ * - [UI thread] Schedule `runtimeCaptureBlock` on js thread
34+ * - [UI thread] Wait for runtime capture: await(runtime)
35+ * - [JS thread] Capture runtime for ui thread: resolve(runtime, &rt);
36+ * - [JS thread] Wait until runtimeWork done: await(runtimeWorkDone)
37+ * - [UI thread] Call runtimeWork: runtimeWork(*runtimePrt);
38+ * - [UI thread] Signal runtimeWork done: resolve(runtimeWorkDone)
39+ * - [UI thread] Wait until runtime capture block finished:
40+ * await(runtimeCaptureBlockDone);
41+ * - [JS thread] Signal runtime capture block is finished:
42+ * resolve(runtimeCaptureBlockDone);
4443 */
4544inline static void executeSynchronouslyOnSameThread_CAN_DEADLOCK (
4645 const RuntimeExecutor& runtimeExecutor,
47- std::function<void (jsi::Runtime& runtime)>&& callback) noexcept {
48- // Note: We need the third mutex to get back to the main thread before
49- // the lambda is finished (because all mutexes are allocated on the stack).
50-
51- std::mutex runtimeCaptured;
52- std::mutex callbackExecuted;
53- std::mutex jsBlockExecuted;
54-
55- runtimeCaptured.lock ();
56- callbackExecuted.lock ();
57- jsBlockExecuted.lock ();
46+ std::function<void (jsi::Runtime&)>&& runtimeWork) noexcept {
47+ std::promise<jsi::Runtime*> runtime;
48+ std::promise<void > runtimeCaptureBlockDone;
49+ std::promise<void > runtimeWorkDone;
5850
59- jsi::Runtime* runtimePtr ;
51+ auto callingThread = std::this_thread::get_id () ;
6052
61- auto threadId = std::this_thread::get_id ();
53+ auto runtimeCaptureBlock = [&](jsi::Runtime& rt) {
54+ runtime.set_value (&rt);
6255
63- runtimeExecutor ([&](jsi::Runtime& runtime) {
64- runtimePtr = &runtime;
65-
66- if (threadId == std::this_thread::get_id ()) {
67- // In case of a synchronous call, we should unlock mutexes and return.
68- runtimeCaptured.unlock ();
69- jsBlockExecuted.unlock ();
70- return ;
56+ auto runtimeThread = std::this_thread::get_id ();
57+ if (callingThread != runtimeThread) {
58+ // Block `runtimeThread` on execution of `runtimeWork` on `callingThread`.
59+ runtimeWorkDone.get_future ().wait ();
7160 }
7261
73- runtimeCaptured.unlock ();
74- // `callback` is called somewhere here.
75- callbackExecuted.lock ();
76- jsBlockExecuted.unlock ();
77- });
62+ // TODO(T225331233): This is likely unnecessary. Remove it.
63+ runtimeCaptureBlockDone.set_value ();
64+ };
65+ runtimeExecutor (std::move (runtimeCaptureBlock));
66+
67+ jsi::Runtime* runtimePtr = runtime.get_future ().get ();
68+ runtimeWork (*runtimePtr);
69+ runtimeWorkDone.set_value ();
7870
79- runtimeCaptured.lock ();
80- callback (*runtimePtr);
81- callbackExecuted.unlock ();
82- jsBlockExecuted.lock ();
71+ // TODO(T225331233): This is likely unnecessary. Remove it.
72+ runtimeCaptureBlockDone.get_future ().wait ();
8373}
8474
8575template <typename DataT>
8676inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK (
8777 const RuntimeExecutor& runtimeExecutor,
88- std::function<DataT(jsi::Runtime& runtime)>&& callback ) noexcept {
78+ std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork ) noexcept {
8979 DataT data;
9080
9181 executeSynchronouslyOnSameThread_CAN_DEADLOCK (
9282 runtimeExecutor,
93- [&](jsi::Runtime& runtime) { data = callback (runtime); });
83+ [&](jsi::Runtime& runtime) { data = runtimeWork (runtime); });
9484
9585 return data;
9686}
0 commit comments