diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 29fe07ab7..3600e4a10 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -251,6 +251,7 @@ macro bool @has_same(#a, #b, ...) @const macro bool may_load_atomic($Type) @const { $switch ($Type.kindof) + $case BOOL: $case SIGNED_INT: $case UNSIGNED_INT: $case POINTER: diff --git a/lib/std/experimental/FrameScheduler.c3 b/lib/std/experimental/FrameScheduler.c3 new file mode 100644 index 000000000..134df99c0 --- /dev/null +++ b/lib/std/experimental/FrameScheduler.c3 @@ -0,0 +1,94 @@ +module std::experimental::scheduler(); +import std::collections, std::thread, std::time; + +struct DelayedSchedulerEvent @local +{ + inline Event event; + Clock execution_time; +} + +fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other) @local +{ + switch + { + case self.execution_time < other.execution_time: return -1; + case self.execution_time > other.execution_time: return 1; + default: return 0; + } +} + +struct FrameScheduler +{ + PriorityQueue{DelayedSchedulerEvent} delayed_events; + List{Event} events; + List{Event} pending_events; + bool pending; + Mutex mtx; +} + +fn void FrameScheduler.init(&self) +{ + self.events.new_init(); + self.pending_events.new_init(); + self.delayed_events.new_init(); + (void)self.mtx.init(); + bool pending; +} + +macro void FrameScheduler.@destroy(&self; @destruct(Event e)) +{ + foreach (e : self.events) @destruct(e); + foreach (e : self.pending_events) @destruct(e); + foreach (e : self.delayed_events.heap) @destruct(e.event); + self.events.free(); + self.pending_events.free(); + self.delayed_events.free(); + (void)self.mtx.destroy(); +} + +fn void FrameScheduler.queue_delayed_event(&self, Event event, Duration delay) +{ + self.mtx.@in_lock() + { + self.delayed_events.push({ event, clock::now().add_duration(delay)}); + @atomic_store(self.pending, true); + }; +} + +fn bool FrameScheduler.has_delayed(&self) +{ + self.mtx.@in_lock() + { + return @ok(self.delayed_events.first()); + }; +} + +fn void FrameScheduler.queue_event(&self, Event event) +{ + self.mtx.@in_lock() + { + self.pending_events.push(event); + @atomic_store(self.pending, true); + }; +} +fn Event! FrameScheduler.pop_event(&self) +{ + while (true) + { + if (try event = self.events.pop()) return event; + if (!@atomic_load(self.pending)) return IteratorResult.NO_MORE_ELEMENT?; + self.mtx.@in_lock() + { + self.events.add_all(&self.pending_events); + self.pending_events.clear(); + Clock c = clock::now(); + while (try top = self.delayed_events.first()) + { + if (top.execution_time > c) break; + self.events.push(self.delayed_events.pop()!!); + } + @atomic_store(self.pending, self.delayed_events.len() > 0); + if (!self.events.len()) return IteratorResult.NO_MORE_ELEMENT?; + }; + } +} diff --git a/lib/std/threads/thread.c3 b/lib/std/threads/thread.c3 index 172087ec5..2cb2424d1 100644 --- a/lib/std/threads/thread.c3 +++ b/lib/std/threads/thread.c3 @@ -45,6 +45,12 @@ macro void! TimedMutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock_timeou macro void! TimedRecursiveMutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock_timeout((NativeMutex*)mutex, ms); macro bool Mutex.try_lock(&mutex) => NativeMutex.try_lock((NativeMutex*)mutex); macro void! Mutex.unlock(&mutex) => NativeMutex.unlock((NativeMutex*)mutex); +macro void Mutex.@in_lock(&mutex; @body) +{ + (void)mutex.lock(); + defer (void)mutex.unlock(); + @body(); +} macro void! ConditionVariable.init(&cond) => NativeConditionVariable.init((NativeConditionVariable*)cond); macro void! ConditionVariable.destroy(&cond) => NativeConditionVariable.destroy((NativeConditionVariable*)cond); diff --git a/lib/std/time/clock.c3 b/lib/std/time/clock.c3 index c5d70ccee..e247f2a53 100644 --- a/lib/std/time/clock.c3 +++ b/lib/std/time/clock.c3 @@ -18,6 +18,16 @@ fn NanoDuration Clock.mark(&self) return diff; } +fn Clock Clock.add_nano_duration(self, NanoDuration nano) +{ + return (Clock)((NanoDuration)self + nano); +} + +fn Clock Clock.add_duration(self, Duration duration) +{ + return self.add_nano_duration(duration.to_nano()); +} + fn NanoDuration Clock.to_now(self) { return (NanoDuration)(now() - self);