blob: fdbd403c40c51729384cdb5e3fd5963f547dc70d [file] [edit]
#ifdef WITH_RIVE_SCRIPTING_WASM
#include "rive/wasm/wasm_signal_wait.hpp"
#include "rive/async/timeouts.hpp"
#include "rive/wasm/wasm_lane_layout_gen.hpp"
#include "rive/wasm/wasm_shared.hpp"
using namespace rive;
namespace
{
// Casting a double outside the range to an integer is undefined.
uint64_t sequenceAfter(double after)
{
if (!(after > 0))
{
return 0;
}
return after >= 18446744073709551616.0 ? UINT64_MAX : (uint64_t)after;
}
} // namespace
SignalWait::SignalWait(
uint32_t id,
uint64_t owner,
uint32_t signal,
const SharedSignal* found,
double after,
double timeoutSeconds)
: id(id)
, owner(owner)
, signal(signal)
, after(sequenceAfter(after))
, deadline(
unboundedSeconds(timeoutSeconds) ? Clock::time_point::max()
: deadlineAfter(timeoutSeconds))
, gone(signal != 0 && found == nullptr)
{}
rcp<SharedSignal> SignalWait::find(uint32_t signal, uint64_t owner)
{
return signal != 0 ? SharedRegistry::find<SharedSignal>(signal, owner)
: nullptr;
}
bool SignalWait::fired(Clock::time_point now, double& value) const
{
if (signal != 0)
{
rcp<SharedSignal> found = find(signal, owner);
// Gone mid wait settles only an unbounded wait, so a timed one times
// out however soon its handle is collected.
if (found == nullptr && (gone || deadline == Clock::time_point::max()))
{
value = lane_layout::kWaitGone;
return true;
}
if (found != nullptr && found->seq() > after)
{
value = (double)found->seq();
return true;
}
}
if (now >= deadline)
{
value = lane_layout::kWaitTimedOut;
return true;
}
return false;
}
double SignalWait::block() const
{
rcp<SharedSignal> watched = find(signal, owner);
if (watched == nullptr)
{
return lane_layout::kWaitGone;
}
double value = lane_layout::kWaitTimedOut;
#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__)
fired(deadline, value);
#else
thread_local WakeWord word;
watched->addWatcher(&word);
// The word is read first, so a notify after the check still wakes it.
for (uint32_t seen = word.value(); !fired(Clock::now(), value);
seen = word.value())
{
word.wait(seen, deadline);
}
watched->removeWatcher(&word);
#endif
return value;
}
#endif