#pragma once #include "machine.h" #include #include #include #include class alignas(CACHE_LINE_SIZE) Grip { std::function realtimePredicate; alignas(CACHE_LINE_SIZE) uint32_t loc; public: Grip(const Grip &) = delete; Grip &operator=(const Grip &) = delete; Grip(Grip &&) = delete; Grip &operator=(Grip &&) = delete; Grip(std::function &&pred) : realtimePredicate(std::move(pred)), loc(0) {} template requires requires(F &&f) { { f() } -> std::same_as; } void with(F &&f) { // try once optimistically if (f()) { return; } bool realtime = realtimePredicate(); if (realtime) { // increment count of realtime threads using this grip emscripten_atomic_add_u32(&loc, 1); } while (true) { if (!realtime) { // block until no more realtime threads are using this grip while (true) { const auto currentVal = emscripten_atomic_load_u32(&loc); if (currentVal == 0) { break; } emscripten_atomic_wait_u32(&loc, currentVal, ATOMICS_WAIT_DURATION_INFINITE); } } if (f()) { break; } } if (realtime) { // decrement count of realtime threads using this grip emscripten_atomic_sub_u32(&loc, 1); // wake up all threads waiting for this grip to become available again emscripten_atomic_notify(&loc, EMSCRIPTEN_NOTIFY_ALL_WAITERS); } } };