forked from ROMEO/nexosim
Return both simulation and scheduler at init
This commit is contained in:
@ -102,9 +102,10 @@ impl simulation_server::Simulation for GrpcSimulationService {
|
||||
|
||||
let (reply, bench) = self.initializer().init(request);
|
||||
|
||||
if let Some((simulation, endpoint_registry)) = bench {
|
||||
if let Some((simulation, scheduler, endpoint_registry)) = bench {
|
||||
*self.controller() = ControllerService::Started {
|
||||
simulation,
|
||||
scheduler,
|
||||
event_source_registry: endpoint_registry.event_source_registry,
|
||||
query_source_registry: endpoint_registry.query_source_registry,
|
||||
key_registry: KeyRegistry::default(),
|
||||
|
@ -8,7 +8,7 @@ use prost_types::Timestamp;
|
||||
use tai_time::MonotonicTime;
|
||||
|
||||
use super::codegen::simulation::{Error, ErrorCode};
|
||||
use crate::simulation::ExecutionError;
|
||||
use crate::simulation::{ExecutionError, SchedulingError};
|
||||
|
||||
pub(crate) use controller_service::ControllerService;
|
||||
pub(crate) use init_service::InitService;
|
||||
@ -47,6 +47,18 @@ fn map_execution_error(error: ExecutionError) -> Error {
|
||||
to_error(error_code, error_message)
|
||||
}
|
||||
|
||||
/// Map a `SchedulingError` to a Protobuf error.
|
||||
fn map_scheduling_error(error: SchedulingError) -> Error {
|
||||
let error_code = match error {
|
||||
SchedulingError::InvalidScheduledTime => ErrorCode::InvalidDeadline,
|
||||
SchedulingError::NullRepetitionPeriod => ErrorCode::InvalidPeriod,
|
||||
};
|
||||
|
||||
let error_message = error.to_string();
|
||||
|
||||
to_error(error_code, error_message)
|
||||
}
|
||||
|
||||
/// Attempts a cast from a `MonotonicTime` to a protobuf `Timestamp`.
|
||||
///
|
||||
/// This will fail if the time is outside the protobuf-specified range for
|
||||
|
@ -4,12 +4,13 @@ use prost_types::Timestamp;
|
||||
|
||||
use crate::grpc::key_registry::{KeyRegistry, KeyRegistryId};
|
||||
use crate::registry::{EventSourceRegistry, QuerySourceRegistry};
|
||||
use crate::simulation::Simulation;
|
||||
use crate::simulation::{Scheduler, Simulation};
|
||||
|
||||
use super::super::codegen::simulation::*;
|
||||
use super::{
|
||||
map_execution_error, monotonic_to_timestamp, simulation_not_started_error,
|
||||
timestamp_to_monotonic, to_error, to_positive_duration, to_strictly_positive_duration,
|
||||
map_execution_error, map_scheduling_error, monotonic_to_timestamp,
|
||||
simulation_not_started_error, timestamp_to_monotonic, to_error, to_positive_duration,
|
||||
to_strictly_positive_duration,
|
||||
};
|
||||
|
||||
/// Protobuf-based simulation manager.
|
||||
@ -24,6 +25,7 @@ pub(crate) enum ControllerService {
|
||||
NotStarted,
|
||||
Started {
|
||||
simulation: Simulation,
|
||||
scheduler: Scheduler,
|
||||
event_source_registry: EventSourceRegistry,
|
||||
query_source_registry: QuerySourceRegistry,
|
||||
key_registry: KeyRegistry,
|
||||
@ -147,6 +149,7 @@ impl ControllerService {
|
||||
let reply = match self {
|
||||
Self::Started {
|
||||
simulation,
|
||||
scheduler,
|
||||
event_source_registry,
|
||||
key_registry,
|
||||
..
|
||||
@ -224,7 +227,9 @@ impl ControllerService {
|
||||
}
|
||||
});
|
||||
|
||||
simulation.process(action).map_err(map_execution_error)?;
|
||||
scheduler
|
||||
.schedule(deadline, action)
|
||||
.map_err(map_scheduling_error)?;
|
||||
|
||||
Ok(key_id)
|
||||
}(),
|
||||
|
@ -2,8 +2,7 @@ use ciborium;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::registry::EndpointRegistry;
|
||||
use crate::simulation::SimInit;
|
||||
use crate::simulation::Simulation;
|
||||
use crate::simulation::{Scheduler, SimInit, Simulation};
|
||||
|
||||
use super::{map_execution_error, timestamp_to_monotonic, to_error};
|
||||
|
||||
@ -51,7 +50,7 @@ impl InitService {
|
||||
pub(crate) fn init(
|
||||
&mut self,
|
||||
request: InitRequest,
|
||||
) -> (InitReply, Option<(Simulation, EndpointRegistry)>) {
|
||||
) -> (InitReply, Option<(Simulation, Scheduler, EndpointRegistry)>) {
|
||||
let start_time = request.time.unwrap_or_default();
|
||||
|
||||
let reply = (self.sim_gen)(&request.cfg)
|
||||
@ -73,7 +72,7 @@ impl InitService {
|
||||
sim_init
|
||||
.init(start_time)
|
||||
.map_err(map_execution_error)
|
||||
.map(|sim| (sim, registry))
|
||||
.map(|(sim, sched)| (sim, sched, registry))
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -325,7 +325,8 @@
|
||||
//! # .add_model(multiplier2, multiplier2_mbox, "multiplier2")
|
||||
//! # .add_model(delay1, delay1_mbox, "delay1")
|
||||
//! # .add_model(delay2, delay2_mbox, "delay2")
|
||||
//! # .init(t0)?;
|
||||
//! # .init(t0)?
|
||||
//! # .0;
|
||||
//! // Send a value to the first multiplier.
|
||||
//! simu.process_event(Multiplier::input, 21.0, &input_address)?;
|
||||
//!
|
||||
|
@ -107,7 +107,7 @@
|
||||
//! # impl Model for ModelB {};
|
||||
//! # let modelA_addr = Mailbox::<ModelA>::new().address();
|
||||
//! # let modelB_addr = Mailbox::<ModelB>::new().address();
|
||||
//! # let mut simu = SimInit::new().init(MonotonicTime::EPOCH)?;
|
||||
//! # let mut simu = SimInit::new().init(MonotonicTime::EPOCH)?.0;
|
||||
//! simu.process_event(
|
||||
//! |m: &mut ModelA| {
|
||||
//! m.output.connect(ModelB::input, modelB_addr);
|
||||
@ -164,11 +164,11 @@ thread_local! { pub(crate) static CURRENT_MODEL_ID: Cell<ModelId> = const { Cell
|
||||
///
|
||||
/// A [`Simulation`] object also manages an event scheduling queue and
|
||||
/// simulation time. The scheduling queue can be accessed from the simulation
|
||||
/// itself, but also from models via the optional
|
||||
/// [`&mut Context`](crate::model::Context) argument of input and replier port
|
||||
/// methods. Likewise, simulation time can be accessed with the
|
||||
/// [`Simulation::time()`] method, or from models with the
|
||||
/// [`LocalScheduler::time()`](crate::simulation::LocalScheduler::time) method.
|
||||
/// itself, but also from models via the optional [`&mut
|
||||
/// Context`](crate::model::Context) argument of input and replier port methods.
|
||||
/// Likewise, simulation time can be accessed with the [`Simulation::time()`]
|
||||
/// method, or from models with the
|
||||
/// [`Context::time()`](crate::simulation::Context::time) method.
|
||||
///
|
||||
/// Events and queries can be scheduled immediately, *i.e.* for the current
|
||||
/// simulation time, using [`process_event()`](Simulation::process_event) and
|
||||
@ -276,11 +276,6 @@ impl Simulation {
|
||||
self.step_until_unchecked(target_time)
|
||||
}
|
||||
|
||||
/// Returns an owned scheduler handle.
|
||||
pub fn scheduler(&self) -> Scheduler {
|
||||
Scheduler::new(self.scheduler_queue.clone(), self.time.reader())
|
||||
}
|
||||
|
||||
/// Processes an action immediately, blocking until completion.
|
||||
///
|
||||
/// Simulation time remains unchanged. The periodicity of the action, if
|
||||
|
@ -69,8 +69,6 @@ impl Scheduler {
|
||||
///
|
||||
/// Events scheduled for the same time and targeting the same model are
|
||||
/// guaranteed to be processed according to the scheduling order.
|
||||
///
|
||||
/// See also: [`LocalScheduler::schedule_event`](LocalScheduler::schedule_event).
|
||||
pub fn schedule_event<M, F, T, S>(
|
||||
&self,
|
||||
deadline: impl Deadline,
|
||||
@ -95,8 +93,6 @@ impl Scheduler {
|
||||
///
|
||||
/// Events scheduled for the same time and targeting the same model are
|
||||
/// guaranteed to be processed according to the scheduling order.
|
||||
///
|
||||
/// See also: [`LocalScheduler::schedule_keyed_event`](LocalScheduler::schedule_keyed_event).
|
||||
pub fn schedule_keyed_event<M, F, T, S>(
|
||||
&self,
|
||||
deadline: impl Deadline,
|
||||
@ -121,8 +117,6 @@ impl Scheduler {
|
||||
///
|
||||
/// Events scheduled for the same time and targeting the same model are
|
||||
/// guaranteed to be processed according to the scheduling order.
|
||||
///
|
||||
/// See also: [`LocalScheduler::schedule_periodic_event`](LocalScheduler::schedule_periodic_event).
|
||||
pub fn schedule_periodic_event<M, F, T, S>(
|
||||
&self,
|
||||
deadline: impl Deadline,
|
||||
@ -155,8 +149,6 @@ impl Scheduler {
|
||||
///
|
||||
/// Events scheduled for the same time and targeting the same model are
|
||||
/// guaranteed to be processed according to the scheduling order.
|
||||
///
|
||||
/// See also: [`LocalScheduler::schedule_keyed_periodic_event`](LocalScheduler::schedule_keyed_periodic_event).
|
||||
pub fn schedule_keyed_periodic_event<M, F, T, S>(
|
||||
&self,
|
||||
deadline: impl Deadline,
|
||||
|
@ -11,7 +11,8 @@ use crate::util::priority_queue::PriorityQueue;
|
||||
use crate::util::sync_cell::SyncCell;
|
||||
|
||||
use super::{
|
||||
add_model, ExecutionError, Mailbox, GlobalScheduler, SchedulerQueue, Signal, Simulation,
|
||||
add_model, ExecutionError, GlobalScheduler, Mailbox, Scheduler, SchedulerQueue, Signal,
|
||||
Simulation,
|
||||
};
|
||||
|
||||
/// Builder for a multi-threaded, discrete-event simulation.
|
||||
@ -146,10 +147,17 @@ impl SimInit {
|
||||
/// Builds a simulation initialized at the specified simulation time,
|
||||
/// executing the [`Model::init()`](crate::model::Model::init) method on all
|
||||
/// model initializers.
|
||||
pub fn init(mut self, start_time: MonotonicTime) -> Result<Simulation, ExecutionError> {
|
||||
///
|
||||
/// The simulation object and its associated scheduler are returned upon
|
||||
/// success.
|
||||
pub fn init(
|
||||
mut self,
|
||||
start_time: MonotonicTime,
|
||||
) -> Result<(Simulation, Scheduler), ExecutionError> {
|
||||
self.time.write(start_time);
|
||||
self.clock.synchronize(start_time);
|
||||
|
||||
let scheduler = Scheduler::new(self.scheduler_queue.clone(), self.time.reader());
|
||||
let mut simulation = Simulation::new(
|
||||
self.executor,
|
||||
self.scheduler_queue,
|
||||
@ -162,7 +170,7 @@ impl SimInit {
|
||||
);
|
||||
simulation.run()?;
|
||||
|
||||
Ok(simulation)
|
||||
Ok((simulation, scheduler))
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user