blob: 478debf9be09e3de0df881d3a673511a8446dbb3 [file] [edit]
#ifndef _RIVE_WASM_JOBS_HPP_
#define _RIVE_WASM_JOBS_HPP_
#ifdef WITH_RIVE_SCRIPTING_WASM
#include "rive/async/job_pool.hpp"
#include "rive/wasm/wasm_lane.hpp"
#include "rive/refcnt.hpp"
#include "rive/span.hpp"
#include <vector>
namespace rive
{
/// One run of a jobs module entry: bytes in, bytes out, in an instance as
/// instantiation leaves it, on whichever thread claims it.
class WasmJob : public JobTask, public WasmLane
{
public:
static constexpr uint32_t kJoinRefused = lane_layout::kJoinRefused;
static constexpr LaneKind kKind = LaneKind::job;
WasmJob(
rcp<WasmLaneModule> module,
uint32_t entry,
std::vector<uint8_t> input);
LaneState state() const override;
void stop() override;
/// Valid once finished.
const std::vector<uint8_t>& output() const { return m_output; }
uint32_t reuseMaxPages() const { return m_module->reuseMaxPages; }
/// The job running on this thread, for the natives its module imports.
static WasmJob* current();
protected:
void run() override;
void interrupt() override;
private:
bool execute();
#ifndef __EMSCRIPTEN__
// The entry answers the address of (pointer, length) of its result.
bool takeResult(uint32_t record);
void park();
#endif
bool m_failed = false;
// A cancel that reached the job while it ran ended it.
bool m_stopped = false;
std::vector<uint8_t> m_output;
#ifdef __EMSCRIPTEN__
// Set by a cancel, for the job's cancelled() to read.
std::atomic<int32_t> m_cancelWord{0};
#endif
};
/// A VM's jobs: the module carried in its main module's "rive.jobs" custom
/// section, and every job the VM started.
class WasmJobs : public WasmLaneSet<WasmJob>
{
public:
using WasmLaneSet::WasmLaneSet;
~WasmJobs();
/// Reconfigures the process wide job pool. Tests use it to run the same
/// jobs at every thread count and schedule.
static void configurePool(
uint32_t threads,
JobSchedule schedule = JobSchedule::fifo,
uint64_t seed = 0);
static JobPool& pool();
/// The pool's threads, or those it would start with, without making it.
/// chosen says whether the host chose the count rather than the default.
static uint32_t poolThreads(bool* chosen = nullptr);
#if defined(WITH_RIVE_TOOLS) || defined(TESTING)
/// Drops the pool and the host's choice, so the next use makes the
/// default pool.
static void resetPool();
#endif
/// With no pool threads a job runs only when joined or here, at each poll:
/// at least one, more within the cooperative slice, each to its end.
static void runQueuedInline();
/// A run of the job holding the page's thread may take
/// pageThreadBudgetMs, 0 for no limit.
rcp<WasmJob> run(
uint32_t entry,
std::vector<uint8_t> input,
uint32_t pageThreadBudgetMs);
/// Joins within the usableSeconds a caller may spend, infinity for none:
/// only a caller with none runs the job here, to its end, and no wait
/// outlasts them.
bool join(WasmJob* job, double timeoutSeconds, double usableSeconds);
int joinAny(Span<WasmJob*> jobs, double timeoutSeconds, double usableSeconds);
/// A started job that has not finished.
bool hasUnfinished() const;
};
} // namespace rive
#endif
#endif