forked from Orchid/orchid
Fixed a tricky type erasure bug in the scheduler
This commit is contained in:
@@ -18,6 +18,7 @@ use crate::interpreted::{Clause, ExprInst};
|
||||
use crate::interpreter::HandlerTable;
|
||||
use crate::pipeline::file_loader::embed_to_map;
|
||||
use crate::systems::codegen::call;
|
||||
use crate::systems::stl::Numeric;
|
||||
use crate::utils::poller::{PollEvent, Poller};
|
||||
use crate::utils::unwrap_or;
|
||||
use crate::{ConstTree, Interner};
|
||||
@@ -28,8 +29,8 @@ struct Timer {
|
||||
delay: NotNan<f64>,
|
||||
}
|
||||
|
||||
pub fn set_timer(recurring: bool, delay: NotNan<f64>) -> XfnResult<Clause> {
|
||||
Ok(init_cps(2, Timer { recurring, delay }))
|
||||
pub fn set_timer(recurring: bool, delay: Numeric) -> XfnResult<Clause> {
|
||||
Ok(init_cps(2, Timer { recurring, delay: delay.as_float() }))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -38,9 +39,7 @@ impl CancelTimer {
|
||||
pub fn new(f: impl Fn() + Send + 'static) -> Self {
|
||||
Self(Arc::new(Mutex::new(f)))
|
||||
}
|
||||
pub fn cancel(&self) {
|
||||
self.0.lock().unwrap()()
|
||||
}
|
||||
pub fn cancel(&self) { self.0.lock().unwrap()() }
|
||||
}
|
||||
impl Debug for CancelTimer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
||||
@@ -39,7 +39,8 @@ pub fn tuple(data: impl IntoIterator<Item = ExprInst>) -> Clause {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{systems::codegen::tuple, foreign::Atomic};
|
||||
use crate::foreign::Atomic;
|
||||
use crate::systems::codegen::tuple;
|
||||
|
||||
#[test]
|
||||
fn tuple_printer() {
|
||||
|
||||
@@ -2,12 +2,12 @@ use super::flow::IOCmdHandlePack;
|
||||
use super::instances::{BRead, ReadCmd, SRead, Sink, Source, WriteCmd};
|
||||
use crate::error::RuntimeError;
|
||||
use crate::foreign::cps_box::init_cps;
|
||||
use crate::foreign::{xfn_1ary, xfn_2ary, Atomic, XfnResult, Atom};
|
||||
use crate::foreign::{xfn_1ary, xfn_2ary, Atom, Atomic, XfnResult};
|
||||
use crate::interpreted::Clause;
|
||||
use crate::representations::OrcString;
|
||||
use crate::systems::scheduler::SharedHandle;
|
||||
use crate::systems::stl::Binary;
|
||||
use crate::{ConstTree, Interner, ast};
|
||||
use crate::{ast, ConstTree, Interner};
|
||||
|
||||
type WriteHandle = SharedHandle<Sink>;
|
||||
type ReadHandle = SharedHandle<Source>;
|
||||
@@ -62,9 +62,7 @@ pub fn io_bindings<'a>(
|
||||
]) + ConstTree::Tree(
|
||||
std_streams
|
||||
.into_iter()
|
||||
.map(|(n, at)| {
|
||||
(i.i(n), ConstTree::clause(ast::Clause::Atom(Atom(at))))
|
||||
})
|
||||
.map(|(n, at)| (i.i(n), ConstTree::clause(ast::Clause::Atom(Atom(at)))))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,12 +5,13 @@ use super::Canceller;
|
||||
use crate::interpreted::ExprInst;
|
||||
|
||||
pub type SyncResult<T> = (T, Box<dyn Any + Send>);
|
||||
/// Output from handlers contains the resource being processed and any Orchid
|
||||
/// handlers executed as a result of the operation
|
||||
pub type HandlerRes<T> = (T, Vec<ExprInst>);
|
||||
pub type SyncOperation<T> =
|
||||
Box<dyn FnOnce(T, Canceller) -> SyncResult<T> + Send>;
|
||||
pub type SyncOpResultHandler<T> = Box<
|
||||
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>)
|
||||
|
||||
+ Send,
|
||||
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>) + Send,
|
||||
>;
|
||||
|
||||
struct SyncQueueItem<T> {
|
||||
@@ -43,10 +44,7 @@ pub struct BusyState<T> {
|
||||
}
|
||||
impl<T> BusyState<T> {
|
||||
pub fn new<U: 'static + Send>(
|
||||
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>)
|
||||
|
||||
+ Send
|
||||
+ 'static,
|
||||
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
|
||||
) -> Self {
|
||||
BusyState {
|
||||
handler: Box::new(|t, payload, cancel| {
|
||||
@@ -65,8 +63,8 @@ impl<T> BusyState<T> {
|
||||
pub fn enqueue<U: 'static + Send>(
|
||||
&mut self,
|
||||
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
|
||||
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + Send + 'static,
|
||||
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + Send + 'static,
|
||||
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
|
||||
early_cancel: impl FnOnce(T) -> HandlerRes<T> + Send + 'static,
|
||||
) -> Option<Canceller> {
|
||||
if self.seal.is_some() {
|
||||
return None;
|
||||
@@ -80,28 +78,31 @@ impl<T> BusyState<T> {
|
||||
(t, Box::new(r))
|
||||
}),
|
||||
handler: Box::new(|t, u, c| {
|
||||
let u = u.downcast().expect("mismatched handler and operation");
|
||||
let u: Box<U> = u.downcast().expect("mismatched handler and operation");
|
||||
handler(t, *u, c)
|
||||
}),
|
||||
});
|
||||
Some(cancelled)
|
||||
}
|
||||
|
||||
pub fn seal(&mut self, recipient: impl FnOnce(T) -> Vec<ExprInst> + Send + 'static) {
|
||||
pub fn seal(
|
||||
&mut self,
|
||||
recipient: impl FnOnce(T) -> Vec<ExprInst> + Send + 'static,
|
||||
) {
|
||||
assert!(self.seal.is_none(), "Already sealed");
|
||||
self.seal = Some(Box::new(recipient))
|
||||
}
|
||||
|
||||
pub fn is_sealed(&self) -> bool { self.seal.is_some() }
|
||||
|
||||
pub fn rotate<U: Send + 'static>(
|
||||
pub fn rotate(
|
||||
mut self,
|
||||
instance: T,
|
||||
result: U,
|
||||
result: Box<dyn Any + Send>,
|
||||
cancelled: Canceller,
|
||||
) -> NextItemReport<T> {
|
||||
let (mut instance, mut events) =
|
||||
(self.handler)(instance, Box::new(result), cancelled);
|
||||
(self.handler)(instance, result, cancelled);
|
||||
let next_item = loop {
|
||||
if let Some(candidate) = self.queue.pop_front() {
|
||||
if candidate.cancelled.is_cancelled() {
|
||||
|
||||
@@ -5,5 +5,6 @@ mod busy;
|
||||
mod canceller;
|
||||
mod system;
|
||||
|
||||
pub use busy::HandlerRes;
|
||||
pub use canceller::Canceller;
|
||||
pub use system::{SealedOrTaken, SeqScheduler, SharedHandle, SharedState};
|
||||
|
||||
@@ -8,8 +8,8 @@ use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use super::busy::{BusyState, NextItemReportKind};
|
||||
use super::Canceller;
|
||||
use super::busy::{BusyState, NextItemReportKind, SyncOperation};
|
||||
use super::{Canceller, HandlerRes};
|
||||
use crate::error::AssertionError;
|
||||
use crate::facade::{IntoSystem, System};
|
||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||
@@ -80,13 +80,10 @@ impl<T> SharedHandle<T> {
|
||||
/// is to return values synchronously after they have been removed with
|
||||
/// [SyncHandle::untake].
|
||||
pub fn untake(&self, value: T) -> Result<(), T> {
|
||||
take_with_output(
|
||||
&mut *self.0.lock().unwrap(),
|
||||
|state| match state {
|
||||
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
||||
_ => (state, Err(value)),
|
||||
},
|
||||
)
|
||||
take_with_output(&mut *self.0.lock().unwrap(), |state| match state {
|
||||
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
||||
_ => (state, Err(value)),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<T> Clone for SharedHandle<T> {
|
||||
@@ -144,7 +141,7 @@ pub fn is_taken_error(x: ExprInst) -> XfnResult<bool> {
|
||||
trait_set! {
|
||||
/// The part of processing a blocking I/O task that cannot be done on a remote
|
||||
/// thread, eg. because it accesses other systems or Orchid code.
|
||||
trait NonSendFn = FnOnce(Box<dyn Any>, SeqScheduler) -> Vec<ExprInst>;
|
||||
trait NonSendFn = FnOnce(Box<dyn Any + Send>, SeqScheduler) -> Vec<ExprInst>;
|
||||
}
|
||||
|
||||
struct SyncReply {
|
||||
@@ -198,9 +195,9 @@ impl SeqScheduler {
|
||||
pub fn schedule<T: Send + 'static, U: Send + 'static>(
|
||||
&self,
|
||||
handle: SharedHandle<T>,
|
||||
operation: impl FnOnce(T, Canceller) -> (T, U) + Sync + Send + 'static,
|
||||
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + Sync + Send + 'static,
|
||||
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + Sync + Send + 'static,
|
||||
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
|
||||
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
|
||||
early_cancel: impl FnOnce(T) -> HandlerRes<T> + Send + 'static,
|
||||
) -> Result<Canceller, SealedOrTaken> {
|
||||
take_with_output(&mut *handle.0.lock().unwrap(), {
|
||||
let handle = handle.clone();
|
||||
@@ -216,7 +213,11 @@ impl SeqScheduler {
|
||||
SharedResource::Free(t) => {
|
||||
let cancelled = Canceller::new();
|
||||
drop(early_cancel); // cannot possibly be useful
|
||||
self.submit(t, handle, cancelled.clone(), operation);
|
||||
let op_erased: SyncOperation<T> = Box::new(|t, c| {
|
||||
let (t, u) = operation(t, c);
|
||||
(t, Box::new(u))
|
||||
});
|
||||
self.submit(t, handle, cancelled.clone(), op_erased);
|
||||
(SharedResource::Busy(BusyState::new(handler)), Ok(cancelled))
|
||||
},
|
||||
}
|
||||
@@ -233,9 +234,11 @@ impl SeqScheduler {
|
||||
) -> Canceller {
|
||||
let cancelled = Canceller::new();
|
||||
let canc1 = cancelled.clone();
|
||||
let opid = self.0.pending.borrow_mut().insert(Box::new(|data, _| {
|
||||
handler(*data.downcast().expect("This is associated by ID"), canc1)
|
||||
}));
|
||||
let opid = self.0.pending.borrow_mut().insert(Box::new(
|
||||
|data: Box<dyn Any + Send>, _| {
|
||||
handler(*data.downcast().expect("This is associated by ID"), canc1)
|
||||
},
|
||||
));
|
||||
let canc1 = cancelled.clone();
|
||||
let mut port = self.0.port.clone();
|
||||
self.0.pool.submit(Box::new(move || {
|
||||
@@ -251,18 +254,15 @@ impl SeqScheduler {
|
||||
handle: SharedHandle<T>,
|
||||
seal: impl FnOnce(T) -> Vec<ExprInst> + Sync + Send + 'static,
|
||||
) -> Result<Vec<ExprInst>, SealedOrTaken> {
|
||||
take_with_output(
|
||||
&mut *handle.0.lock().unwrap(),
|
||||
|state| match state {
|
||||
SharedResource::Busy(mut b) if !b.is_sealed() => {
|
||||
b.seal(seal);
|
||||
(SharedResource::Busy(b), Ok(Vec::new()))
|
||||
},
|
||||
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
|
||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
|
||||
take_with_output(&mut *handle.0.lock().unwrap(), |state| match state {
|
||||
SharedResource::Busy(mut b) if !b.is_sealed() => {
|
||||
b.seal(seal);
|
||||
(SharedResource::Busy(b), Ok(Vec::new()))
|
||||
},
|
||||
)
|
||||
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
|
||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
|
||||
})
|
||||
}
|
||||
|
||||
/// Asynchronously recursive function to schedule a new task for execution and
|
||||
@@ -270,18 +270,18 @@ impl SeqScheduler {
|
||||
/// from the callback passed to the [AsynchSystem] so that if the task is
|
||||
/// never resolved but the [AsynchSystem] through which the resolving event
|
||||
/// would arrive is dropped this [SeqScheduler] is also dropped.
|
||||
fn submit<T: Send + 'static, U: Send + 'static>(
|
||||
fn submit<T: Send + 'static>(
|
||||
&self,
|
||||
t: T,
|
||||
handle: SharedHandle<T>,
|
||||
cancelled: Canceller,
|
||||
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
|
||||
operation: SyncOperation<T>,
|
||||
) {
|
||||
// referenced by self until run, references handle
|
||||
let opid = self.0.pending.borrow_mut().insert(Box::new({
|
||||
let cancelled = cancelled.clone();
|
||||
move |data, this| {
|
||||
let (t, u): (T, U) =
|
||||
move |data: Box<dyn Any + Send>, this: SeqScheduler| {
|
||||
let (t, u): (T, Box<dyn Any + Send>) =
|
||||
*data.downcast().expect("This is associated by ID");
|
||||
let handle2 = handle.clone();
|
||||
take_with_output(&mut *handle.0.lock().unwrap(), |state| {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use crate::foreign::{xfn_1ary, xfn_2ary, XfnResult, Atom};
|
||||
use super::Numeric;
|
||||
use crate::error::AssertionError;
|
||||
use crate::foreign::{xfn_1ary, xfn_2ary, Atom, XfnResult};
|
||||
use crate::interner::Interner;
|
||||
use crate::representations::interpreted::Clause;
|
||||
use crate::error::AssertionError;
|
||||
use crate::{ConstTree, Location, OrcString};
|
||||
|
||||
use super::Numeric;
|
||||
|
||||
/// Takes a boolean and two branches, runs the first if the bool is true, the
|
||||
/// second if it's false.
|
||||
// Even though it's a ternary function, IfThenElse is implemented as an unary
|
||||
@@ -23,11 +22,12 @@ pub fn if_then_else(b: bool) -> XfnResult<Clause> {
|
||||
/// - both are bool,
|
||||
/// - both are either uint or num
|
||||
pub fn equals(a: Atom, b: Atom) -> XfnResult<bool> {
|
||||
let (a, b) = match (a.try_downcast::<OrcString>(), b.try_downcast::<OrcString>()) {
|
||||
(Ok(a), Ok(b)) => return Ok(a == b),
|
||||
(Err(a), Err(b)) => (a, b),
|
||||
_ => return Ok(false),
|
||||
};
|
||||
let (a, b) =
|
||||
match (a.try_downcast::<OrcString>(), b.try_downcast::<OrcString>()) {
|
||||
(Ok(a), Ok(b)) => return Ok(a == b),
|
||||
(Err(a), Err(b)) => (a, b),
|
||||
_ => return Ok(false),
|
||||
};
|
||||
match (a.request::<Numeric>(), b.request::<Numeric>()) {
|
||||
(Some(a), Some(b)) => return Ok(a.as_float() == b.as_float()),
|
||||
(None, None) => (),
|
||||
|
||||
@@ -3,12 +3,12 @@ import std::panic
|
||||
|
||||
-- utilities for using lists as pairs
|
||||
|
||||
export const fst := \l. (
|
||||
const fst := \l. (
|
||||
list::get l 0
|
||||
(panic "nonempty expected")
|
||||
\x.x
|
||||
)
|
||||
export const snd := \l. (
|
||||
const snd := \l. (
|
||||
list::get l 1
|
||||
(panic "2 elements expected")
|
||||
\x.x
|
||||
|
||||
@@ -4,15 +4,15 @@ mod arithmetic_error;
|
||||
mod binary;
|
||||
mod bool;
|
||||
mod conv;
|
||||
mod exit_status;
|
||||
mod inspect;
|
||||
mod number;
|
||||
mod panic;
|
||||
mod state;
|
||||
mod stl_system;
|
||||
mod string;
|
||||
mod exit_status;
|
||||
pub use arithmetic_error::ArithmeticError;
|
||||
pub use binary::Binary;
|
||||
pub use exit_status::ExitStatus;
|
||||
pub use number::Numeric;
|
||||
pub use stl_system::StlConfig;
|
||||
pub use exit_status::ExitStatus;
|
||||
|
||||
@@ -4,7 +4,7 @@ use ordered_float::NotNan;
|
||||
|
||||
use super::ArithmeticError;
|
||||
use crate::error::AssertionError;
|
||||
use crate::foreign::{xfn_2ary, ExternError, ToClause, XfnResult, Atomic};
|
||||
use crate::foreign::{xfn_2ary, Atomic, ExternError, ToClause, XfnResult};
|
||||
use crate::interpreted::TryFromExprInst;
|
||||
use crate::representations::interpreted::{Clause, ExprInst};
|
||||
use crate::{ConstTree, Interner, Location};
|
||||
|
||||
Reference in New Issue
Block a user