Skip to content

Commit

Permalink
fix(cndrv): 为 RawContainer 增加 Unpin 约束以保证 transmute_copy 的安全性,并添加说明文档。
Browse files Browse the repository at this point in the history
Signed-off-by: YdrMaster <ydrml@hotmail.com>
  • Loading branch information
YdrMaster committed Jun 30, 2024
1 parent cd7a09e commit 27c2693
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
2 changes: 1 addition & 1 deletion cndrv/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cndrv"
description = "Safe Cambricon driver API."
version = "0.1.0"
version = "0.1.1"
edition = "2021"
authors = ["YdrMaster <ydrml@hotmail.com>"]
repository = "https://github.com/InfiniTensor/cndrv.git"
Expand Down
12 changes: 6 additions & 6 deletions cndrv/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl CurrentCtx {
cndrv!(cnCtxSync());
}

/// 如果存在当前上下文,在当前上下文上执行依赖上下文的操作。
/// Applies `f` to current context if it exists, otherwise returns `Err(NoCtxError)`.
#[inline]
pub fn apply_current<T>(f: impl FnOnce(&Self) -> T) -> Result<T, NoCtxError> {
let mut raw = null_mut();
Expand All @@ -123,11 +123,11 @@ impl CurrentCtx {
}
}

/// 直接指定当前上下文,并执行依赖上下文的操作。
/// Designates `raw` as the current context without checking, then applies `f` to the context.
///
/// # Safety
///
/// The `raw` context must be the current pushed context.
/// The `raw` context must be the current pushed context on this thread.
#[inline]
pub unsafe fn apply_current_unchecked<T>(raw: CNcontext, f: impl FnOnce(&Self) -> T) -> T {
f(&Self(raw))
Expand All @@ -137,20 +137,20 @@ impl CurrentCtx {
///
/// # Safety
///
/// The `raw` context must be the current pushed context.
/// The `raw` context must be the current pushed context on this thread.
/// Generally, this method only used for [`RawContainer::ctx`] with limited lifetime.
#[inline]
pub unsafe fn from_raw(raw: &CNcontext) -> &Self {
&*(raw as *const _ as *const _)
}

/// Wrap a raw object in a `RawContainer`.
/// Wraps a raw object in a `RawContainer`.
///
/// # Safety
///
/// The raw object must be created in this [`Context`].
#[inline]
pub unsafe fn wrap_raw<T>(&self, raw: T) -> RawContainer<T> {
pub unsafe fn wrap_raw<T: Unpin>(&self, raw: T) -> RawContainer<T> {
RawContainer { ctx: self.0, raw }
}
}
Expand Down
36 changes: 34 additions & 2 deletions cndrv/src/spore.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
use crate::{bindings::CNcontext, CurrentCtx};
//! 资源-孢子这一对抽象保证了基于上下文的驱动设计的安全性。
//!
//! 由于加速硬件与 CPU 是异构异步的,驱动引入了硬件上下文的概念,代表某个加速硬件上的一系列资源。
//! 所有申请、释放加速器资源(包括存储空间、算力、调度能力等)的操作都需要在某个硬件上下文中进行。
//! 同一个资源只能释放回申请它的上下文,不能串台。
//!
//! 在 ABI 中,这些限制需要程序员人为保证,对于包含多个上下文的应用程序来说,上下文管理非常难。
//! 因此,cndrv crate 提出资源-孢子这一对抽象封装上下文上的资源,并借助编译器规则和运行时检查保证安全性。
//!
//! 资源-孢子的抽象由两个 trait 组成:
//!
//! - [`ContextResource`] 即上下文资源。
//! 这个 trait 将资源的生命周期与上下文绑定,以保证资源的申请和释放在同一个上下文中完成。
//! 处于上下文资源状态的资源对象可以参与相应的功能。例如,处于上下文资源状态的存储空间可以读写。
//! 但是业务逻辑中,不可避免地会出现需要暂时切换当前上下文而不释放资源的情况,
//! 因此资源提供 [`sporulate`](ContextResource::sporulate) 方法将资源转换为孢子。
//! - [`ContextSpore`] 即上下文孢子。
//! 这个 trait 移除上下文资源的生命周期约束,从而允许在上下文被换出时暂时保持资源存在。
//! 但处于上下文孢子状态的资源通常不再允许参与相应的功能。
//! 只有当申请这些资源的上下文被换回,并在上下文上将孢子恢复为资源后才能继续发挥作用。
//! 上下文孢子提供 [`sprout`](ContextSpore::sprout) 方法将孢子转换为资源,
//! 以及 [`sprout_ref`](ContextSpore::sprout_ref) 和 [`sprout_mut`](ContextSpore::sprout_mut) 方法获取资源的不可变和可变引用。
//! 这些方法将引入运行时检查以保证孢子在正确的上下文上复原。
//!
//! [`spore_convention`] 宏提供了基于 [`RawContainer`] 类型实现的资源-孢子对的标准版本。
use crate::{bindings::CNcontext, CurrentCtx};

pub trait ContextResource<'ctx> {
type Spore: ContextSpore<Resource<'ctx> = Self>;
Expand Down Expand Up @@ -28,7 +54,7 @@ macro_rules! spore_convention {
};
}

pub struct RawContainer<T> {
pub struct RawContainer<T: Unpin> {
pub ctx: CNcontext,
pub raw: T,
}
Expand Down Expand Up @@ -62,6 +88,8 @@ macro_rules! impl_spore {
assert_eq!(self.0.ctx, unsafe {
<$crate::CurrentCtx as $crate::AsRaw>::as_raw(ctx)
});
// Safety: `transmute_copy` + `forget` 是手工实现移动语义。
// `RawContainer`` 具有 `Unpin` 保证它的安全性。
let ans = unsafe { std::mem::transmute_copy(&self.0) };
std::mem::forget(self);
ans
Expand All @@ -72,6 +100,7 @@ macro_rules! impl_spore {
assert_eq!(self.0.ctx, unsafe {
<$crate::CurrentCtx as $crate::AsRaw>::as_raw(ctx)
});
// Safety: 资源以引用的形式返回,因此在使用完成后不会释放。
unsafe { std::mem::transmute(&self.0) }
}

Expand All @@ -83,6 +112,7 @@ macro_rules! impl_spore {
assert_eq!(self.0.ctx, unsafe {
<$crate::CurrentCtx as $crate::AsRaw>::as_raw(ctx)
});
// Safety: 资源以可变引用的形式返回,因此在使用完成后不会释放。
unsafe { std::mem::transmute(&mut self.0) }
}
}
Expand All @@ -92,6 +122,8 @@ macro_rules! impl_spore {

#[inline]
fn sporulate(self) -> Self::Spore {
// Safety: `transmute_copy` + `forget` 是手工实现移动语义。
// `RawContainer`` 具有 `Unpin` 保证它的安全性。
let s = unsafe { std::mem::transmute_copy(&self.0) };
std::mem::forget(self);
$spore(s)
Expand Down

0 comments on commit 27c2693

Please sign in to comment.