From 5cf057eecec75092e5c56dba2bcbd47e150c3016 Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Tue, 23 Nov 2021 19:21:45 +0100 Subject: [PATCH 1/5] Support for abi_stable --- Cargo.toml | 5 +++++ src/lib.rs | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc8de54..110e0fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,11 @@ exclude = ["/link_tests"] rust-version = "1.49" # 1.48 doesn't support `ManuallyDrop` in union. # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +abi_stable = { version = "0.10", default-features = false, optional = true } [dev-dependencies] tokio = { version = "1.4.0", features = ["macros", "rt-multi-thread", "sync", "time"] } + +[features] +sabi = ["abi_stable"] diff --git a/src/lib.rs b/src/lib.rs index ca90ee7..525cf9c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,12 +85,11 @@ use std::{ /// Every non-compatible ABI change will increase this number. pub const ABI_VERSION: u32 = 2; -type PollFn = unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll; - /// The FFI compatible [`std::task::Poll`] /// /// [`std::task::Poll`]: std::task::Poll #[repr(C, u8)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] pub enum FfiPoll { /// Represents that a value is immediately ready. Ready(T), @@ -131,9 +130,9 @@ impl Drop for DropBomb { pub struct FfiContext<'a> { /// This waker is passed as borrow semantic. /// The external fn must not `drop` or `wake` it. - waker_ref: *const FfiWaker, + waker_ref: *const FfiWakerBase, /// Lets the compiler know that this references the FfiWaker and should not outlive it - phantom: PhantomData<&'a FfiWaker>, + phantom: PhantomData<&'a Waker>, } impl<'a> FfiContext<'a> { @@ -141,7 +140,7 @@ impl<'a> FfiContext<'a> { /// sane behavior as a Waker. `with_context` relies on this to be safe. unsafe fn new(waker: &'a FfiWaker) -> Self { Self { - waker_ref: waker as *const _ as *const FfiWaker, + waker_ref: waker as *const FfiWaker as *const FfiWakerBase, phantom: PhantomData, } } @@ -287,6 +286,13 @@ impl<'a> ContextExt for Context<'a> { } // Inspired by Gary Guo (github.com/nbdd0121) +// +// The base is what can be accessed through FFI, and the regular struct contains +// internal data (the original waker). +#[repr(C)] +struct FfiWakerBase { + vtable: &'static FfiWakerVTable, +} #[repr(C)] struct FfiWaker { vtable: &'static FfiWakerVTable, @@ -313,6 +319,7 @@ struct FfiWakerVTable { /// /// See [module level documentation](index.html) for more details. #[repr(transparent)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] pub struct BorrowingFfiFuture<'a, T>(LocalBorrowingFfiFuture<'a, T>); /// The FFI compatible future type with `Send` bound and `'static` lifetime, @@ -427,9 +434,10 @@ impl Future for BorrowingFfiFuture<'_, T> { /// /// See [module level documentation](index.html) for more details. #[repr(C)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] pub struct LocalBorrowingFfiFuture<'a, T> { fut_ptr: *mut (), - poll_fn: PollFn, + poll_fn: unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll, drop_fn: unsafe extern "C" fn(*mut ()), _marker: PhantomData<&'a ()>, } From d6ba60676a37dad7d9352c9210539b1572eea63f Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Tue, 23 Nov 2021 19:33:42 +0100 Subject: [PATCH 2/5] Fix compilation --- src/lib.rs | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 525cf9c..906d8c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,12 +127,13 @@ impl Drop for DropBomb { /// /// [`std::task::Context`]: std::task::Context #[repr(C)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] pub struct FfiContext<'a> { /// This waker is passed as borrow semantic. /// The external fn must not `drop` or `wake` it. waker_ref: *const FfiWakerBase, /// Lets the compiler know that this references the FfiWaker and should not outlive it - phantom: PhantomData<&'a Waker>, + phantom: PhantomData<&'a FfiWakerBase>, } impl<'a> FfiContext<'a> { @@ -154,20 +155,20 @@ impl<'a> FfiContext<'a> { static RUST_WAKER_VTABLE: RawWakerVTable = { unsafe fn clone(data: *const ()) -> RawWaker { let waker = data.cast::(); - let cloned = ((*waker).vtable.clone)(waker); + let cloned = ((*waker).vtable.clone)(waker.cast()); RawWaker::new(cloned.cast(), &RUST_WAKER_VTABLE) } unsafe fn wake(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.wake)(waker); + ((*waker).vtable.wake)(waker.cast()); } unsafe fn wake_by_ref(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.wake_by_ref)(waker); + ((*waker).vtable.wake_by_ref)(waker.cast()); } unsafe fn drop(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.drop)(waker); + ((*waker).vtable.drop)(waker.cast()); } RawWakerVTable::new(clone, wake, wake_by_ref, drop) }; @@ -200,8 +201,9 @@ pub trait ContextExt { impl<'a> ContextExt for Context<'a> { fn with_ffi_context T>(&mut self, closure: F) -> T { static C_WAKER_VTABLE_OWNED: FfiWakerVTable = { - unsafe extern "C" fn clone(data: *const FfiWaker) -> *const FfiWaker { + unsafe extern "C" fn clone(data: *const FfiWakerBase) -> *const FfiWakerBase { DropBomb::with("Waker::clone", || { + let data = data as *mut FfiWaker; let waker: Waker = (*(*data).waker.owned).clone(); Box::into_raw(Box::new(FfiWaker { vtable: &C_WAKER_VTABLE_OWNED, @@ -214,19 +216,20 @@ impl<'a> ContextExt for Context<'a> { } // In this case, we must own `data`. This can only happen when the `data` pointer is returned from `clone`. // Thus the it is `Box`. - unsafe extern "C" fn wake(data: *const FfiWaker) { + unsafe extern "C" fn wake(data: *const FfiWakerBase) { DropBomb::with("Waker::wake", || { let b = Box::from_raw(data as *mut FfiWaker); ManuallyDrop::into_inner(b.waker.owned).wake(); }) } - unsafe extern "C" fn wake_by_ref(data: *const FfiWaker) { + unsafe extern "C" fn wake_by_ref(data: *const FfiWakerBase) { DropBomb::with("Waker::wake_by_ref", || { + let data = data as *mut FfiWaker; (*data).waker.owned.wake_by_ref(); }) } // Same as `wake`. - unsafe extern "C" fn drop(data: *const FfiWaker) { + unsafe extern "C" fn drop(data: *const FfiWakerBase) { DropBomb::with("Waker::drop", || { let mut b = Box::from_raw(data as *mut FfiWaker); ManuallyDrop::drop(&mut b.waker.owned); @@ -242,8 +245,9 @@ impl<'a> ContextExt for Context<'a> { }; static C_WAKER_VTABLE_REF: FfiWakerVTable = { - unsafe extern "C" fn clone(data: *const FfiWaker) -> *const FfiWaker { + unsafe extern "C" fn clone(data: *const FfiWakerBase) -> *const FfiWakerBase { DropBomb::with("Waker::clone", || { + let data = data as *mut FfiWaker; let waker: Waker = (*(*data).waker.reference).clone(); Box::into_raw(Box::new(FfiWaker { vtable: &C_WAKER_VTABLE_OWNED, @@ -254,12 +258,13 @@ impl<'a> ContextExt for Context<'a> { .cast() }) } - unsafe extern "C" fn wake_by_ref(data: *const FfiWaker) { + unsafe extern "C" fn wake_by_ref(data: *const FfiWakerBase) { DropBomb::with("Waker::wake_by_ref", || { + let data = data as *mut FfiWaker; (*(*data).waker.reference).wake_by_ref(); }) } - unsafe extern "C" fn unreachable(_: *const FfiWaker) { + unsafe extern "C" fn unreachable(_: *const FfiWakerBase) { std::process::abort(); } FfiWakerVTable { @@ -290,8 +295,9 @@ impl<'a> ContextExt for Context<'a> { // The base is what can be accessed through FFI, and the regular struct contains // internal data (the original waker). #[repr(C)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] struct FfiWakerBase { - vtable: &'static FfiWakerVTable, + vtable: *const FfiWakerVTable, } #[repr(C)] struct FfiWaker { @@ -308,11 +314,12 @@ union WakerUnion { #[derive(PartialEq, Eq, Hash, Clone, Copy)] #[repr(C)] +#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] struct FfiWakerVTable { - clone: unsafe extern "C" fn(*const FfiWaker) -> *const FfiWaker, - wake: unsafe extern "C" fn(*const FfiWaker), - wake_by_ref: unsafe extern "C" fn(*const FfiWaker), - drop: unsafe extern "C" fn(*const FfiWaker), + clone: unsafe extern "C" fn(*const FfiWakerBase) -> *const FfiWakerBase, + wake: unsafe extern "C" fn(*const FfiWakerBase), + wake_by_ref: unsafe extern "C" fn(*const FfiWakerBase), + drop: unsafe extern "C" fn(*const FfiWakerBase), } /// The FFI compatible future type with `Send` bound. From f066b51241ebdf6e95dbf59cf13ec187476dc3a3 Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Tue, 23 Nov 2021 20:33:16 +0100 Subject: [PATCH 3/5] Inheritance-like structure --- src/lib.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 906d8c5..3b2fdb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,20 +155,20 @@ impl<'a> FfiContext<'a> { static RUST_WAKER_VTABLE: RawWakerVTable = { unsafe fn clone(data: *const ()) -> RawWaker { let waker = data.cast::(); - let cloned = ((*waker).vtable.clone)(waker.cast()); + let cloned = ((*(*waker).base.vtable).clone)(waker.cast()); RawWaker::new(cloned.cast(), &RUST_WAKER_VTABLE) } unsafe fn wake(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.wake)(waker.cast()); + ((*(*waker).base.vtable).wake)(waker.cast()); } unsafe fn wake_by_ref(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.wake_by_ref)(waker.cast()); + ((*(*waker).base.vtable).wake_by_ref)(waker.cast()); } unsafe fn drop(data: *const ()) { let waker = data.cast::(); - ((*waker).vtable.drop)(waker.cast()); + ((*(*waker).base.vtable).drop)(waker.cast()); } RawWakerVTable::new(clone, wake, wake_by_ref, drop) }; @@ -206,7 +206,9 @@ impl<'a> ContextExt for Context<'a> { let data = data as *mut FfiWaker; let waker: Waker = (*(*data).waker.owned).clone(); Box::into_raw(Box::new(FfiWaker { - vtable: &C_WAKER_VTABLE_OWNED, + base: FfiWakerBase { + vtable: &C_WAKER_VTABLE_OWNED, + }, waker: WakerUnion { owned: ManuallyDrop::new(waker), }, @@ -250,7 +252,9 @@ impl<'a> ContextExt for Context<'a> { let data = data as *mut FfiWaker; let waker: Waker = (*(*data).waker.reference).clone(); Box::into_raw(Box::new(FfiWaker { - vtable: &C_WAKER_VTABLE_OWNED, + base: FfiWakerBase { + vtable: &C_WAKER_VTABLE_OWNED, + }, waker: WakerUnion { owned: ManuallyDrop::new(waker), }, @@ -276,7 +280,9 @@ impl<'a> ContextExt for Context<'a> { }; let waker = FfiWaker { - vtable: &C_WAKER_VTABLE_REF, + base: FfiWakerBase { + vtable: &C_WAKER_VTABLE_REF, + }, waker: WakerUnion { reference: self.waker(), }, @@ -301,7 +307,7 @@ struct FfiWakerBase { } #[repr(C)] struct FfiWaker { - vtable: &'static FfiWakerVTable, + base: FfiWakerBase, waker: WakerUnion, } From dd0e276a302d114af7daab4fcbe758ccdb2dcb70 Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Mon, 17 Jan 2022 11:46:14 +0000 Subject: [PATCH 4/5] Apply suggestions in PR --- src/lib.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3b2fdb3..841f880 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ pub const ABI_VERSION: u32 = 2; /// /// [`std::task::Poll`]: std::task::Poll #[repr(C, u8)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] pub enum FfiPoll { /// Represents that a value is immediately ready. Ready(T), @@ -127,13 +127,13 @@ impl Drop for DropBomb { /// /// [`std::task::Context`]: std::task::Context #[repr(C)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] pub struct FfiContext<'a> { /// This waker is passed as borrow semantic. /// The external fn must not `drop` or `wake` it. - waker_ref: *const FfiWakerBase, + waker: *const FfiWakerBase, /// Lets the compiler know that this references the FfiWaker and should not outlive it - phantom: PhantomData<&'a FfiWakerBase>, + _marker: PhantomData<&'a FfiWakerBase>, } impl<'a> FfiContext<'a> { @@ -141,8 +141,8 @@ impl<'a> FfiContext<'a> { /// sane behavior as a Waker. `with_context` relies on this to be safe. unsafe fn new(waker: &'a FfiWaker) -> Self { Self { - waker_ref: waker as *const FfiWaker as *const FfiWakerBase, - phantom: PhantomData, + waker: waker as *const FfiWaker as *const FfiWakerBase, + _marker: PhantomData, } } @@ -173,12 +173,12 @@ impl<'a> FfiContext<'a> { RawWakerVTable::new(clone, wake, wake_by_ref, drop) }; - // SAFETY: `waker_ref`'s vtable functions must have behavior, this is the contract of + // SAFETY: `waker`'s vtable functions must have behavior, this is the contract of // `FfiContext::new`. let waker = unsafe { - // The `waker_ref` is borrowed from external context. We must not call drop on it. + // The waker reference is borrowed from external context. We must not call drop on it. ManuallyDrop::new(Waker::from_raw(RawWaker::new( - self.waker_ref.cast(), + self.waker.cast(), &RUST_WAKER_VTABLE, ))) }; @@ -301,7 +301,7 @@ impl<'a> ContextExt for Context<'a> { // The base is what can be accessed through FFI, and the regular struct contains // internal data (the original waker). #[repr(C)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] struct FfiWakerBase { vtable: *const FfiWakerVTable, } @@ -320,7 +320,7 @@ union WakerUnion { #[derive(PartialEq, Eq, Hash, Clone, Copy)] #[repr(C)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] struct FfiWakerVTable { clone: unsafe extern "C" fn(*const FfiWakerBase) -> *const FfiWakerBase, wake: unsafe extern "C" fn(*const FfiWakerBase), @@ -332,7 +332,7 @@ struct FfiWakerVTable { /// /// See [module level documentation](index.html) for more details. #[repr(transparent)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] pub struct BorrowingFfiFuture<'a, T>(LocalBorrowingFfiFuture<'a, T>); /// The FFI compatible future type with `Send` bound and `'static` lifetime, @@ -447,7 +447,7 @@ impl Future for BorrowingFfiFuture<'_, T> { /// /// See [module level documentation](index.html) for more details. #[repr(C)] -#[cfg_attr(feature = "sabi", derive(abi_stable::StableAbi))] +#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))] pub struct LocalBorrowingFfiFuture<'a, T> { fut_ptr: *mut (), poll_fn: unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll, From b32581868b28238aeb7d0662558aec019980292c Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Mon, 17 Jan 2022 20:51:47 +0000 Subject: [PATCH 5/5] Forgot to remove the sabi feature --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 110e0fa..90489fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,3 @@ abi_stable = { version = "0.10", default-features = false, optional = true } [dev-dependencies] tokio = { version = "1.4.0", features = ["macros", "rt-multi-thread", "sync", "time"] } - -[features] -sabi = ["abi_stable"]