Next Generation WASM Microkernel Operating System
1// Copyright 2025. Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use crate::time::max_duration;
9use core::fmt;
10use core::time::Duration;
11
12pub struct Clock {
13 name: &'static str,
14 tick_duration: Duration,
15 clock: RawClock,
16}
17
18/// A virtual function pointer table (vtable) that specifies the behavior
19/// of a [`RawClock`].
20///
21/// The pointer passed to all functions inside the vtable is the `data` pointer
22/// from the enclosing [`RawClock`] object.
23///
24/// The functions inside this struct are only intended to be called on the `data`
25/// pointer of a properly constructed [`RawClock`] object from inside the
26/// [`RawClock`] implementation. Calling one of the contained functions using
27/// any other `data` pointer will cause undefined behavior.
28///
29/// # Thread safety
30///
31/// All vtable functions must be thread-safe (even though [`RawClock`] is
32/// <code>\![Send] + \![Sync]</code>). This is because [`Clock`] is <code>[Send] + [Sync]</code>,
33/// and it *will* be moved to arbitrary threads or invoked by `&` reference. For example,
34/// this means that if the `clone` and `drop` functions manage a reference count,
35/// they must do so atomically.
36#[derive(Copy, Clone, Debug)]
37pub struct RawClockVTable {
38 clone: unsafe fn(*const ()) -> RawClock,
39 now: unsafe fn(*const ()) -> u64,
40 schedule_wakeup: unsafe fn(*const (), at: u64),
41 drop: unsafe fn(*const ()),
42}
43
44#[derive(Debug)]
45pub struct RawClock {
46 /// The `data` pointer can be used to store arbitrary data as required by the clock implementation.
47 data: *const (),
48 /// Virtual function pointer table that customizes the behavior of this clock.
49 vtable: &'static RawClockVTable,
50}
51
52// === impl Clock ===
53
54impl Unpin for Clock {}
55
56// Safety: As part of the safety contract for RawClockVTable, the caller promised RawClock is Send
57// therefore Clock is Send too
58unsafe impl Send for Clock {}
59// Safety: As part of the safety contract for RawClockVTable, the caller promised RawClock is Sync
60// therefore Clock is Sync too
61unsafe impl Sync for Clock {}
62
63impl Clock {
64 /// Creates a new `Clock` from the provided `tick_duration`, `data` pointer and `vtable`.
65 ///
66 /// The `tick_duration` is the `Duration` of time represented by a single `u64` tick in this clock.
67 /// This is in effect the precision of the clock and should be set to the precision of the underlying
68 /// hardware timer.
69 ///
70 /// The `data` pointer can be used to store arbitrary data as required by the clock implementation.
71 /// This could be e.g. a type-erased pointer to an `Arc` that holds private implementation-specific state.
72 /// The value of this pointer will get passed to all functions that are part
73 /// of the `vtable` as the first parameter.
74 ///
75 /// It is important to consider that the `data` pointer must point to a
76 /// thread safe type such as an `Arc`.
77 ///
78 /// The `vtable` customizes the behavior of a `Clock`. For each operation
79 /// on the `Clock`, the associated function in the `vtable` will be called.
80 ///
81 /// # Safety
82 ///
83 /// The behavior of the returned `Clock` is undefined if the contract defined
84 /// in [`RawClockVTable`]'s documentation is not upheld.
85 #[inline]
86 #[must_use]
87 pub const unsafe fn new(
88 tick_duration: Duration,
89 data: *const (),
90 vtable: &'static RawClockVTable,
91 ) -> Clock {
92 // Safety: ensured by caller
93 unsafe { Self::from_raw(tick_duration, RawClock { data, vtable }) }
94 }
95
96 /// Creates a new `Clock` from a [`RawClock`].
97 ///
98 /// # Safety
99 ///
100 /// The behavior of the returned `Waker` is undefined if the contract defined
101 /// in [`RawClock`]'s and [`RawClockVTable`]'s documentation is not upheld.
102 #[inline]
103 #[must_use]
104 pub const unsafe fn from_raw(tick_duration: Duration, clock: RawClock) -> Clock {
105 Self {
106 clock,
107 tick_duration,
108 name: "<unnamed mystery clock>",
109 }
110 }
111
112 /// Add an arbitrary user-defined name to this `Clock`.
113 ///
114 /// This is generally used to describe the hardware time source used by the
115 /// `now()` function for this `Clock`.
116 #[must_use]
117 pub const fn named(mut self, name: &'static str) -> Self {
118 self.name = name;
119 self
120 }
121
122 /// Returns this `Clock`'s name, if it was given one using the [`Clock::named`]
123 /// method.
124 #[must_use]
125 pub fn name(&self) -> &'static str {
126 self.name
127 }
128
129 /// Returns the [`Duration`] of one tick of this clock.
130 #[must_use]
131 pub const fn tick_duration(&self) -> Duration {
132 self.tick_duration
133 }
134
135 /// Returns the maximum duration of this clock.
136 #[must_use]
137 pub fn max_duration(&self) -> Duration {
138 max_duration(self.tick_duration())
139 }
140
141 /// Gets the `data` pointer used to create this `Clock`.
142 #[inline]
143 #[must_use]
144 pub fn data(&self) -> *const () {
145 self.clock.data
146 }
147
148 /// Gets the `vtable` pointer used to create this `Clock`.
149 #[inline]
150 #[must_use]
151 pub fn vtable(&self) -> &'static RawClockVTable {
152 self.clock.vtable
153 }
154
155 #[inline]
156 pub fn now(&self) -> u64 {
157 // Safety: This is safe because `Clock::from_raw` is the only way
158 // to initialize `vtable` and `data` requiring the user to acknowledge
159 // that the contract of `RawClock` is upheld.
160 unsafe { (self.clock.vtable.now)(self.clock.data) }
161 }
162
163 #[inline]
164 pub fn schedule_wakeup(&self, at: u64) {
165 // Safety: see Clock::now
166 unsafe { (self.clock.vtable.schedule_wakeup)(self.clock.data, at) };
167 }
168}
169
170impl Clone for Clock {
171 #[inline]
172 fn clone(&self) -> Self {
173 Clock {
174 // SAFETY: see Clock::now
175 clock: unsafe { (self.clock.vtable.clone)(self.clock.data) },
176 tick_duration: self.tick_duration,
177 name: self.name,
178 }
179 }
180}
181
182impl Drop for Clock {
183 #[inline]
184 fn drop(&mut self) {
185 // SAFETY: see Clock::now
186 unsafe { (self.clock.vtable.drop)(self.clock.data) }
187 }
188}
189
190impl fmt::Debug for Clock {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 let vtable_ptr = self.clock.vtable as *const RawClockVTable;
193 f.debug_struct("Waker")
194 .field("name", &self.name)
195 .field("tick_duration", &self.tick_duration)
196 .field("data", &self.clock.data)
197 .field("vtable", &vtable_ptr)
198 .finish()
199 }
200}
201
202impl fmt::Display for Clock {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 write!(f, "{}, {:?} precision", self.name, self.tick_duration)
205 }
206}
207
208// === impl RawClock ===
209
210impl RawClock {
211 /// Creates a new `Clock` from the provided `data` pointer and `vtable`.
212 ///
213 /// The `data` pointer can be used to store arbitrary data as required by the clock implementation.
214 /// his could be e.g. a type-erased pointer to an `Arc` that holds private implementation-specific state.
215 /// The value of this pointer will get passed to all functions that are part
216 /// of the `vtable` as the first parameter.
217 ///
218 /// It is important to consider that the `data` pointer must point to a
219 /// thread safe type such as an `Arc`.
220 ///
221 /// The `vtable` customizes the behavior of a `Clock`. For each operation
222 /// on the `Clock`, the associated function in the `vtable` will be called.
223 #[inline]
224 #[must_use]
225 pub const fn new(data: *const (), vtable: &'static RawClockVTable) -> RawClock {
226 Self { data, vtable }
227 }
228}
229
230// === impl RawClockVTable ===
231
232impl RawClockVTable {
233 pub const fn new(
234 clone: unsafe fn(*const ()) -> RawClock,
235 now: unsafe fn(*const ()) -> u64,
236 schedule_wakeup: unsafe fn(*const (), at: u64),
237 drop: unsafe fn(*const ()),
238 ) -> Self {
239 Self {
240 clone,
241 now,
242 schedule_wakeup,
243 drop,
244 }
245 }
246}