mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Add runtime detection for shared handle misuse wrap the FFI engine handle with parking_lot::RwLock when the new contention_checks feature is enabled, surfacing a clear “handle is already in use” error instead of allowing undefined behavior keep the feature optional so no_std builds or environments that supply their own synchronization can opt out caution users that this guards the handle itself but does not make the engine’s operations globally thread-safe on its own Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
104 lines
2.9 KiB
Rust
104 lines
2.9 KiB
Rust
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
//! Abstractions over synchronization primitives used by the FFI layer.
|
|
//!
|
|
//! For `std` builds we rely on `parking_lot::RwLock` so we can detect
|
|
//! contention across threads. For `no_std` builds we fall back to
|
|
//! `RefCell`, which still lets us detect aliasing within a single thread.
|
|
|
|
#[cfg(not(feature = "std"))]
|
|
extern crate alloc;
|
|
|
|
#[cfg(all(feature = "std", feature = "contention_checks"))]
|
|
mod locking {
|
|
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
|
use std::sync::Arc;
|
|
|
|
pub(crate) type Handle<T> = Arc<RwLock<T>>;
|
|
pub(crate) type ReadGuard<'a, T> = RwLockReadGuard<'a, T>;
|
|
pub(crate) type WriteGuard<'a, T> = RwLockWriteGuard<'a, T>;
|
|
|
|
#[inline]
|
|
pub(crate) fn new_handle<T>(value: T) -> Handle<T> {
|
|
Arc::new(RwLock::new(value))
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_write<'a, T>(handle: &'a Handle<T>) -> Option<WriteGuard<'a, T>> {
|
|
handle.try_write()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_read<'a, T>(handle: &'a Handle<T>) -> Option<ReadGuard<'a, T>> {
|
|
handle.try_read()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn read<'a, T>(handle: &'a Handle<T>) -> ReadGuard<'a, T> {
|
|
handle.read()
|
|
}
|
|
}
|
|
|
|
#[cfg(all(feature = "std", not(feature = "contention_checks")))]
|
|
mod locking {
|
|
use std::cell::{Ref, RefCell, RefMut};
|
|
use std::rc::Rc;
|
|
|
|
pub(crate) type Handle<T> = Rc<RefCell<T>>;
|
|
pub(crate) type ReadGuard<'a, T> = Ref<'a, T>;
|
|
pub(crate) type WriteGuard<'a, T> = RefMut<'a, T>;
|
|
|
|
#[inline]
|
|
pub(crate) fn new_handle<T>(value: T) -> Handle<T> {
|
|
Rc::new(RefCell::new(value))
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_write<'a, T>(handle: &'a Handle<T>) -> Option<WriteGuard<'a, T>> {
|
|
handle.try_borrow_mut().ok()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_read<'a, T>(handle: &'a Handle<T>) -> Option<ReadGuard<'a, T>> {
|
|
handle.try_borrow().ok()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn read<'a, T>(handle: &'a Handle<T>) -> ReadGuard<'a, T> {
|
|
handle.borrow()
|
|
}
|
|
}
|
|
|
|
#[cfg(not(feature = "std"))]
|
|
mod locking {
|
|
use alloc::rc::Rc;
|
|
use core::cell::{Ref, RefCell, RefMut};
|
|
|
|
pub(crate) type Handle<T> = Rc<RefCell<T>>;
|
|
pub(crate) type ReadGuard<'a, T> = Ref<'a, T>;
|
|
pub(crate) type WriteGuard<'a, T> = RefMut<'a, T>;
|
|
|
|
#[inline]
|
|
pub(crate) fn new_handle<T>(value: T) -> Handle<T> {
|
|
Rc::new(RefCell::new(value))
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_write<'a, T>(handle: &'a Handle<T>) -> Option<WriteGuard<'a, T>> {
|
|
handle.try_borrow_mut().ok()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn try_read<'a, T>(handle: &'a Handle<T>) -> Option<ReadGuard<'a, T>> {
|
|
handle.try_borrow().ok()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn read<'a, T>(handle: &'a Handle<T>) -> ReadGuard<'a, T> {
|
|
handle.borrow()
|
|
}
|
|
}
|
|
|
|
pub(crate) use locking::{new_handle, read, try_read, try_write, Handle, ReadGuard, WriteGuard};
|