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::{
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#[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 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 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 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 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 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 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 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 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) generations: [Cell<Option<route::Epoch>>; route::CAPACITY],
387 pub(in crate::driver) sequence: sequence::Owner,
388 timer: heap::raw::Store<time::Instant, slot::Slot, timer::Tag>,
389}
390
391impl Shared {
392 pub(in crate::driver) fn try_new(
393 seed: random::Seed,
394 plan: settings::Plan,
395 failure: &mut Option<result::CreateError>,
396 ) -> Result<(provided::Arena<driver::Buffer, Self, ()>, Engine), &mut result::CreateError> {
397 let config = *plan.config();
398 let initialize = match provided::Arena::<driver::Buffer, Self, ()>::try_allocate(
399 config.receive().count().into(),
400 ) {
401 Ok(initialize) => initialize,
402 Err(error) => return Err(failure.insert(error.into())),
403 };
404 let schedule = match schedule::State::try_new(plan) {
405 Ok(schedule) => schedule,
406 Err(error) => return Err(failure.insert(error.into())),
407 };
408 let timer = match heap::raw::Store::try_new(config.schedule().timers().count().get()) {
409 Ok(timer) => timer,
410 Err(error) => return Err(failure.insert(error.into())),
411 };
412 let (backend, buffer, receive) =
416 match unsafe { <Backend as engine::raw::Create<Host<Backend>, _>>::try_new(&config) } {
417 Ok(created) => created,
418 Err(error) => return Err(failure.insert(create::Created::from(error).0)),
419 };
420 Ok((
421 initialize(Self {
422 random_seed: seed,
423 schedule,
424 receive,
425 buffer,
426 retire: queues::Pending::new(),
427 generations: [const { Cell::new(Some(route::Epoch::INITIAL)) }; route::CAPACITY],
428 sequence: sequence::Owner::new(),
429 timer,
430 }),
431 backend,
432 ))
433 }
434
435 pub(in crate::driver) const fn random_seed(&self) -> &random::Seed {
436 &self.random_seed
437 }
438
439 pub(crate) fn buffer(&self) -> &<Engine as engine::Buffer>::Context {
440 &self.buffer
441 }
442
443 pub(crate) fn into_buffer(self) -> <Engine as engine::Buffer>::Context {
444 self.buffer
445 }
446
447 pub(in crate::driver) fn timer(
448 &self,
449 ) -> &heap::raw::Store<time::Instant, slot::Slot, timer::Tag> {
450 &self.timer
451 }
452}
453
454impl buffer::raw::Fixed<driver::Buffer> for Shared {
455 fn resident(&self) -> num::NonZero<u32> {
456 buffer::raw::Fixed::resident(&self.buffer)
457 }
458
459 unsafe fn project<'a, 'id>(
460 &'a self,
461 item: &'a mut driver::Buffer,
462 limit: buffer::raw::Limit<'id>,
463 ) -> buffer::raw::Projection<'a, 'id> {
464 unsafe { buffer::raw::Fixed::project(&self.buffer, item, limit) }
467 }
468}