Introduced dylib extension format, cleared up shutdown sequence

This commit is contained in:
2026-01-17 00:23:35 +01:00
parent 1a7230ce9b
commit 6a3c1d5917
18 changed files with 214 additions and 113 deletions

View File

@@ -1,14 +1,15 @@
use std::mem;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use orchid_api::binary::{FutureContextVT, FutureVT, OwnedWakerVT, UnitPoll};
use orchid_api::binary::{FutureBin, FutureContextBin, OwnedWakerBin, UnitPoll};
type WideBox = Box<dyn Future<Output = ()>>;
static OWNED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|data| {
let data = unsafe { Rc::<OwnedWakerVT>::from_raw(data as *const _) };
let data = unsafe { Rc::<OwnedWakerBin>::from_raw(data as *const _) };
let val = RawWaker::new(Rc::into_raw(data.clone()) as *const (), &OWNED_VTABLE);
// Clone must create a duplicate of the Rc, so it has to be un-leaked, cloned,
// then leaked again.
@@ -18,30 +19,32 @@ static OWNED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|data| {
// Wake must awaken the task and then clean up the state, so the waker must be
// un-leaked
let data = unsafe { Rc::<OwnedWakerVT>::from_raw(data as *const _) };
let data = unsafe { Rc::<OwnedWakerBin>::from_raw(data as *const _) };
(data.wake)(data.data);
mem::drop(data);
},
|data| {
// Wake-by-ref must awaken the task while preserving the future, so the Rc is
// untouched
let data = unsafe { (data as *const OwnedWakerVT).as_ref() }.unwrap();
let data = unsafe { (data as *const OwnedWakerBin).as_ref() }.unwrap();
(data.wake_ref)(data.data);
},
|data| {
// Drop must clean up the state, so the waker must be un-leaked
let data = unsafe { Rc::<OwnedWakerVT>::from_raw(data as *const _) };
let data = unsafe { Rc::<OwnedWakerBin>::from_raw(data as *const _) };
(data.drop)(data.data);
mem::drop(data);
},
);
struct BorrowedWakerData<'a> {
go_around: &'a mut bool,
cx: FutureContextVT,
cx: FutureContextBin,
}
static BORROWED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|data| {
let data = unsafe { (data as *mut BorrowedWakerData).as_mut() }.unwrap();
let owned_data = Rc::<OwnedWakerVT>::new((data.cx.waker)(data.cx.data));
let owned_data = Rc::<OwnedWakerBin>::new((data.cx.waker)(data.cx.data));
RawWaker::new(Rc::into_raw(owned_data) as *const (), &OWNED_VTABLE)
},
|data| *unsafe { (data as *mut BorrowedWakerData).as_mut() }.unwrap().go_around = true,
@@ -51,13 +54,13 @@ static BORROWED_VTABLE: RawWakerVTable = RawWakerVTable::new(
/// Convert a future to a binary-compatible format that can be sent across
/// dynamic library boundaries
pub fn future_to_vt<Fut: Future<Output = ()> + 'static>(fut: Fut) -> FutureVT {
pub fn future_to_vt<Fut: Future<Output = ()> + 'static>(fut: Fut) -> FutureBin {
let wide_box = Box::new(fut) as WideBox;
let data = Box::into_raw(Box::new(wide_box));
extern "C" fn drop(raw: *const ()) {
std::mem::drop(unsafe { Box::<WideBox>::from_raw(raw as *mut _) })
mem::drop(unsafe { Box::<WideBox>::from_raw(raw as *mut _) })
}
extern "C" fn poll(raw: *const (), cx: FutureContextVT) -> UnitPoll {
extern "C" fn poll(raw: *const (), cx: FutureContextBin) -> UnitPoll {
let mut this = unsafe { Pin::new_unchecked(&mut **(raw as *mut WideBox).as_mut().unwrap()) };
loop {
let mut go_around = false;
@@ -77,22 +80,22 @@ pub fn future_to_vt<Fut: Future<Output = ()> + 'static>(fut: Fut) -> FutureVT {
}
}
}
FutureVT { data: data as *const _, drop, poll }
FutureBin { data: data as *const _, drop, poll }
}
struct VirtualFuture {
vt: FutureVT,
vt: FutureBin,
}
impl Unpin for VirtualFuture {}
impl Future for VirtualFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
extern "C" fn waker(raw: *const ()) -> OwnedWakerVT {
extern "C" fn waker(raw: *const ()) -> OwnedWakerBin {
let waker = unsafe { (raw as *mut Context).as_mut() }.unwrap().waker().clone();
let data = Box::into_raw(Box::<Waker>::new(waker)) as *const ();
return OwnedWakerVT { data, drop, wake, wake_ref };
return OwnedWakerBin { data, drop, wake, wake_ref };
extern "C" fn drop(raw: *const ()) {
std::mem::drop(unsafe { Box::<Waker>::from_raw(raw as *mut Waker) })
mem::drop(unsafe { Box::<Waker>::from_raw(raw as *mut Waker) })
}
extern "C" fn wake(raw: *const ()) {
unsafe { Box::<Waker>::from_raw(raw as *mut Waker) }.wake();
@@ -101,7 +104,7 @@ impl Future for VirtualFuture {
unsafe { (raw as *mut Waker).as_mut() }.unwrap().wake_by_ref();
}
}
let cx = FutureContextVT { data: cx as *mut Context as *const (), waker };
let cx = FutureContextBin { data: cx as *mut Context as *const (), waker };
let result = (self.vt.poll)(self.vt.data, cx);
match result {
UnitPoll::Pending => Poll::Pending,
@@ -115,4 +118,4 @@ impl Drop for VirtualFuture {
/// Receive a future sent across dynamic library boundaries and convert it into
/// an owned object
pub fn vt_to_future(vt: FutureVT) -> impl Future<Output = ()> { VirtualFuture { vt } }
pub fn vt_to_future(vt: FutureBin) -> impl Future<Output = ()> { VirtualFuture { vt } }