Unit tests pass
Fixed a nasty deadlock in reqnot
This commit is contained in:
@@ -3,13 +3,13 @@ use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
use orchid_api::binary::{FutureBin, FutureContextBin, OwnedWakerBin, UnitPoll};
|
||||
use crate::api;
|
||||
|
||||
type WideBox = Box<dyn Future<Output = ()>>;
|
||||
|
||||
static OWNED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
|data| {
|
||||
let data = unsafe { Rc::<OwnedWakerBin>::from_raw(data as *const _) };
|
||||
let data = unsafe { Rc::<api::binary::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.
|
||||
@@ -19,19 +19,19 @@ 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::<OwnedWakerBin>::from_raw(data as *const _) };
|
||||
let data = unsafe { Rc::<api::binary::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 OwnedWakerBin).as_ref() }.unwrap();
|
||||
let data = unsafe { (data as *const api::binary::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::<OwnedWakerBin>::from_raw(data as *const _) };
|
||||
let data = unsafe { Rc::<api::binary::OwnedWakerBin>::from_raw(data as *const _) };
|
||||
(data.drop)(data.data);
|
||||
mem::drop(data);
|
||||
},
|
||||
@@ -39,12 +39,12 @@ static OWNED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
|
||||
struct BorrowedWakerData<'a> {
|
||||
go_around: &'a mut bool,
|
||||
cx: FutureContextBin,
|
||||
cx: api::binary::FutureContextBin,
|
||||
}
|
||||
static BORROWED_VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
|data| {
|
||||
let data = unsafe { (data as *mut BorrowedWakerData).as_mut() }.unwrap();
|
||||
let owned_data = Rc::<OwnedWakerBin>::new((data.cx.waker)(data.cx.data));
|
||||
let owned_data = Rc::<api::binary::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,
|
||||
@@ -54,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) -> FutureBin {
|
||||
pub fn future_to_vt<Fut: Future<Output = ()> + 'static>(fut: Fut) -> api::binary::FutureBin {
|
||||
let wide_box = Box::new(fut) as WideBox;
|
||||
let data = Box::into_raw(Box::new(wide_box));
|
||||
extern "C" fn drop(raw: *const ()) {
|
||||
mem::drop(unsafe { Box::<WideBox>::from_raw(raw as *mut _) })
|
||||
}
|
||||
extern "C" fn poll(raw: *const (), cx: FutureContextBin) -> UnitPoll {
|
||||
extern "C" fn poll(raw: *const (), cx: api::binary::FutureContextBin) -> api::binary::UnitPoll {
|
||||
let mut this = unsafe { Pin::new_unchecked(&mut **(raw as *mut WideBox).as_mut().unwrap()) };
|
||||
loop {
|
||||
let mut go_around = false;
|
||||
@@ -73,27 +73,27 @@ pub fn future_to_vt<Fut: Future<Output = ()> + 'static>(fut: Fut) -> FutureBin {
|
||||
let mut ctx = Context::from_waker(&borrowed_waker);
|
||||
let result = this.as_mut().poll(&mut ctx);
|
||||
if matches!(result, Poll::Ready(())) {
|
||||
break UnitPoll::Ready;
|
||||
break api::binary::UnitPoll::Ready;
|
||||
}
|
||||
if !go_around {
|
||||
break UnitPoll::Pending;
|
||||
break api::binary::UnitPoll::Pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
FutureBin { data: data as *const _, drop, poll }
|
||||
api::binary::FutureBin { data: data as *const _, drop, poll }
|
||||
}
|
||||
|
||||
struct VirtualFuture {
|
||||
vt: FutureBin,
|
||||
vt: api::binary::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 ()) -> OwnedWakerBin {
|
||||
extern "C" fn waker(raw: *const ()) -> api::binary::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 OwnedWakerBin { data, drop, wake, wake_ref };
|
||||
return api::binary::OwnedWakerBin { data, drop, wake, wake_ref };
|
||||
extern "C" fn drop(raw: *const ()) {
|
||||
mem::drop(unsafe { Box::<Waker>::from_raw(raw as *mut Waker) })
|
||||
}
|
||||
@@ -104,11 +104,11 @@ impl Future for VirtualFuture {
|
||||
unsafe { (raw as *mut Waker).as_mut() }.unwrap().wake_by_ref();
|
||||
}
|
||||
}
|
||||
let cx = FutureContextBin { data: cx as *mut Context as *const (), waker };
|
||||
let cx = api::binary::FutureContextBin { data: cx as *mut Context as *const (), waker };
|
||||
let result = (self.vt.poll)(self.vt.data, cx);
|
||||
match result {
|
||||
UnitPoll::Pending => Poll::Pending,
|
||||
UnitPoll::Ready => Poll::Ready(()),
|
||||
api::binary::UnitPoll::Pending => Poll::Pending,
|
||||
api::binary::UnitPoll::Ready => Poll::Ready(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,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: FutureBin) -> impl Future<Output = ()> { VirtualFuture { vt } }
|
||||
pub fn vt_to_future(vt: api::binary::FutureBin) -> impl Future<Output = ()> { VirtualFuture { vt } }
|
||||
|
||||
Reference in New Issue
Block a user