Skip to main content

kernel_api/syscall/
handle_inner.rs

1use alloc::sync::Arc;
2use core::fmt;
3use core::mem::ManuallyDrop;
4use core::sync::atomic::{AtomicI64, AtomicPtr, AtomicU64, Ordering};
5use lf_radix_tree::LockFreeRadixTreeU32L4;
6use crate::memory::EpochGuard;
7use crate::ptr::TaggedNonNull;
8use crate::syscall;
9use crate::syscall::Error;
10use crate::threading::TaskRef;
11
12/// A map of numeric identifiers to [`Handle`]s.
13// INVARIANT: `self.0` always comes from `Arc::<HandleMapInner>::into_raw`
14#[derive(Debug)]
15pub struct HandleMap(AtomicPtr<HandleMapInner>);
16
17struct HandleMapInner {
18	map: LockFreeRadixTreeU32L4<Handle>,
19	// use a u64 here so that we can detect overflow more easily
20	bump_free: AtomicU64,
21	// a value of -1 means that there are no handles in the free stack
22	// any other value is the next free handle number, which when looked
23	// up in the handle map gives, in turn, the next handle in the free stack
24	// INVARIANT: value is in -1..=u32::MAX
25	// INVARIANT: if holding value in 0..=u32::MAX, then this must point
26	//  to an existing entry in the handle map with a value as described
27	//  in the above comments
28	free_stack_top: AtomicI64,
29}
30
31impl HandleMap {
32	fn deref<'ebr>(&self, _ebr: &'ebr EpochGuard) -> &'ebr HandleMapInner {
33		let ptr = self.0.load(Ordering::Acquire).cast_const();
34		// SAFETY: `ptr` is always a valid `HandleMapInner` by invariants of `HandleMap`,
35		//  and we hold an ebr guard so the pointed to memory cannot have been dropped yet
36		unsafe { &*ptr }
37	}
38
39	pub fn clone(&self, _ebr: &EpochGuard) -> Self {
40		let ptr = self.0.load(Ordering::Acquire).cast_const();
41		// SAFETY: `ptr` is always a valid `HandleMapInner` by invariants of `HandleMap`,
42		//  and we hold an ebr guard so the pointed to memory cannot have been dropped yet
43		unsafe { Arc::increment_strong_count(ptr) };
44		Self(AtomicPtr::new(ptr.cast_mut()))
45	}
46
47	/// Creates an empty `HandleMap`.
48	///
49	/// # Examples
50	///
51	/// ```
52	/// let map = HandleMap::new();
53	/// ```
54	#[must_use]
55	pub fn new() -> Self {
56		let this = HandleMapInner {
57			map: LockFreeRadixTreeU32L4::new(),
58			bump_free: AtomicU64::new(0),
59			free_stack_top: AtomicI64::new(-1),
60		};
61		let arc = Arc::new(this);
62		Self(AtomicPtr::new(Arc::into_raw(arc).cast_mut()))
63	}
64
65	/// Adds the passed handle to the handle map and returns the position it's placed at.
66	///
67	/// No guarantees are made on what positions in the map are used.
68	///
69	/// # Errors
70	///
71	/// Returns [`Error::Overflow`] if there are no more free positions to add
72	/// the handle at.
73	pub fn push(&self, handle: Arc<Handle>, ebr: &EpochGuard) -> syscall::Result<u32> {
74		self.transfer(PoppedHandle(Arc::into_raw(handle)), ebr)
75	}
76
77	/// Adds a [`PoppedHandle`] to the handle map and returns the position it's placed at,
78	/// without incurring costs of refcount changes.
79	///
80	/// No guarantees are made on what positions in the map are used.
81	///
82	/// # Errors
83	///
84	/// Returns [`Error::Overflow`] if there are no more free positions to add
85	/// the handle at.
86	pub fn transfer(&self, handle: PoppedHandle, ebr: &EpochGuard) -> syscall::Result<u32> {
87		let this = self.deref(ebr);
88		let val = {
89			let mut stack_top = this.free_stack_top.load(Ordering::Acquire);
90			loop {
91				// -1 indicates empty free stack, other values are first value in free stack
92				// see comment on `HandleMap::free_stack_top`
93				if stack_top < 0 {
94					let val = this.bump_free.fetch_add(1, Ordering::Relaxed);
95					break u32::try_from(val).map_err(|_| {
96						this.bump_free.fetch_sub(1, Ordering::Relaxed);
97						Error::Overflow
98					})?
99				} else {
100					let val = stack_top as u32;
101					// SAFETY: invariant of `free_stack_top` that it holds existing handle
102					let next = unsafe { this.map.get(val).unwrap_unchecked() }
103						.load(Ordering::Acquire)
104						.addr();
105					match this.free_stack_top.compare_exchange_weak(
106						stack_top,
107						next as i64,
108						Ordering::AcqRel,
109						Ordering::Acquire,
110					) {
111						Ok(_) => break val,
112						Err(updated) => stack_top = updated,
113					}
114				}
115			}
116		};
117		let handle = ManuallyDrop::new(handle);
118		this.map.insert(val, handle.0.cast_mut()).expect("val from free list must be free");
119		Ok(val)
120	}
121
122	/// Returns a reference to the handle at `val`.
123	///
124	/// # Errors
125	///
126	/// Returns [`Error::InvalidHandle`] if the handle is not in the map.
127	pub fn get<'ebr>(&self, val: u32, ebr: &'ebr EpochGuard) -> syscall::Result<&'ebr Handle> {
128		let this = self.deref(ebr);
129		this.map.get(val)
130			// SAFETY: holding an EBR guard so if non-null the pointer cannot point to
131			//  a dropped Handle
132			.and_then(|ptr| unsafe { ptr.load(Ordering::Acquire).as_ref() })
133			.ok_or(Error::InvalidHandle)
134	}
135
136	/// Removes the handle at `val` from the `HandleMap`, returning a [`PoppedHandle`].
137	/// The [`PoppedHandle`] can either be directly dropped, converted into an [`Arc<Handle>`]
138	/// (incurrent refcount costs) or directly passed to [`HandleMap::transfer()`] to add it
139	/// to a different handle map without incurrent refcount costs.
140	///
141	/// # Errors
142	///
143	/// Returns [`Error::InvalidHandle`] if the handle is not in the map.
144	#[inline]
145	pub fn pop(&self, val: u32, ebr: &EpochGuard) -> syscall::Result<PoppedHandle> {
146		let this = self.deref(ebr);
147		let ptr = this.map.get(val).ok_or(Error::InvalidHandle)?;
148		let ptr = ptr.swap(core::ptr::null_mut(), Ordering::AcqRel).cast_const();
149		if ptr.is_null() { return Err(Error::InvalidHandle); }
150		Ok(PoppedHandle(ptr))
151	}
152
153	pub fn close(&self, val: u32, ebr: &EpochGuard) -> syscall::Result<()> {
154		self.pop(val, ebr).map(drop)
155	}
156
157	/// Swaps `self` to contain the mappings contained in `other`, and
158	/// returns the mappings originally contained in `self`.
159	///
160	/// <div class="warning">
161	///
162	/// This will race with any calls on `self` to `pop`, `push`, or `get`
163	/// such that changes may modify either the old or new handle map.
164	/// Therefore this method should be avoided when `self` is shared
165	/// between multiple threads and concurrently modified.
166	///
167	/// </div>
168	#[must_use]
169	pub fn swap(&self, other: Self) -> Self {
170		let mut other = ManuallyDrop::new(other);
171		let other_ptr = *other.0.get_mut();
172		let old = self.0.swap(other_ptr, Ordering::AcqRel);
173		Self(AtomicPtr::new(old))
174	}
175}
176
177impl Default for HandleMap {
178	fn default() -> Self {
179		Self::new()
180	}
181}
182
183impl Drop for HandleMap {
184	fn drop(&mut self) {
185		let inner = *self.0.get_mut();
186		crate::bridge::ebr::defer_and_cleanup(
187			// SAFETY: invariant of `self.0` that it comes from `Arc::into_raw`, and no active epoch
188			//  holds a reference to this arc anymore
189			|ptr| unsafe { drop(Arc::<HandleMapInner>::from_raw(ptr.cast_const().cast())) },
190			inner.cast(),
191		);
192	}
193}
194
195union Object {
196	oid: u32,
197	koid: TaggedNonNull<u64>,
198}
199
200unsafe impl Sync for Object {}
201unsafe impl Send for Object {}
202
203/// A handle representing a userspace resource within the kernel.
204pub struct Handle {
205	endpoint: Option<TaskRef>,
206	object: Object,
207}
208
209impl Handle {
210	/// Creates a new `Handle` object pointing to the passed server and object ID, and supporting the passed list of protocols.
211	pub fn new(endpoint: TaskRef, oid: u32) -> Arc<Self> {
212		Arc::new(Self {
213			endpoint: Some(endpoint),
214			object: Object { oid },
215		})
216	}
217
218	/// Creates a new `Handle` object pointing to the passed system service.
219	pub fn new_system(koid: TaggedNonNull<u64>) -> Arc<Self> {
220		Arc::new(Self {
221			endpoint: None,
222			object: Object { koid },
223		})
224	}
225
226	/// Returns the object ID for this handle.
227	#[inline]
228	pub fn oid(&self) -> u32 {
229		assert!(!self.is_system(), "cannot get `oid` for system handle");
230		// SAFETY: checked that `self` is not system handle
231		unsafe { self.object.oid }
232	}
233
234	/// Returns the object ID for a system handle.
235	#[inline]
236	pub fn koid(&self) -> TaggedNonNull<u64> {
237		assert!(self.is_system(), "cannot get `koid` for non-system handle");
238		// SAFETY: checked that `self` is system handle
239		unsafe { self.object.koid }
240	}
241
242	/// Returns the target task for this handle.
243	#[inline]
244	pub fn target(&self) -> TaskRef {
245		self.endpoint.expect("cannot get endpoint of system handle")
246	}
247
248	/// Returns whether the handle is backed by the kernel or a userspace service.
249	#[inline]
250	pub fn is_system(&self) -> bool {
251		self.endpoint.is_none()
252	}
253}
254
255impl fmt::Debug for Handle {
256	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257		let mut f = f.debug_struct("Handle");
258
259		if self.is_system() {
260			f.field("koid", &self.koid());
261		} else {
262			f.field("endpoint", &self.target())
263				.field("oid", &self.oid());
264		}
265
266		f.finish()
267	}
268}
269
270/// A wrapper around a [`Handle`] that has been removed from a [`HandleMap`] but not yet dropped.
271///
272/// This exists to allow a faster path when moving a handle between two maps,
273/// by delaying any refcount adjustments on a popped handle until the wrapper is
274/// dropped.
275// INVARIANT: `self.0` always comes from `Arc::<HandleMapInner>::into_raw`
276#[repr(transparent)]
277pub struct PoppedHandle(*const Handle);
278
279impl PoppedHandle {
280	#[must_use = "dropping PoppedHandle directly cleans up the contained Handle without paying refcount costs"]
281	pub fn to_arc(self) -> Arc<Handle> {
282		// SAFETY: invariant of `self.0` that it comes from `Arc::into_raw`
283		unsafe { Arc::increment_strong_count(self.0) };
284		// SAFETY: invariant of `self.0` that it comes from `Arc::into_raw`
285		unsafe { Arc::from_raw(self.0) }
286	}
287}
288
289impl Drop for PoppedHandle {
290	fn drop(&mut self) {
291		crate::bridge::ebr::defer_and_cleanup(
292			// SAFETY: invariant of `self.0` that it comes from `Arc::into_raw`, and no active epoch
293			//  holds a reference to this arc anymore
294			|ptr| unsafe { drop(Arc::<Handle>::from_raw(ptr.cast_const().cast())) },
295			self.0.cast_mut().cast(),
296		);
297	}
298}