reactor_rt/lib.rs
1/*
2 * Copyright (c) 2021, TU Dresden.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
22 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25//! The runtime library for reactor programs generated by LFC,
26//! the [Lingua Franca](https://github.com/lf-lang/lingua-franca) compiler.
27//!
28//! Most of this crate consists of types that are manipulated
29//! only by the generated code. User-written Rust code mostly
30//! interacts with the type [ReactionCtx], which is the entry
31//! point for user documentation.
32//!
33//! Crate-level features include:
34//! - `parallel-runtime`: use Rayon to execute reactions in parallel
35//! when possible. This is not yet the default. For some applications,
36//! where there is no data parallelism, this may harm performance
37//! (as well as pull in unneeded dependencies) and should be off.
38//! - `wide-ids`: Enables 64-bit wide reaction ids on 64-bit
39//! architectures. This may reduce performance, but allows for
40//! 2^32 reactor instances compared to the default of 2^16,
41//! which may feel a bit tight for some applications. On machines
42//! with a pointer-width of less than 64 bits, ID types are
43//! always 32 bits. The feature also widens trigger ids to 64 bits
44//! if possible, which enables 2^64 individual trigger components
45//! (ports, actions, etc.) instead of 2^32.
46//! - `vec-id-sets`: Change the implementation of reaction sets
47//! to be a sorted vector instead of a hash set. This has a positive
48//! performance impact, as reaction sets are typically very small.
49//! More testing is required to determine pathological cases.
50//! This is a default feature.
51//! - `no-unsafe`: disable optimisations that use unsafe code in this runtime.
52//! Just provided for comparison, should probably be removed (unsafe code is fine).
53
54// #![deny(unused_crate_dependencies)]
55#![deny(unused_extern_crates)]
56// #![warn(unreachable_pub)]
57#![warn(unused_lifetimes)]
58#![warn(single_use_lifetimes)]
59#![warn(explicit_outlives_requirements)]
60
61#[macro_use]
62extern crate array_macro;
63#[cfg(test)]
64#[allow(unused, unused_imports)]
65#[macro_use]
66extern crate assert_matches;
67// #[macro_use]
68// extern crate index_vec;
69#[macro_use]
70extern crate log;
71#[cfg(feature = "parallel-runtime")]
72extern crate rayon;
73#[macro_use]
74extern crate static_assertions;
75#[macro_use]
76extern crate cfg_if;
77
78pub use std::time::{Duration, Instant};
79
80pub(crate) use scheduler::debug::*;
81
82pub use self::actions::*;
83pub use self::ids::*;
84pub use self::ports::*;
85pub use self::scheduler::*;
86pub use self::time::*;
87pub use self::timers::*;
88pub use self::triggers::ReactionTrigger;
89pub use self::util::*;
90
91#[cfg(test)]
92pub mod test;
93
94mod actions;
95mod ids;
96mod ports;
97mod scheduler;
98mod time;
99mod timers;
100mod triggers;
101mod util;
102
103pub mod assembly;
104
105/// The prelude that is imported at the top of reactor files
106/// generated by LFC.
107pub mod prelude {
108 pub use crate::Offset::*;
109 pub use crate::{
110 after, assert_tag_is, delay, tag, AsyncCtx, Duration, EventTag, Instant, LogicalAction, Multiport, PhysicalActionRef,
111 Port, ReactionCtx, Timer,
112 };
113
114 /// Alias for the unit type, so that it can be written without quotes in LF.
115 /// Otherwise it needs to be written `{= () =}`.
116 /// It is not camel-case as it is actually a primitive type.
117 #[allow(non_camel_case_types)]
118 pub type unit = ();
119}
120
121/// The trait used by the framework to interact with the reactor
122/// during runtime.
123///
124/// Importantly, it's object-safe and has no type parameters
125/// or associated types. This allows us to wrap it into a
126/// `Box<dyn ReactorBehavior>`.
127pub trait ReactorBehavior {
128 /// The unique ID of this reactor. This is given by the
129 /// framework upon construction.
130 fn id(&self) -> ReactorId;
131
132 /// Execute a single user-written reaction.
133 /// Dispatches on the reaction id, and unpacks parameters,
134 /// which are the reactor components declared as fields of
135 /// this struct.
136 ///
137 /// It must always be the case that `local_rid < Self::MAX_REACTION_ID`,
138 /// where `Self::MAX_REACTION_ID` is defined by the [assembly::ReactorInitializer],
139 /// because of object safety.
140 fn react(&mut self, ctx: &mut ReactionCtx, local_rid: LocalReactionId);
141
142 /// Acknowledge that the given tag is done executing and
143 /// free resources if need be.
144 fn cleanup_tag(&mut self, ctx: &CleanupCtx);
145}
146assert_obj_safe!(ReactorBehavior);
147
148/// Used for benchmarking to access private API of the crate.
149#[cfg(feature = "public-internals")]
150#[doc(hidden)]
151pub mod internals {
152 pub use crate::ids::impl_types::*;
153 pub use crate::scheduler::internals::*;
154 use crate::{GlobalId, GlobalReactionId};
155
156 pub fn new_global_rid(u: GlobalIdImpl) -> GlobalReactionId {
157 GlobalReactionId(GlobalId::from_raw(u))
158 }
159}