1use futures_util::future::BoxFuture;
2use sharded_slab::Slab;
3use std::{
4 any::{Any, TypeId},
5 collections::HashMap,
6 marker::PhantomData,
7 sync::{Arc, Mutex},
8 task::Waker,
9};
10use thiserror::Error;
11use tracing::{
12 Instrument, Span, debug,
13 field::{self, Empty},
14};
15
16use crate::{
17 KernelError,
18 drivers::Capability,
19 futures::FutureSharedState,
20 guest_data::GuestResult,
21 mailbox::GuestMailbox,
22 session::{Session, SessionError},
23};
24use selium_abi::{DependencyId, GuestResourceId};
25use wasmtime::{StoreLimits, StoreLimitsBuilder};
26
27pub type ResourceId = usize;
29type GuestFuture = Arc<FutureSharedState<GuestResult<Vec<u8>>>>;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum ResourceType {
34 Process,
36 Instance,
38 Channel,
40 Reader,
42 Writer,
44 Session,
46 Network,
48 Future,
50 Other,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct ResourceMetadata {
57 pub id: ResourceId,
59 pub owner: Option<ResourceId>,
61 pub kind: ResourceType,
63}
64
65#[derive(Clone)]
67pub struct ResourceHandle<T>(ResourceId, PhantomData<T>);
68
69struct Resource {
70 data: Arc<Mutex<Option<Box<dyn Any + Send>>>>,
71 kind: ResourceType,
72 span: Span,
74}
75
76struct InstanceState {
77 process_id: Option<ResourceId>,
78 mailbox: Option<&'static GuestMailbox>,
79 extensions: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
80 limits: StoreLimits,
81}
82
83#[derive(Default)]
84struct HandleTable {
85 entries: Vec<Option<ResourceId>>,
86 free: Vec<usize>,
87}
88
89struct HandleIndex {
90 shared: HandleTable,
91 shared_reverse: HashMap<ResourceId, usize>,
92 instances: HashMap<ResourceId, HandleTable>,
93 futures: HashMap<ResourceId, HandleTable>,
94}
95
96#[derive(Default)]
97struct RelationIndex {
98 owner_of: HashMap<ResourceId, ResourceId>,
99 owned_by: HashMap<ResourceId, Vec<ResourceId>>,
100 parent_of: HashMap<ResourceId, ResourceId>,
101 children_of: HashMap<ResourceId, Vec<ResourceId>>,
102 instance_to_process: HashMap<ResourceId, ResourceId>,
103 process_to_instance: HashMap<ResourceId, ResourceId>,
104 process_log_channel: HashMap<ResourceId, ResourceId>,
105 log_channel_process: HashMap<ResourceId, ResourceId>,
106 singletons: HashMap<DependencyId, ResourceId>,
107 singleton_ids: HashMap<ResourceId, DependencyId>,
108}
109
110pub struct Registry {
112 resources: Slab<Resource>,
113 relations: Mutex<RelationIndex>,
114 handles: Mutex<HandleIndex>,
115}
116
117pub struct InstanceRegistry {
119 registry: Arc<Registry>,
121 instance_id: ResourceId,
123}
124
125#[derive(Clone)]
127pub struct InstanceRegistrar {
128 registry: Arc<Registry>,
129 instance_id: ResourceId,
130}
131
132#[derive(Debug, Error)]
134pub enum RegistryError {
135 #[error("registry capacity exhausted")]
137 CapacityExhausted,
138 #[error("registry lock poisoned")]
140 LockPoisoned,
141 #[error("invalid resource reservation")]
143 InvalidReservation,
144 #[error("instance state missing")]
146 MissingInstance,
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
151pub struct ProcessIdentity(ResourceId);
152
153impl InstanceState {
154 fn new() -> Self {
155 Self {
156 process_id: None,
157 mailbox: None,
158 extensions: HashMap::new(),
159 limits: StoreLimits::default(),
160 }
161 }
162}
163
164impl HandleTable {
165 fn allocate(&mut self, resource_id: ResourceId) -> usize {
166 if let Some(slot) = self.free.pop()
167 && let Some(entry) = self.entries.get_mut(slot)
168 {
169 *entry = Some(resource_id);
170 return slot;
171 }
172
173 self.entries.push(Some(resource_id));
174 self.entries.len() - 1
175 }
176
177 fn resolve(&self, handle: usize) -> Option<ResourceId> {
178 self.entries.get(handle).and_then(|entry| *entry)
179 }
180
181 fn remove(&mut self, handle: usize) -> Option<ResourceId> {
182 let entry = self.entries.get_mut(handle)?;
183 let resource_id = entry.take();
184 if resource_id.is_some() {
185 self.free.push(handle);
186 }
187 resource_id
188 }
189}
190
191impl HandleIndex {
192 fn new() -> Self {
193 Self {
194 shared: HandleTable::default(),
195 shared_reverse: HashMap::new(),
196 instances: HashMap::new(),
197 futures: HashMap::new(),
198 }
199 }
200
201 fn share_handle(&mut self, id: ResourceId) -> Result<GuestResourceId, RegistryError> {
202 if let Some(existing) = self.shared_reverse.get(&id).copied() {
203 return GuestResourceId::try_from(existing)
204 .map_err(|_| RegistryError::CapacityExhausted);
205 }
206
207 let handle = self.shared.allocate(id);
208 match GuestResourceId::try_from(handle) {
209 Ok(guest) => {
210 self.shared_reverse.insert(id, handle);
211 Ok(guest)
212 }
213 Err(_) => {
214 self.shared.remove(handle);
215 Err(RegistryError::CapacityExhausted)
216 }
217 }
218 }
219
220 fn resolve_shared(&self, handle: GuestResourceId) -> Option<ResourceId> {
221 let idx = usize::try_from(handle).ok()?;
222 self.shared.resolve(idx)
223 }
224
225 fn shared_handle(&self, id: ResourceId) -> Option<GuestResourceId> {
226 let handle = self.shared_reverse.get(&id).copied()?;
227 GuestResourceId::try_from(handle).ok()
228 }
229
230 fn remove_shared(&mut self, id: ResourceId) {
231 if let Some(handle) = self.shared_reverse.remove(&id) {
232 self.shared.remove(handle);
233 }
234 }
235
236 fn insert_instance(&mut self, instance_id: ResourceId, resource_id: ResourceId) -> usize {
237 self.instances
238 .entry(instance_id)
239 .or_default()
240 .allocate(resource_id)
241 }
242
243 fn resolve_instance(&self, instance_id: ResourceId, handle: usize) -> Option<ResourceId> {
244 self.instances
245 .get(&instance_id)
246 .and_then(|table| table.resolve(handle))
247 }
248
249 fn remove_instance(&mut self, instance_id: ResourceId, handle: usize) -> Option<ResourceId> {
250 self.instances
251 .get_mut(&instance_id)
252 .and_then(|table| table.remove(handle))
253 }
254
255 fn insert_future(&mut self, instance_id: ResourceId, resource_id: ResourceId) -> usize {
256 self.futures
257 .entry(instance_id)
258 .or_default()
259 .allocate(resource_id)
260 }
261
262 fn resolve_future(&self, instance_id: ResourceId, handle: usize) -> Option<ResourceId> {
263 self.futures
264 .get(&instance_id)
265 .and_then(|table| table.resolve(handle))
266 }
267
268 fn remove_future(&mut self, instance_id: ResourceId, handle: usize) -> Option<ResourceId> {
269 self.futures
270 .get_mut(&instance_id)
271 .and_then(|table| table.remove(handle))
272 }
273
274 fn remove_instance_tables(&mut self, instance_id: ResourceId) {
275 self.instances.remove(&instance_id);
276 self.futures.remove(&instance_id);
277 }
278}
279
280impl RelationIndex {
281 fn set_owner(&mut self, id: ResourceId, owner: ResourceId) {
282 if let Some(previous) = self.owner_of.insert(id, owner)
283 && previous != owner
284 {
285 Self::remove_from_list(self.owned_by.get_mut(&previous), id);
286 }
287 Self::push_unique(self.owned_by.entry(owner).or_default(), id);
288 }
289
290 fn owner(&self, id: ResourceId) -> Option<ResourceId> {
291 self.owner_of.get(&id).copied()
292 }
293
294 fn owned_by(&self, owner: ResourceId) -> Vec<ResourceId> {
295 self.owned_by.get(&owner).cloned().unwrap_or_default()
296 }
297
298 fn set_parent(&mut self, id: ResourceId, parent: ResourceId) {
299 if let Some(previous) = self.parent_of.insert(id, parent)
300 && previous != parent
301 {
302 Self::remove_from_list(self.children_of.get_mut(&previous), id);
303 }
304 Self::push_unique(self.children_of.entry(parent).or_default(), id);
305 }
306
307 fn parent(&self, id: ResourceId) -> Option<ResourceId> {
308 self.parent_of.get(&id).copied()
309 }
310
311 fn children(&self, parent: ResourceId) -> Vec<ResourceId> {
312 self.children_of.get(&parent).cloned().unwrap_or_default()
313 }
314
315 fn set_instance_process(&mut self, instance_id: ResourceId, process_id: ResourceId) {
316 if let Some(previous) = self.instance_to_process.insert(instance_id, process_id)
317 && previous != process_id
318 {
319 self.process_to_instance.remove(&previous);
320 }
321 self.process_to_instance.insert(process_id, instance_id);
322 }
323
324 fn instance_process(&self, instance_id: ResourceId) -> Option<ResourceId> {
325 self.instance_to_process.get(&instance_id).copied()
326 }
327
328 fn process_instance(&self, process_id: ResourceId) -> Option<ResourceId> {
329 self.process_to_instance.get(&process_id).copied()
330 }
331
332 fn set_log_channel(&mut self, process_id: ResourceId, channel_id: ResourceId) {
333 if let Some(previous) = self.process_log_channel.insert(process_id, channel_id)
334 && previous != channel_id
335 {
336 self.log_channel_process.remove(&previous);
337 }
338
339 if let Some(previous) = self.log_channel_process.insert(channel_id, process_id)
340 && previous != process_id
341 {
342 self.process_log_channel.remove(&previous);
343 }
344 }
345
346 fn log_channel(&self, process_id: ResourceId) -> Option<ResourceId> {
347 self.process_log_channel.get(&process_id).copied()
348 }
349
350 fn register_singleton(&mut self, id: DependencyId, resource: ResourceId) -> bool {
351 if self.singletons.contains_key(&id) || self.singleton_ids.contains_key(&resource) {
352 return false;
353 }
354
355 self.singletons.insert(id, resource);
356 self.singleton_ids.insert(resource, id);
357 true
358 }
359
360 fn singleton(&self, id: DependencyId) -> Option<ResourceId> {
361 self.singletons.get(&id).copied()
362 }
363
364 fn remove_resource(&mut self, id: ResourceId) {
365 if let Some(owner) = self.owner_of.remove(&id) {
366 Self::remove_from_list(self.owned_by.get_mut(&owner), id);
367 }
368
369 if let Some(parent) = self.parent_of.remove(&id) {
370 Self::remove_from_list(self.children_of.get_mut(&parent), id);
371 }
372
373 if let Some(process) = self.instance_to_process.remove(&id) {
374 self.process_to_instance.remove(&process);
375 }
376
377 if let Some(instance) = self.process_to_instance.remove(&id) {
378 self.instance_to_process.remove(&instance);
379 }
380
381 if let Some(channel) = self.process_log_channel.remove(&id) {
382 self.log_channel_process.remove(&channel);
383 }
384
385 if let Some(process) = self.log_channel_process.remove(&id) {
386 self.process_log_channel.remove(&process);
387 }
388
389 if let Some(singleton_id) = self.singleton_ids.remove(&id) {
390 self.singletons.remove(&singleton_id);
391 }
392 }
393
394 fn push_unique(list: &mut Vec<ResourceId>, id: ResourceId) {
395 if !list.contains(&id) {
396 list.push(id);
397 }
398 }
399
400 fn remove_from_list(list: Option<&mut Vec<ResourceId>>, id: ResourceId) {
401 if let Some(list) = list {
402 list.retain(|entry| *entry != id);
403 }
404 }
405}
406
407impl ProcessIdentity {
408 pub fn new(id: ResourceId) -> Self {
410 Self(id)
411 }
412
413 pub fn raw(&self) -> ResourceId {
415 self.0
416 }
417}
418
419impl<T> ResourceHandle<T> {
420 pub fn new(id: ResourceId) -> ResourceHandle<T> {
422 Self(id, PhantomData)
423 }
424
425 pub fn into_id(self) -> ResourceId {
427 self.0
428 }
429}
430
431impl Registry {
432 fn resource_span(kind: ResourceType, owner: Option<ResourceId>) -> Span {
433 tracing::debug_span!(
434 "kernel.resource",
435 resource_id = Empty,
436 kind = ?kind,
437 owner = ?owner,
438 resource_type = Empty,
439 guest_slot = Empty,
440 host_ptr = Empty,
441 parent_id = Empty,
442 shared_id = Empty,
443 )
444 }
445
446 pub fn new() -> Arc<Self> {
448 let registry = Arc::new(Self {
449 resources: Slab::new(),
450 relations: Mutex::new(RelationIndex::default()),
451 handles: Mutex::new(HandleIndex::new()),
452 });
453
454 registry.resources.insert(Resource {
456 data: Arc::new(Mutex::new(Some(Box::new(())))),
457 kind: ResourceType::Other,
458 span: Self::resource_span(ResourceType::Other, None),
459 });
460
461 registry
462 }
463
464 pub fn instance(self: &Arc<Self>) -> Result<InstanceRegistry, RegistryError> {
466 let instance = self.add(InstanceState::new(), None, ResourceType::Instance)?;
467 Ok(InstanceRegistry {
468 registry: self.clone(),
469 instance_id: instance.into_id(),
470 })
471 }
472
473 pub fn add<T: Send + 'static>(
475 &self,
476 resource: T,
477 owner: Option<ResourceId>,
478 kind: ResourceType,
479 ) -> Result<ResourceHandle<T>, RegistryError> {
480 let r = Resource {
481 data: Arc::new(Mutex::new(Some(Box::new(resource)))),
482 kind,
483 span: Self::resource_span(kind, owner),
484 };
485 let raw = self
486 .resources
487 .insert(r)
488 .ok_or(RegistryError::CapacityExhausted)?;
489 if let Some(owner) = owner {
490 let mut relations = self
491 .relations
492 .lock()
493 .map_err(|_| RegistryError::LockPoisoned)?;
494 relations.set_owner(raw, owner);
495 }
496 self.record_resource_added::<T>(raw);
497 Ok(ResourceHandle(raw, PhantomData))
498 }
499
500 pub fn reserve(
502 &self,
503 owner: Option<ResourceId>,
504 kind: ResourceType,
505 ) -> Result<ResourceId, RegistryError> {
506 let r = Resource {
507 data: Arc::new(Mutex::new(None)),
508 kind,
509 span: Self::resource_span(kind, owner),
510 };
511
512 let id = self
513 .resources
514 .insert(r)
515 .ok_or(RegistryError::CapacityExhausted)?;
516 if let Some(owner) = owner {
517 let mut relations = self
518 .relations
519 .lock()
520 .map_err(|_| RegistryError::LockPoisoned)?;
521 relations.set_owner(id, owner);
522 }
523 self.record_resource_reserved(id);
524 Ok(id)
525 }
526
527 pub fn initialise<T: Send + 'static>(
529 &self,
530 id: ResourceId,
531 resource: T,
532 ) -> Result<ResourceHandle<T>, RegistryError> {
533 let entry = self
534 .resources
535 .get(id)
536 .ok_or(RegistryError::InvalidReservation)?;
537 let mut guard = entry.data.lock().map_err(|_| RegistryError::LockPoisoned)?;
538
539 if guard.is_some() {
540 return Err(RegistryError::InvalidReservation);
541 }
542
543 *guard = Some(Box::new(resource));
544 self.record_resource_initialised::<T>(id);
545 Ok(ResourceHandle(id, PhantomData))
546 }
547
548 pub fn remove<T: 'static>(&self, id: ResourceHandle<T>) -> Option<T> {
550 self.record_resource_removed(id.0);
551 let kind = self.resources.get(id.0).map(|resource| resource.kind);
552 if let Ok(mut handles) = self.handles.lock() {
553 handles.remove_shared(id.0);
554 if matches!(kind, Some(ResourceType::Instance)) {
555 handles.remove_instance_tables(id.0);
556 }
557 }
558 if let Ok(mut relations) = self.relations.lock() {
559 relations.remove_resource(id.0);
560 }
561 self.resources.take(id.0).and_then(|resource| {
562 let data = Arc::try_unwrap(resource.data).ok()?;
563 let boxed_opt = data.into_inner().ok()?;
564 let boxed = boxed_opt?;
565 boxed.downcast::<T>().map(|b| *b).ok()
566 })
567 }
568
569 pub fn discard(&self, id: ResourceId) -> bool {
571 self.record_resource_removed(id);
572 let kind = self.resources.get(id).map(|resource| resource.kind);
573 if let Ok(mut handles) = self.handles.lock() {
574 handles.remove_shared(id);
575 if matches!(kind, Some(ResourceType::Instance)) {
576 handles.remove_instance_tables(id);
577 }
578 }
579 if let Ok(mut relations) = self.relations.lock() {
580 relations.remove_resource(id);
581 }
582 self.resources.take(id).is_some()
583 }
584
585 pub fn with<T: 'static, R>(
587 &self,
588 id: ResourceHandle<T>,
589 func: impl FnOnce(&mut T) -> R,
590 ) -> Option<R> {
591 let (data, span) = {
592 let entry = self.resources.get(id.0)?;
593 (entry.data.clone(), entry.span.clone())
594 };
595 let mut guard = data.lock().ok()?;
596 let t = guard.as_mut().and_then(|boxed| boxed.downcast_mut::<T>())?;
597 Some(span.in_scope(|| func(t)))
598 }
599
600 pub(crate) async fn with_async<T: Send + 'static, R>(
602 &self,
603 id: ResourceHandle<T>,
604 func: impl for<'a> FnOnce(&'a mut T) -> BoxFuture<'a, R>,
605 ) -> Option<R> {
606 let (data, span) = {
607 let entry = self.resources.get(id.0)?;
608 (entry.data.clone(), entry.span.clone())
609 };
610 let boxed = {
611 let mut guard = data.lock().ok()?;
612 guard.take()?
613 };
614 let mut resource = boxed.downcast::<T>().ok()?;
615 let result = func(resource.as_mut()).instrument(span).await;
616 let boxed: Box<dyn Any + Send> = resource;
617 let mut guard = data.lock().ok()?;
618 *guard = Some(boxed);
619 Some(result)
620 }
621
622 pub fn share_handle(&self, id: ResourceId) -> Result<GuestResourceId, RegistryError> {
624 let shared = {
625 let mut handles = self
626 .handles
627 .lock()
628 .map_err(|_| RegistryError::LockPoisoned)?;
629 handles.share_handle(id)
630 }?;
631
632 self.record_shared_handle(id, shared);
633
634 Ok(shared)
635 }
636
637 pub fn resolve_shared(&self, handle: GuestResourceId) -> Option<ResourceId> {
639 let resolved = {
640 let handles = self.handles.lock().ok()?;
641 handles.resolve_shared(handle)
642 };
643 if let Some(id) = resolved
644 && let Some(resource) = self.resources.get(id)
645 {
646 debug!(parent: &resource.span, shared_handle = handle, "resolve shared handle");
647 }
648 resolved
649 }
650
651 pub fn shared_handle(&self, id: ResourceId) -> Option<GuestResourceId> {
653 let handles = self.handles.lock().ok()?;
654 handles.shared_handle(id)
655 }
656
657 pub fn metadata(&self, id: ResourceId) -> Option<ResourceMetadata> {
659 let resource = self.resources.get(id)?;
660 let owner = self.relations.lock().ok()?.owner(id);
661 Some(ResourceMetadata {
662 id,
663 owner,
664 kind: resource.kind,
665 })
666 }
667
668 pub fn owner(&self, id: ResourceId) -> Option<ResourceId> {
670 self.relations.lock().ok()?.owner(id)
671 }
672
673 pub fn owned_resources(&self, owner: ResourceId) -> Vec<ResourceId> {
675 self.relations
676 .lock()
677 .map(|relations| relations.owned_by(owner))
678 .unwrap_or_default()
679 }
680
681 pub fn parent(&self, id: ResourceId) -> Option<ResourceId> {
683 self.relations.lock().ok()?.parent(id)
684 }
685
686 pub fn children(&self, id: ResourceId) -> Vec<ResourceId> {
688 self.relations
689 .lock()
690 .map(|relations| relations.children(id))
691 .unwrap_or_default()
692 }
693
694 pub fn instance_process(&self, instance_id: ResourceId) -> Option<ResourceId> {
696 self.relations.lock().ok()?.instance_process(instance_id)
697 }
698
699 pub fn process_instance(&self, process_id: ResourceId) -> Option<ResourceId> {
701 self.relations.lock().ok()?.process_instance(process_id)
702 }
703
704 pub fn log_channel(&self, process_id: ResourceId) -> Option<ResourceId> {
706 self.relations.lock().ok()?.log_channel(process_id)
707 }
708
709 pub fn log_channel_handle(&self, process_id: ResourceId) -> Option<GuestResourceId> {
711 let channel_id = self.log_channel(process_id)?;
712 self.shared_handle(channel_id)
713 }
714
715 pub fn register_singleton(
719 &self,
720 id: DependencyId,
721 resource: ResourceId,
722 ) -> Result<bool, RegistryError> {
723 let mut relations = self
724 .relations
725 .lock()
726 .map_err(|_| RegistryError::LockPoisoned)?;
727 Ok(relations.register_singleton(id, resource))
728 }
729
730 pub fn singleton(&self, id: DependencyId) -> Option<ResourceId> {
732 self.relations.lock().ok()?.singleton(id)
733 }
734
735 fn record_resource_added<T: 'static>(&self, id: ResourceId) {
736 if let Some(resource) = self.resources.get(id) {
737 resource.span.record("resource_id", field::display(id));
738 resource
739 .span
740 .record("resource_type", field::display(std::any::type_name::<T>()));
741 debug!(parent: &resource.span, "resource registered");
742 }
743 }
744
745 fn record_resource_reserved(&self, id: ResourceId) {
746 if let Some(resource) = self.resources.get(id) {
747 resource.span.record("resource_id", field::display(id));
748 debug!(parent: &resource.span, "resource reserved");
749 }
750 }
751
752 fn record_resource_initialised<T: 'static>(&self, id: ResourceId) {
753 if let Some(resource) = self.resources.get(id) {
754 resource
755 .span
756 .record("resource_type", field::display(std::any::type_name::<T>()));
757 debug!(parent: &resource.span, "resource initialised");
758 }
759 }
760
761 fn record_resource_removed(&self, id: ResourceId) {
762 if let Some(resource) = self.resources.get(id) {
763 debug!(parent: &resource.span, "resource removed");
764 }
765 }
766
767 fn record_guest_slot(&self, id: ResourceId, slot: usize) {
768 if let Some(resource) = self.resources.get(id) {
769 resource.span.record("guest_slot", field::display(slot));
770 debug!(parent: &resource.span, guest_slot = %slot, "resource slot assigned");
771 }
772 }
773
774 fn record_slot_detached(&self, id: ResourceId, slot: usize) {
775 if let Some(resource) = self.resources.get(id) {
776 debug!(parent: &resource.span, guest_slot = %slot, "resource slot detached");
777 }
778 }
779
780 fn record_shared_handle(&self, id: ResourceId, shared: GuestResourceId) {
781 if let Some(resource) = self.resources.get(id) {
782 resource.span.record("shared_id", field::display(shared));
783 debug!(parent: &resource.span, shared_handle = shared, "resource shared");
784 } else {
785 debug!(resource_id = %id, shared_handle = shared, "resource shared");
786 }
787 }
788
789 pub(crate) fn record_host_ptr(&self, id: ResourceId, ptr: &str) {
791 if let Some(resource) = self.resources.get(id) {
792 resource.span.record("host_ptr", field::display(ptr));
793 debug!(parent: &resource.span, host_ptr = %ptr, "resource host pointer");
794 }
795 }
796
797 pub(crate) fn record_parent(&self, id: ResourceId, parent: ResourceId) {
799 if let Ok(mut relations) = self.relations.lock() {
800 relations.set_parent(id, parent);
801 }
802 if let Some(resource) = self.resources.get(id) {
803 resource.span.record("parent_id", field::display(parent));
804 debug!(parent: &resource.span, parent_id = %parent, "resource parent linked");
805 }
806 }
807
808 pub(crate) fn set_instance_process(
810 &self,
811 instance_id: ResourceId,
812 process_id: ResourceId,
813 ) -> Result<(), RegistryError> {
814 if self.resources.get(instance_id).is_none() {
815 return Err(RegistryError::InvalidReservation);
816 }
817 if self.resources.get(process_id).is_none() {
818 return Err(RegistryError::InvalidReservation);
819 }
820 let mut relations = self
821 .relations
822 .lock()
823 .map_err(|_| RegistryError::LockPoisoned)?;
824 relations.set_instance_process(instance_id, process_id);
825 relations.set_owner(instance_id, process_id);
826 Ok(())
827 }
828
829 pub(crate) fn set_log_channel(
831 &self,
832 process_id: ResourceId,
833 channel_id: ResourceId,
834 ) -> Result<(), RegistryError> {
835 if self.resources.get(process_id).is_none() {
836 return Err(RegistryError::InvalidReservation);
837 }
838 if self.resources.get(channel_id).is_none() {
839 return Err(RegistryError::InvalidReservation);
840 }
841 let mut relations = self
842 .relations
843 .lock()
844 .map_err(|_| RegistryError::LockPoisoned)?;
845 relations.set_log_channel(process_id, channel_id);
846 Ok(())
847 }
848}
849
850impl InstanceRegistry {
851 fn with_instance_state<R>(&self, f: impl FnOnce(&mut InstanceState) -> R) -> Option<R> {
852 self.registry.with(ResourceHandle::new(self.instance_id), f)
853 }
854
855 pub fn load_mailbox(&mut self, mb: &'static GuestMailbox) -> Result<(), RegistryError> {
859 self.with_instance_state(|state| state.mailbox = Some(mb))
860 .ok_or(RegistryError::MissingInstance)
861 }
862
863 pub fn registrar(&self) -> InstanceRegistrar {
865 InstanceRegistrar {
866 registry: self.registry.clone(),
867 instance_id: self.instance_id,
868 }
869 }
870
871 pub fn refresh_mailbox(&self, base: usize) {
873 if let Some(mb) = self.mailbox() {
874 mb.refresh_base(base);
875 }
876 }
877
878 pub fn close_mailbox(&self) {
880 if let Some(mb) = self.mailbox() {
881 mb.close();
882 }
883 }
884
885 pub fn set_memory_limit(&mut self, bytes: usize) -> Result<(), RegistryError> {
889 self.with_instance_state(|state| {
890 state.limits = StoreLimitsBuilder::new().memory_size(bytes).build();
891 })
892 .ok_or(RegistryError::MissingInstance)
893 }
894
895 fn insert_instance_handle(&self, resource_id: ResourceId) -> Result<usize, RegistryError> {
896 let mut handles = self
897 .registry
898 .handles
899 .lock()
900 .map_err(|_| RegistryError::LockPoisoned)?;
901 Ok(handles.insert_instance(self.instance_id, resource_id))
902 }
903
904 fn remove_instance_handle(&self, handle: usize) -> Option<ResourceId> {
905 let mut handles = self.registry.handles.lock().ok()?;
906 handles.remove_instance(self.instance_id, handle)
907 }
908
909 fn resolve_instance_handle(&self, handle: usize) -> Option<ResourceId> {
910 let handles = self.registry.handles.lock().ok()?;
911 handles.resolve_instance(self.instance_id, handle)
912 }
913
914 fn insert_future_handle(&self, resource_id: ResourceId) -> Result<usize, RegistryError> {
915 let mut handles = self
916 .registry
917 .handles
918 .lock()
919 .map_err(|_| RegistryError::LockPoisoned)?;
920 Ok(handles.insert_future(self.instance_id, resource_id))
921 }
922
923 fn resolve_future_handle(&self, handle: usize) -> Option<ResourceId> {
924 let handles = self.registry.handles.lock().ok()?;
925 handles.resolve_future(self.instance_id, handle)
926 }
927
928 fn remove_future_handle(&self, handle: usize) -> Option<ResourceId> {
929 let mut handles = self.registry.handles.lock().ok()?;
930 handles.remove_future(self.instance_id, handle)
931 }
932
933 pub fn insert<T: Send + 'static>(
935 &mut self,
936 entry: T,
937 owner: Option<ResourceId>,
938 kind: ResourceType,
939 ) -> Result<usize, RegistryError> {
940 let owner = self.process_id()?.or(owner);
941 let entry = self.registry.add(entry, owner, kind)?;
942 let resource_id = entry.0;
943 let slot = self.insert_instance_handle(resource_id)?;
944 self.registry.record_guest_slot(resource_id, slot);
945 Ok(slot)
946 }
947
948 pub fn insert_id(&mut self, id: ResourceId) -> Result<usize, RegistryError> {
950 let slot = self.insert_instance_handle(id)?;
951 self.registry.record_guest_slot(id, slot);
952 Ok(slot)
953 }
954
955 pub fn entry(&self, idx: usize) -> Option<ResourceId> {
957 self.resolve_instance_handle(idx)
958 }
959
960 pub fn with<T: 'static, R>(&self, idx: ResourceId, f: impl FnOnce(&mut T) -> R) -> Option<R> {
962 let resource = self.resolve_instance_handle(idx)?;
963 self.registry
964 .with::<T, R>(ResourceHandle(resource, PhantomData), f)
965 }
966
967 pub fn insert_extension<T: Any + Send + Sync>(
971 &mut self,
972 value: T,
973 ) -> Result<(), RegistryError> {
974 let ext: Arc<dyn Any + Send + Sync> = Arc::new(value);
975 self.with_instance_state(|state| {
976 state.extensions.insert(TypeId::of::<T>(), ext);
977 })
978 .ok_or(RegistryError::MissingInstance)
979 }
980
981 pub fn extension<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
983 self.with_instance_state(|state| {
984 state
985 .extensions
986 .get(&TypeId::of::<T>())
987 .and_then(|boxed| Arc::clone(boxed).downcast::<T>().ok())
988 })
989 .flatten()
990 }
991
992 pub fn remove<T: 'static>(&mut self, idx: usize) -> Option<T> {
994 let resource_id = self.remove_instance_handle(idx)?;
995 self.registry
996 .remove(ResourceHandle(resource_id, PhantomData))
997 }
998
999 pub fn detach_slot(&mut self, idx: usize) -> Option<ResourceId> {
1001 let resource_id = self.remove_instance_handle(idx);
1002 if let Some(resource_id) = resource_id {
1003 self.registry.record_slot_detached(resource_id, idx);
1004 }
1005 resource_id
1006 }
1007
1008 pub fn waker(&self, task_id: usize) -> Option<Waker> {
1010 self.mailbox().map(|mailbox| mailbox.waker(task_id))
1011 }
1012
1013 pub fn mailbox(&self) -> Option<&'static GuestMailbox> {
1015 self.with_instance_state(|state| state.mailbox).flatten()
1016 }
1017
1018 pub fn registry(&self) -> &Registry {
1020 &self.registry
1021 }
1022
1023 pub fn registry_arc(&self) -> Arc<Registry> {
1025 self.registry.clone()
1026 }
1027
1028 pub fn set_process_id(&mut self, process_id: ResourceId) -> Result<(), RegistryError> {
1033 self.with_instance_state(|state| state.process_id = Some(process_id))
1034 .ok_or(RegistryError::MissingInstance)?;
1035 self.registry
1036 .set_instance_process(self.instance_id, process_id)
1037 }
1038
1039 fn process_id(&self) -> Result<Option<ResourceId>, RegistryError> {
1040 self.with_instance_state(|state| state.process_id)
1041 .ok_or(RegistryError::MissingInstance)
1042 }
1043
1044 pub fn grant_session_resource(
1046 &self,
1047 session_slot: usize,
1048 capability: Capability,
1049 resource: ResourceId,
1050 ) -> Result<bool, KernelError> {
1051 self.with::<Session, _>(session_slot, |session| {
1052 session.grant_resource(capability, resource)
1053 })
1054 .ok_or(KernelError::InvalidHandle)
1055 }
1056
1057 pub fn revoke_session_resource(
1059 &self,
1060 session_slot: usize,
1061 capability: Capability,
1062 resource: ResourceId,
1063 ) -> Result<Result<bool, SessionError>, KernelError> {
1064 self.with::<Session, _>(session_slot, |session| {
1065 session.revoke_resource(capability, resource)
1066 })
1067 .ok_or(KernelError::InvalidHandle)
1068 }
1069
1070 pub fn insert_future(
1072 &mut self,
1073 state: Arc<FutureSharedState<GuestResult<Vec<u8>>>>,
1074 ) -> Result<usize, RegistryError> {
1075 let owner = self.process_id()?;
1076 let entry = self.registry.add(state, owner, ResourceType::Future)?;
1077 let handle = self.insert_future_handle(entry.0)?;
1078 Ok(handle)
1079 }
1080
1081 pub(crate) fn future_state(&self, handle: usize) -> Option<GuestFuture> {
1083 let resource_id = self.resolve_future_handle(handle)?;
1084 self.registry.with(
1085 ResourceHandle::new(resource_id),
1086 |state: &mut GuestFuture| Arc::clone(state),
1087 )
1088 }
1089
1090 pub fn remove_future(&mut self, handle: usize) -> Option<GuestFuture> {
1092 let resource_id = self.remove_future_handle(handle)?;
1093 self.registry
1094 .remove(ResourceHandle::<GuestFuture>::new(resource_id))
1095 }
1096}
1097
1098impl InstanceRegistrar {
1099 fn with_instance_state<R>(&self, f: impl FnOnce(&mut InstanceState) -> R) -> Option<R> {
1100 self.registry.with(ResourceHandle::new(self.instance_id), f)
1101 }
1102
1103 fn process_id(&self) -> Result<Option<ResourceId>, RegistryError> {
1104 self.with_instance_state(|state| state.process_id)
1105 .ok_or(RegistryError::MissingInstance)
1106 }
1107
1108 fn insert_instance_handle(&self, resource_id: ResourceId) -> Result<usize, RegistryError> {
1109 let mut handles = self
1110 .registry
1111 .handles
1112 .lock()
1113 .map_err(|_| RegistryError::LockPoisoned)?;
1114 Ok(handles.insert_instance(self.instance_id, resource_id))
1115 }
1116
1117 fn resolve_instance_handle(&self, handle: usize) -> Option<ResourceId> {
1118 let handles = self.registry.handles.lock().ok()?;
1119 handles.resolve_instance(self.instance_id, handle)
1120 }
1121
1122 pub fn insert<T: Send + 'static>(
1124 &self,
1125 entry: T,
1126 owner: Option<ResourceId>,
1127 kind: ResourceType,
1128 ) -> Result<usize, RegistryError> {
1129 let owner = self.process_id()?.or(owner);
1130 let entry = self.registry.add(entry, owner, kind)?;
1131 let resource_id = entry.0;
1132 let slot = self.insert_instance_handle(resource_id)?;
1133 self.registry.record_guest_slot(resource_id, slot);
1134 Ok(slot)
1135 }
1136
1137 pub fn insert_id(&self, id: ResourceId) -> Result<usize, RegistryError> {
1139 let slot = self.insert_instance_handle(id)?;
1140 self.registry.record_guest_slot(id, slot);
1141 Ok(slot)
1142 }
1143
1144 pub fn entry(&self, idx: usize) -> Option<ResourceId> {
1146 self.resolve_instance_handle(idx)
1147 }
1148}
1149
1150impl Drop for InstanceRegistry {
1151 fn drop(&mut self) {
1152 if let Some(mb) = self.mailbox() {
1153 mb.close();
1154 }
1155 self.registry.discard(self.instance_id);
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use super::*;
1162 use std::sync::Arc;
1163
1164 #[test]
1165 fn detach_slot_returns_resource_id_without_dropping() {
1166 let registry = Registry::new();
1167 let resource = registry
1168 .add(5u32, None, ResourceType::Other)
1169 .expect("insert resource");
1170 let id = resource.into_id();
1171
1172 let mut instance = registry.instance().expect("instance registry");
1173 let slot = instance.insert_id(id).expect("insert id");
1174 let detached = instance.detach_slot(slot).expect("detach handle");
1175 assert_eq!(detached, id);
1176
1177 let value = registry
1178 .with(ResourceHandle::<u32>::new(detached), |value| *value)
1179 .expect("resource present");
1180 assert_eq!(value, 5);
1181 }
1182
1183 #[test]
1184 fn shared_handle_is_stable_and_cleared_on_remove() {
1185 let registry = Registry::new();
1186 let resource = registry
1187 .add(10u32, None, ResourceType::Other)
1188 .expect("insert resource");
1189 let id = resource.into_id();
1190
1191 let handle_a = registry.share_handle(id).expect("share handle");
1192 let handle_b = registry.share_handle(id).expect("share handle");
1193 assert_eq!(handle_a, handle_b);
1194
1195 let removed = registry.remove(ResourceHandle::<u32>::new(id));
1196 assert_eq!(removed, Some(10));
1197
1198 assert!(registry.resolve_shared(handle_a).is_none());
1199 assert!(registry.shared_handle(id).is_none());
1200 }
1201
1202 #[test]
1203 fn instance_process_relation_is_recorded() {
1204 let registry = Registry::new();
1205 let process = registry
1206 .add((), None, ResourceType::Process)
1207 .expect("insert process");
1208 let process_id = process.into_id();
1209
1210 let mut instance = registry.instance().expect("instance registry");
1211 let instance_id = instance.instance_id;
1212 instance.set_process_id(process_id).expect("set process id");
1213
1214 assert_eq!(registry.instance_process(instance_id), Some(process_id));
1215 assert_eq!(registry.process_instance(process_id), Some(instance_id));
1216 assert_eq!(registry.owner(instance_id), Some(process_id));
1217 }
1218
1219 #[test]
1220 fn parent_child_relation_roundtrip() {
1221 let registry = Registry::new();
1222 let parent = registry
1223 .add((), None, ResourceType::Other)
1224 .expect("insert parent")
1225 .into_id();
1226 let child = registry
1227 .add((), None, ResourceType::Other)
1228 .expect("insert child")
1229 .into_id();
1230
1231 registry.record_parent(child, parent);
1232 assert_eq!(registry.parent(child), Some(parent));
1233 assert!(registry.children(parent).contains(&child));
1234
1235 registry.discard(child);
1236 assert!(!registry.children(parent).contains(&child));
1237 }
1238
1239 #[test]
1240 fn owned_resources_updates_on_remove() {
1241 let registry = Registry::new();
1242 let owner = registry
1243 .add((), None, ResourceType::Other)
1244 .expect("insert owner")
1245 .into_id();
1246 let first = registry
1247 .add(5u32, Some(owner), ResourceType::Other)
1248 .expect("insert owned")
1249 .into_id();
1250 let second = registry
1251 .add(6u64, Some(owner), ResourceType::Other)
1252 .expect("insert owned")
1253 .into_id();
1254
1255 let owned = registry.owned_resources(owner);
1256 assert!(owned.contains(&first));
1257 assert!(owned.contains(&second));
1258
1259 registry.remove(ResourceHandle::<u32>::new(first));
1260 let owned = registry.owned_resources(owner);
1261 assert!(!owned.contains(&first));
1262 assert!(owned.contains(&second));
1263 }
1264
1265 #[test]
1266 fn future_handle_roundtrip() {
1267 let registry = Registry::new();
1268 let mut instance = registry.instance().expect("instance registry");
1269 let state = FutureSharedState::<GuestResult<Vec<u8>>>::new();
1270 let handle = instance
1271 .insert_future(Arc::clone(&state))
1272 .expect("insert future");
1273
1274 let resolved = instance.future_state(handle).expect("future state");
1275 assert!(Arc::ptr_eq(&state, &resolved));
1276
1277 let removed = instance.remove_future(handle).expect("remove future");
1278 assert!(Arc::ptr_eq(&state, &removed));
1279 assert!(instance.future_state(handle).is_none());
1280 }
1281
1282 #[test]
1283 fn instance_handle_reuse() {
1284 let registry = Registry::new();
1285 let mut instance = registry.instance().expect("instance registry");
1286 let _slot_a = instance
1287 .insert(1u32, None, ResourceType::Other)
1288 .expect("insert resource");
1289 let slot_b = instance
1290 .insert(2u32, None, ResourceType::Other)
1291 .expect("insert resource");
1292 let removed = instance.remove::<u32>(slot_b).expect("remove resource");
1293 assert_eq!(removed, 2);
1294
1295 let slot_c = instance
1296 .insert(3u32, None, ResourceType::Other)
1297 .expect("insert resource");
1298 assert_eq!(slot_c, slot_b);
1299 }
1300
1301 #[test]
1302 fn registrar_inserts_into_instance_table_and_sets_owner() {
1303 let registry = Registry::new();
1304 let process = registry
1305 .add((), None, ResourceType::Process)
1306 .expect("insert process");
1307 let process_id = process.into_id();
1308
1309 let mut instance = registry.instance().expect("instance registry");
1310 instance.set_process_id(process_id).expect("set process id");
1311 let registrar = instance.registrar();
1312
1313 let slot = registrar
1314 .insert(42u32, None, ResourceType::Other)
1315 .expect("registrar insert");
1316 let resource_id = instance.entry(slot).expect("entry present");
1317 let value = registry
1318 .with(ResourceHandle::<u32>::new(resource_id), |value| *value)
1319 .expect("resource present");
1320 assert_eq!(value, 42);
1321 assert_eq!(registry.owner(resource_id), Some(process_id));
1322 }
1323}