|
1 | 1 | #include "napi_support.h" |
2 | 2 |
|
3 | 3 | #include <atomic> |
| 4 | +#include <chrono> |
4 | 5 | #include <condition_variable> |
5 | 6 | #include <map> |
| 7 | +#include <memory> |
6 | 8 | #include <mutex> |
7 | 9 | #include <thread> |
8 | 10 | #include <tuple> |
@@ -475,10 +477,38 @@ void RunOnMainThreadSync(const std::function<void()>& work) { |
475 | 477 | done_signal.wait(lock, [&] { return done; }); |
476 | 478 | } |
477 | 479 |
|
| 480 | +namespace { |
| 481 | + |
| 482 | +// Whether something on the UI thread drains its queue — a host running the |
| 483 | +// platform loop, as under `deno desktop`. `deno test` also runs JS off the main |
| 484 | +// thread, but its main thread only waits in Deno's own loop: hopping there |
| 485 | +// would block forever, so calls stay on the JS thread instead. |
| 486 | +bool MainThreadIsServiced() { |
| 487 | + struct Probe { |
| 488 | + std::mutex mutex; |
| 489 | + std::condition_variable signal; |
| 490 | + bool ran = false; |
| 491 | + }; |
| 492 | + // Shared, because a late run can land after this returns. |
| 493 | + auto probe = std::make_shared<Probe>(); |
| 494 | + bool posted = nativeapi::RunOnMainThread([probe] { |
| 495 | + std::lock_guard<std::mutex> lock(probe->mutex); |
| 496 | + probe->ran = true; |
| 497 | + probe->signal.notify_one(); |
| 498 | + }); |
| 499 | + if (!posted) { |
| 500 | + return false; |
| 501 | + } |
| 502 | + std::unique_lock<std::mutex> lock(probe->mutex); |
| 503 | + return probe->signal.wait_for(lock, std::chrono::seconds(1), [&] { return probe->ran; }); |
| 504 | +} |
| 505 | + |
| 506 | +} // namespace |
| 507 | + |
478 | 508 | void InitRuntime(napi_env env) { |
479 | 509 | g_js_thread = std::this_thread::get_id(); |
480 | | - g_hop_to_main_thread = |
481 | | - !nativeapi::IsMainThread() && nativeapi::IsMainThreadDispatchSupported(); |
| 510 | + g_hop_to_main_thread = !nativeapi::IsMainThread() && |
| 511 | + nativeapi::IsMainThreadDispatchSupported() && MainThreadIsServiced(); |
482 | 512 | g_env_alive.store(true); |
483 | 513 | napi_add_env_cleanup_hook( |
484 | 514 | env, [](void*) { g_env_alive.store(false); }, nullptr); |
|
0 commit comments