Skip to main content

dope_core/driver/
mod.rs

1use std::{marker, mem, num, ops::ControlFlow, ptr, task, time};
2
3use dope_sys::{engine, io::reactor::ready::delivery::Quota as _, kernel};
4use o3::{
5    base::cell::region,
6    buffer::{self, storage::provided},
7};
8use route::table;
9
10use crate::{
11    Backend, Engine, driver,
12    driver::{
13        life::{
14            domain::runtime::Runtime,
15            native,
16            native::{create, host::Host},
17        },
18        receive::access,
19        result::poll,
20        retained::{flight, flight::cancel},
21        route::{kind, queues},
22        schedule::{
23            clock,
24            clock::{timer, timer::heap},
25            ready,
26            ready::{task::owner, wake::resident::slot},
27            sequence,
28            state::scope,
29        },
30    },
31    io,
32    io::{
33        event::{
34            batch,
35            net::{accept, recv},
36        },
37        fd::{access::Access, outbound},
38    },
39    random,
40};
41
42pub mod life;
43pub mod receive;
44pub mod result;
45pub mod retained;
46pub mod route;
47pub mod schedule;
48pub mod settings;
49pub mod storage;
50
51use result::{IoOperation, Opcode, SubmitError};
52
53type Buffer = <Engine as engine::Buffer>::Token;
54
55/// Keeps every derived capability in the exact driver lifetime that issued it.
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57#[repr(transparent)]
58pub(crate) struct Invariant<'d>(marker::PhantomData<fn(&'d ()) -> &'d ()>);
59
60#[must_use = "application binding must be consumed during startup"]
61pub struct Binding<'d> {
62    timer: timer::Timer<'d>,
63    owners: owner::Capacity,
64}
65
66impl<'d> Binding<'d> {
67    #[doc(hidden)]
68    pub const fn new(timer: timer::Timer<'d>, owners: owner::Capacity) -> Self {
69        Self { timer, owners }
70    }
71
72    pub const fn timer(&self) -> timer::Timer<'d> {
73        self.timer
74    }
75
76    pub const fn owners(&self) -> owner::Capacity {
77        self.owners
78    }
79
80    pub fn sequence(&self) -> sequence::Block<'d> {
81        sequence::Block::new(self.timer.driver)
82    }
83}
84
85#[repr(transparent)]
86pub struct Driver {
87    runtime: Runtime,
88}
89
90#[derive(Clone, Copy)]
91#[repr(transparent)]
92pub struct Reference<'d> {
93    shared: provided::Root<'d, Buffer, Shared, ()>,
94    pub(crate) brand: Invariant<'d>,
95}
96
97impl<'d> Reference<'d> {
98    pub fn outbound_cap(self) -> table::Capacity {
99        let arena = self.ready().arena();
100        arena.descriptors().outbound_cap()
101    }
102
103    pub fn accept_cap(self) -> table::Capacity {
104        let arena = self.ready().arena();
105        arena.descriptors().accept_cap()
106    }
107
108    fn new(shared: provided::Root<'d, Buffer, Shared, ()>) -> Self {
109        Self {
110            shared,
111            brand: Invariant(marker::PhantomData),
112        }
113    }
114
115    pub const fn ready(self) -> ready::Context<'d> {
116        ready::Context::new(self)
117    }
118
119    pub const fn targets<Tag: route::Tag>(self) -> route::Space<'d, Tag> {
120        route::Space {
121            driver: route::Brand::new(self.brand),
122        }
123    }
124
125    pub const fn scheduler(self) -> schedule::Context<'d> {
126        schedule::Context::new(self)
127    }
128
129    /// Issues one identity without reserving a scheduler's local block.
130    pub fn try_next_id(self) -> Result<sequence::Id<'d>, sequence::Exhausted> {
131        let raw = self
132            .shared
133            .context()
134            .sequence
135            .next()
136            .ok_or(sequence::Exhausted)?;
137        Ok(sequence::Id::new(self, raw))
138    }
139
140    pub fn clock(self) -> clock::Clock<'d, 'd> {
141        self.scheduler().clock()
142    }
143
144    pub const fn timer(self) -> timer::Timer<'d> {
145        timer::Timer::new(self)
146    }
147
148    pub fn maintenance(self) -> schedule::Progress<'d> {
149        if self.has_deferred() {
150            schedule::Progress::Runnable
151        } else {
152            schedule::Progress::Quiescent
153        }
154    }
155
156    pub(crate) const fn receive(self) -> access::Access<'d> {
157        access::Access::new(self)
158    }
159
160    pub(crate) fn has_deferred(self) -> bool {
161        self.receive().owners().has_returned()
162            || self.descriptors().retirement().has_pending()
163            || self.shared.context().retire.has_pending()
164    }
165
166    pub(crate) const fn descriptors(self) -> Access<'d> {
167        Access::new(self)
168    }
169
170    pub(crate) const fn outbound(self) -> outbound::Context<'d> {
171        outbound::Context::new(self)
172    }
173
174    #[doc(hidden)]
175    pub fn is_same(self, other: Reference<'_>) -> bool {
176        ptr::from_ref(self.shared.context()).addr() == ptr::from_ref(other.shared.context()).addr()
177    }
178
179    #[doc(hidden)]
180    pub fn random_seed(self) -> &'d random::Seed {
181        self.shared.context().random_seed()
182    }
183}
184
185const _: () = {
186    assert!(mem::size_of::<IoOperation>() == 1);
187    assert!(mem::align_of::<IoOperation>() == 1);
188    assert!(mem::size_of::<Opcode>() == mem::size_of::<<crate::Backend as kernel::Source>::Code>());
189    assert!(
190        mem::align_of::<Opcode>() == mem::align_of::<<crate::Backend as kernel::Source>::Code>()
191    );
192    assert!(mem::size_of::<Driver>() == mem::size_of::<Runtime>());
193    assert!(mem::align_of::<Driver>() == mem::align_of::<Runtime>());
194    assert!(mem::size_of::<Reference<'_>>() == mem::size_of::<usize>());
195    assert!(mem::align_of::<Reference<'_>>() == mem::align_of::<usize>());
196    assert!(mem::size_of::<Invariant<'_>>() == 0);
197    assert!(mem::align_of::<Invariant<'_>>() == 1);
198    assert!(mem::size_of::<Context<'_, '_>>() == mem::size_of::<usize>());
199    assert!(mem::align_of::<Context<'_, '_>>() == mem::align_of::<usize>());
200    assert!(mem::size_of::<SubmitError>() == 1 && mem::align_of::<SubmitError>() == 1);
201    assert!(
202        mem::size_of::<Result<flight::Flight<'static>, SubmitError>>()
203            == mem::size_of::<(flight::Flight<'static>, SubmitError)>()
204    );
205    assert!(
206        mem::align_of::<Result<flight::Flight<'static>, SubmitError>>()
207            == mem::align_of::<flight::Flight<'static>>()
208    );
209};
210
211#[repr(transparent)]
212#[non_exhaustive]
213pub struct Context<'a, 'd> {
214    pub storage: storage::Context<'a, 'd>,
215}
216
217impl<'a, 'd> Context<'a, 'd> {
218    fn new(local: &'a mut life::Local<'d>) -> Self {
219        Self {
220            storage: storage::Context::new(local),
221        }
222    }
223
224    /// Reports one exact cancellation rejection to this scope's mandatory observer.
225    pub fn rejected(&mut self, failure: cancel::Failure) {
226        let report = io::Reclaimed::Cancellation(failure);
227        (self.storage.0.lifecycle.report)(report);
228    }
229
230    /// Reports a consumed accept failure with its original driver-bound target.
231    pub fn accept_error(
232        &mut self,
233        target: route::Erased<'d, kind::Accept>,
234        cause: accept::Failure,
235        flow: batch::Flow,
236    ) {
237        (self.storage.0.lifecycle.report)(io::Reclaimed::AcceptRoute {
238            target: target.into_token(),
239            cause,
240            flow,
241        });
242    }
243
244    /// Reclaims a terminal routed receive and reports its original target and outcome.
245    pub fn retire(&mut self, event: io::Event<'d>) -> ControlFlow<io::Event<'d>> {
246        use io::event::Kind;
247
248        let done = match event.into_kind() {
249            Kind::RetiredRecv(done) => done,
250            kind => return ControlFlow::Break(kind.into()),
251        };
252        self.reclaim(done);
253        ControlFlow::Continue(())
254    }
255
256    /// Consumes one routed receive, releases its owner, and reports the exact result.
257    pub fn reclaim(&mut self, done: recv::Completion<'d>) {
258        use io::transfer::Len;
259        use recv::Outcome;
260
261        let (target, flow, outcome) = done.into_parts();
262        let result = match outcome {
263            Outcome::Data(buffer) => {
264                let length = buffer.len();
265                Ok(length)
266            }
267            Outcome::Eof => Ok(Len::ZERO),
268            Outcome::Cancelled => Err(crate::Errno::CANCELED),
269            Outcome::Exhausted(proof) => Err(proof.retire()),
270            Outcome::Starved(error) => Err(error.into()),
271            Outcome::Failed(error) => Err(error),
272        };
273        (self.storage.0.lifecycle.report)(io::Reclaimed::RecvRoute {
274            target: target.into_token(),
275            result,
276            flow,
277        });
278    }
279
280    pub fn reborrow(&mut self) -> Context<'_, 'd> {
281        Context::new(&mut *self.storage.0)
282    }
283
284    pub(crate) fn native(&mut self) -> native::Access<'_, 'd> {
285        native::Access::new(&mut *self.storage.0)
286    }
287
288    pub fn region_token(&mut self) -> &mut region::Token<region::Identity<'d>> {
289        &mut self.storage.0.region.0
290    }
291
292    pub fn state_token(&mut self) -> &mut region::Token<region::Identity<'d, 1>> {
293        &mut self.storage.0.region.1
294    }
295
296    pub fn into_regions(
297        self,
298    ) -> &'a mut (
299        region::Token<region::Identity<'d>>,
300        region::Token<region::Identity<'d, 1>>,
301    ) {
302        &mut self.storage.0.region
303    }
304
305    pub fn regions(
306        &self,
307    ) -> &(
308        region::Token<region::Identity<'d>>,
309        region::Token<region::Identity<'d, 1>>,
310    ) {
311        &self.storage.0.region
312    }
313
314    pub fn receive(&self) -> settings::Receive {
315        self.storage.receive()
316    }
317
318    pub fn driver_ref(&self) -> Reference<'d> {
319        self.storage.0.driver
320    }
321}
322
323impl<'a, 'd> Context<'a, 'd> {
324    pub fn dispatch(
325        &mut self,
326        work: scope::Reactor<'_, 'd>,
327        emit: impl FnMut(io::Event<'d>, &mut Self) -> ControlFlow<io::Event<'d>>,
328    ) -> poll::Dispatch<'d> {
329        let work = native::Backend::new(work);
330        // SAFETY: Context retains the same Local root, registered storage, and
331        // branded flight owners throughout native resolution and host emission.
332        let turn: <Backend as engine::Dispatch<'_, Host<Backend>, Self>>::Turn<_> =
333            unsafe { engine::raw::Dispatch::<'_, Host<Backend>, Self, _>::new(self, work) };
334        engine::raw::Dispatch::<'_, Host<Backend>, Self, _>::dispatch(turn, emit)
335    }
336
337    pub fn commit(&mut self, work: scope::Reactor<'_, 'd>) -> Result<poll::Commit, poll::Error> {
338        let quota = native::Backend::new(work);
339        quota.reclaim(self);
340        let retry = self.storage.0.retry;
341        let owner = self.driver_ref();
342        let mut native = self.native();
343        // SAFETY: Context retains this driver's registered storage and branded
344        // flight owners throughout maintenance and native completion processing.
345        let state = unsafe {
346            engine::raw::Poll::commit(native.as_mut(), quota, || retry || owner.has_deferred())
347        }
348        .map_err(poll::Error::from_backend)?;
349        self.storage.0.retry = false;
350        Ok(match state {
351            task::Poll::Ready(()) => poll::Commit::Drained,
352            task::Poll::Pending => poll::Commit::Pending,
353        })
354    }
355
356    pub fn wait(
357        &mut self,
358        work: scope::Reactor<'_, 'd>,
359        timeout: Option<time::Duration>,
360    ) -> Result<(), poll::Error> {
361        let quota = native::Backend::new(work);
362        quota.reclaim(self);
363        let retry = self.storage.0.retry;
364        let owner = self.driver_ref();
365        let pending = self.storage.0.lifecycle.pending;
366        let mut native = self.native();
367        // SAFETY: Context retains this driver's registered storage and branded
368        // flight owners throughout maintenance and native completion processing.
369        unsafe {
370            engine::raw::Poll::wait(native.as_mut(), quota, timeout, || {
371                retry || pending || owner.has_deferred() || owner.ready().has_ready()
372            })
373        }
374        .map_err(poll::Error::from_backend)?;
375        self.storage.0.retry = false;
376        Ok(())
377    }
378}
379
380pub(crate) struct Shared {
381    random_seed: random::Seed,
382    pub(in crate::driver) schedule: schedule::State,
383    pub(in crate::driver) receive: crate::Permits,
384    buffer: <Engine as engine::Buffer>::Context,
385    pub(in crate::driver) retire: queues::Pending,
386    pub(in crate::driver) sequence: sequence::Owner,
387    timer: heap::raw::Store<time::Instant, slot::Slot, timer::Tag>,
388}
389
390impl Shared {
391    pub(in crate::driver) fn try_new(
392        seed: random::Seed,
393        plan: settings::Plan,
394        failure: &mut Option<result::CreateError>,
395    ) -> Result<(provided::Arena<driver::Buffer, Self, ()>, Engine), &mut result::CreateError> {
396        let config = *plan.config();
397        let initialize = match provided::Arena::<driver::Buffer, Self, ()>::try_allocate(
398            config.receive().count().into(),
399        ) {
400            Ok(initialize) => initialize,
401            Err(error) => return Err(failure.insert(error.into())),
402        };
403        let schedule = match schedule::State::try_new(plan) {
404            Ok(schedule) => schedule,
405            Err(error) => return Err(failure.insert(error.into())),
406        };
407        let timer = match heap::raw::Store::try_new(config.schedule().timers().count().get()) {
408            Ok(timer) => timer,
409            Err(error) => return Err(failure.insert(error.into())),
410        };
411        // SAFETY: all fallible host allocation precedes native creation.
412        // This infallible assembly retains the returned context beside
413        // its backend throughout the same driver generation and teardown.
414        let (backend, buffer, receive) =
415            match unsafe { <Backend as engine::raw::Create<Host<Backend>, _>>::try_new(&config) } {
416                Ok(created) => created,
417                Err(error) => return Err(failure.insert(create::Created::from(error).0)),
418            };
419        Ok((
420            initialize(Self {
421                random_seed: seed,
422                schedule,
423                receive,
424                buffer,
425                retire: queues::Pending::new(),
426                sequence: sequence::Owner::new(),
427                timer,
428            }),
429            backend,
430        ))
431    }
432
433    pub(in crate::driver) const fn random_seed(&self) -> &random::Seed {
434        &self.random_seed
435    }
436
437    pub(crate) fn buffer(&self) -> &<Engine as engine::Buffer>::Context {
438        &self.buffer
439    }
440
441    pub(crate) fn into_buffer(self) -> <Engine as engine::Buffer>::Context {
442        self.buffer
443    }
444
445    pub(in crate::driver) fn timer(
446        &self,
447    ) -> &heap::raw::Store<time::Instant, slot::Slot, timer::Tag> {
448        &self.timer
449    }
450}
451
452impl buffer::raw::Fixed<driver::Buffer> for Shared {
453    fn resident(&self) -> num::NonZero<u32> {
454        buffer::raw::Fixed::resident(&self.buffer)
455    }
456
457    unsafe fn project<'a, 'id>(
458        &'a self,
459        item: &'a mut driver::Buffer,
460        limit: buffer::raw::Limit<'id>,
461    ) -> buffer::raw::Projection<'a, 'id> {
462        // SAFETY: Shared retains this exact native context beside its arena;
463        // the caller supplies its uniquely owned completed item and resident limit.
464        unsafe { buffer::raw::Fixed::project(&self.buffer, item, limit) }
465    }
466}