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