16#include "ravel/clock.hpp"
17#include "ravel/rng.hpp"
18#include "ravel/task.hpp"
19#include "ravel/trace.hpp"
23using TaskId = std::size_t;
32using TaskFactory = std::function<Task()>;
47 RunStatus
status = RunStatus::Completed;
69 : clock_(clock), rng_(rng), trace_(trace) {}
77 void spawn(std::string name, TaskFactory factory);
86 bool await_ready()
const noexcept {
return false; }
87 void await_suspend(std::coroutine_handle<>)
const { scheduler_.requeue_current_task(); }
88 void await_resume()
const noexcept {}
99 bool await_ready()
const noexcept {
return false; }
100 void await_suspend(std::coroutine_handle<>)
const {
101 scheduler_.sleep_current_task(duration_);
103 void await_resume()
const noexcept {}
108 : scheduler_(scheduler), duration_(duration) {}
123 std::uint64_t max_steps,
127 const std::string&
task_name(TaskId
id)
const {
return slots_.at(
id).name; }
147 TaskSlot(std::string
task_name, TaskFactory task_factory)
148 : name(std::move(
task_name)), factory(std::move(task_factory)) {}
157 std::uint64_t sequence;
158 std::function<void()> action;
162 bool operator()(
const Timer& a,
const Timer& b)
const noexcept {
163 return a.due != b.due ? a.due > b.due : a.sequence > b.sequence;
167 void requeue_current_task() {
make_runnable(current_task_); }
170 bool has_pending_work() const noexcept {
return !runnable_.empty() || !timers_.empty(); }
171 void fire_earliest_timers();
172 TaskId take_random_runnable_task();
176 std::exception_ptr resume_task(TaskId
id);
178 void record(TaskId task, TraceEventKind kind) {
179 trace_.
record({clock_.
now(), task, kind});
182 VirtualClock& clock_;
188 std::deque<TaskSlot> slots_;
189 std::vector<TaskId> runnable_;
190 std::priority_queue<Timer, std::vector<Timer>, DueLater> timers_;
191 std::uint64_t next_timer_sequence_ = 0;
192 TaskId current_task_ = 0;
194 void require_running_thread(
const char* operation)
const;
195 std::atomic<std::thread::id> running_thread_{};
What sleep() returns. It is only ever co_awaited.
Definition scheduler.hpp:97
What yield() returns. It is only ever co_awaited.
Definition scheduler.hpp:84
Cooperative, single-threaded task scheduler.
Definition scheduler.hpp:65
YieldAwaiter yield() noexcept
co_await scheduler.yield(); lets the scheduler pick who runs next.
Definition scheduler.hpp:114
void call_after(VirtualClock::Tick delay, std::function< void()> action)
Runs action once the clock reaches now() + delay.
VirtualClock::Tick now() const noexcept
The current virtual time.
Definition scheduler.hpp:133
Scheduler(VirtualClock &clock, VirtualRng &rng, Trace &trace) noexcept
Created by Simulation; you do not construct one yourself.
Definition scheduler.hpp:68
Scheduler(const Scheduler &)=delete
Tasks hold references into the scheduler, so it must never move.
TaskId current_task() const noexcept
The task being resumed right now. Valid only inside a task.
Definition scheduler.hpp:136
void spawn(std::string name, TaskFactory factory)
Registers a task.
RunReport run_until_quiescent(std::uint64_t max_steps, VirtualClock::Tick time_limit=std::numeric_limits< VirtualClock::Tick >::max())
Runs until nothing is left to happen, a task throws, max_steps steps have been taken,...
void make_runnable(TaskId id)
Lets a suspended task run again on a later step.
Definition scheduler.hpp:139
const std::string & task_name(TaskId id) const
The name a task was spawned with.
Definition scheduler.hpp:127
SleepAwaiter sleep(VirtualClock::Tick duration) noexcept
co_await scheduler.sleep(50); suspends the task for 50 virtual ticks.
Definition scheduler.hpp:116
The coroutine type for simulated tasks.
Definition task.hpp:19
Ordered record of everything that happened during a run (scheduling decisions and message fates),...
Definition trace.hpp:48
void record(const TraceEvent &event)
Appends an event and folds it into the digest.
Monotonic virtual time.
Definition clock.hpp:12
Tick now() const noexcept
The current virtual time.
Definition clock.hpp:18
std::uint64_t Tick
Virtual time, in ticks. A tick has no fixed real-world length.
Definition clock.hpp:15
The one source of randomness a Simulation may use.
Definition rng.hpp:28
How a Scheduler run ended.
Definition scheduler.hpp:45
std::uint64_t steps
How many times a task was resumed.
Definition scheduler.hpp:48
std::string failure
Human-readable cause; empty when Completed.
Definition scheduler.hpp:49
RunStatus status
Why the run ended.
Definition scheduler.hpp:47