blob: aee6bab83380fac23a47f19e068293750a74145b [file] [edit]
/*
* Copyright 2021 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#pragma once
#include <functional>
#include <thread>
#include <emscripten/proxying.h>
namespace emscripten {
// Helper class for synchronously proxying work to a dedicated worker thread,
// including where the work is asynchronous.
class ProxyWorker {
// The queue we use to proxy work and the dedicated worker.
ProxyingQueue queue;
std::thread thread;
public:
// Spawn the worker thread.
ProxyWorker()
: queue(), thread([&]() {
// Sometimes the main thread is spinning, waiting on a WasmFS lock held
// by a thread trying to proxy work to this dedicated worker. In that
// case, the proxying message won't be relayed by the main thread and
// the system will deadlock. This heartbeat ensures that proxying work
// eventually gets done so the thread holding the lock can make forward
// progress even if the main thread is blocked.
//
// TODO: Remove this once we can postMessage directly between workers
// without involving the main thread.
//
// Note that this requires adding _emscripten_proxy_execute_queue to
// EXPORTED_FUNCTIONS.
EM_ASM({
var intervalID =
setInterval(() => {
if (ABORT) {
clearInterval(intervalID);
} else {
_emscripten_proxy_execute_queue($0);
}
}, 50);
}, queue.queue);
// Sit in the event loop performing work as it comes in.
emscripten_exit_with_live_runtime();
}) {}
// Kill the worker thread.
~ProxyWorker() {
pthread_cancel(thread.native_handle());
thread.join();
}
// Proxy synchronous work.
void operator()(const std::function<void()>& func) {
queue.proxySync(thread.native_handle(), func);
}
// Proxy asynchronous work that calls `finish()` on the ctx parameter to mark
// its end.
void operator()(const std::function<void(ProxyingQueue::ProxyingCtx)>& func) {
queue.proxySyncWithCtx(thread.native_handle(), func);
}
};
} // namespace emscripten