CFG

    Controlflow Graph
FSM

    finite-state machine
IDE

    integrated development environment
KIELER

    KIEL Integrated Environment for Layout Eclipse Rich Client
LED

    light-emitting diode
LF

    Lingua Franca
SCADE

    Safety-Critical Application Development Environment
UML

    Unified Modeling Language

# Modal Reactors

Alexander Schulz-Rosengarten1, Reinhard von Hanxleden1, Marten Lohstroh2,
Soroush Bateni3, Edward A. Lee2  1 Kiel University, Kiel, Germany, {als,
<EMAIL_ADDRESS>2 UC Berkeley, California, USA, {marten,
<EMAIL_ADDRESS>3 UT Dallas, Texas, USA<EMAIL_ADDRESS>
###### Abstract

Complex software systems often feature distinct modes of operation, each
designed to handle a particular scenario that may require the system to
respond in a certain way. Breaking down system behavior into mutually
exclusive modes and discrete transitions between modes is a commonly used
strategy to reduce implementation complexity and promote code readability.

However, such capabilities often come in the form of self-contained domain
specific languages or language-specific frameworks. The work in this paper
aims to bring the advantages of modal models to mainstream programming
languages, by following the polyglot coordination approach of Lingua Franca
(LF), in which verbatim target code (e. g., C, C++, Python, Typescript, or
Rust) is encapsulated in composable reactive components called reactors.
Reactors can form a dataflow network, are triggered by timed as well as
sporadic events, execute concurrently, and can be distributed across nodes on
a network.

With modal models in LF, we introduce a lean extension to the concept of
reactors that enables the coordination of reactive tasks based on modes of
operation. The implementation of modal reactors outlined in this paper
generalizes to any LF-supported language with only modest modifications to the
generic runtime system.

###### Index Terms:

coodination, polyglot, modal models, state machines, model-driven engineering,
reactors, Lingua Franca

##  I Introduction

The focus of this paper is on reactive systems, which continuously react to
their environment, are typically embedded in larger systems, and often have
some real-time requirements.

Two major notations or views have emerged for describing reactive systems,
actor-oriented dataflow networks and state machines. The _dataflow view_
breaks down the program into smaller blocks with streams of data flowing
between them. Each such actor receives inputs, produces outputs, and can be
assumed to operate fully independently from other blocks on which it has no
data dependencies, thereby presenting opportunities for parallelization or
distribution. MathWorks’ Simulink and National Instruments’ LabVIEW are
examples for such an approach.

In a _state-oriented view_ , the program is modeled in terms of states of the
system and its progression in the form of transitions between them. State
machine notations can be found, for example, as Stateflow [11] in Simulink or
as Statecharts [12]. While state machines often describe fine-grained steps at
the system level, they can also be used to represent more abstract _modes_ of
operation. For example, a system or subsystem may progress from initialization
mode, through a training mode, and into a steady-state mode, with additional
modes for error handling. Each mode of operation may encapsulate a complex
collection of (stateful) reactive behaviors. Such _modal models_ were
realized, for example, in Ptolemy II [17], where they were used to simulate
complex and hybrid systems.

However, the languages that provide the capabilities to model systems in any
of these notations often come in the form of standalone domain specific
languages (as in Simulink, LabVIEW, or Ptolemy II) or language-specific
frameworks (such as Akka [26]). Usually, these languages either compile to or
integrate into specific general purpose programming languages to produce
executable code. The idea of _polyglot coordination_ is to allow any
mainstream programming languages to benefit from the advantages of modeling
with actors, states, or modes. This can be done by directly embedding the
verbatim code and then producing executable code that coordinates the
execution of these modular units.

The goal of the work in this paper is to bring the advantages of modal models
to mainstream programming languages through a reactor-oriented coordination
language called Lingua Franca (LF) [22]. LF is rooted in a model of
computation called _reactors_ [21] and is built as a polyglot coordination
language. Reactors encapsulate reactive tasks specified in verbatim code and
provide a _minimal coordination layer_ around them that is reactive, timed,
concurrent, event-based, and accounts for isolated states. Unlike Ptolemy II,
LF is not merely intended for modeling and simulation, but rather is meant for
building efficient implementations. LF currently supports C, C++, Python,
TypeScript, and Rust. For these languages it provides a runtime environment
for automatic coordination of time-sensitive and concurrent or distributed
reactors. The applicability of LF ranges from embedded systems to distributed
systems deployed to the Cloud.

### Contributions and Outline

While the reactor-oriented modeling approach is well-suited for concurrent and
distributed event-based coordination, it does not allow to naturally
coordinate these tasks in terms of modes of operation, as we will illustrate
in Sec. II. After summarizing relevant aspects of LF in Sec. III, we will
present our concept of modal reactors, extending the polyglot coordination
layer of LF. Specifically, this includes

  * •

a lean textual and diagrammatic modal language extension that embraces the
polyglot nature of LF by taking a “black-box approach” towards the target
language and that allows hierarchical decomposition of modal behavior;

  * •

an adaptation to reactors with two simple but effective transition types,
reset and history, which can be further refined at the target language level;
and

  * •

a semantics for modal behavior that introduces mode-local time and leverages
LF’s superdense time model to achieve deterministic behavior.

Sec. V gives a closer look at implementation aspects and Sec. VI elaborates on
crucial design decisions and potential alternatives. We discuss related work
in Sec. VII and conclude in Sec. VIII.

##  II Motivating Example: The Furuta Pendulum

Figure 1: Schematic of the Furuta pendulum from Wikipedia by Benjamin
Cazzolato — CC BY 3.0.

A Furuta pendulum [10] is a classic control system problem often used to teach
feedback control. As shown in Fig. 1, it consists of a vertical shaft driven
by motor, a fixed arm extending out at 90 degrees from the top of the shaft,
and a pendulum at the end of the arm. The goal is to rotate the shaft to
impart enough energy to the pendulum that it swings up, to then catch the
pendulum and balance it so that the pendulum remains above the arm. Each of
these steps requires a different control behavior which makes a controller a
prime candidate for a modal model. It cycles through the three modes, which we
will name SwingUp, Catch, and Stabilize.

From a classical event-driven or dataflow perspective, there is only a single
reactive task, computing the motor control based on the angle measurements at
the arm and shaft. However, with modes we can identify more fine-granular
tasks and coordinate these by embedding them in a modal model.

(a) Structural overview as graphical diagram

⬇

1target C;

2reactor Controller {

3 input angles:float[];

4 output control:float;

5 initial mode SwingUp {

6 reaction(angles) -> control, reset(Catch) {=

7 ... control law here in C ...

8 lf_set(control, ... control value ... );

9 if ( ... condition ... ) { lf_set_mode(Catch); }

10 =}

11 }

12 mode Catch {

13 reaction(angles) -> control, reset(Stabilize) {=

14 ... control law here in C ...

15 lf_set(control, ... control value ... );

16 if ( ... condition ... ) { lf_set_mode(Stabilize); }

17 =}

18 }

19 mode Stabilize {

20 reaction(angles) -> control, reset(SwingUp) {=

21 ... control law here in C ...

22 lf_set(control, ... control value ... );

23 if ( ... condition ... ) { lf_set_mode(SwingUp); }

24 =}

25 }

26}

(b) The Controller reactor code

⬇

1target C;

2import Controller from "FurutaPendulumController.lf"

3import Sensor, Actuator from "FurutaPendulumUtil.lf"

4

5main reactor {

6 s = new Sensor();

7 c = new Controller();

8 a = new Actuator();

9 s.angles -> c.angles;

10 c.control -> a.control;

11}

(c) The main reactor code for the program

Figure 2: LF program to drive the Furuta Pendulum.

To illustrate what we are aiming for with modal reactors, we have replicated a
solution given by Eker et al. [19] and implemented it using our mode extension
for Lingua Franca. The program is presented in Fig. 2. Our language extension
includes the diagram synthesis capabilities of LF, which yields an
automatically generated and interactive pictorial representation (Fig. 2a) of
the textual program. The overall program consists of three connected reactors
Sensor, Controller, and Actuator. We will now explain the code for this
program, and, in the process, introduce Lingua Franca. Fig. 2b and Fig. 2c
represent an abbreviated version with some C code omitted for clarity. The
source code of a more comprehensive implementation is available
online.111https://github.com/lf-lang/examples-lingua-
franca/tree/date23/C/src/modal_models/FurutaPendulum

Let us start with the core of the program, the controller itself. The very
first line in Fig. 2b identifies the target language as C, which means that
this controller will be translated into a standalone C module, and that the
logic of reactions and mode transitions will be written in C. The first two
lines in the Controller reactor define the input and output ports. It has a
vector-valued input port named angles that accepts inputs containing
measurements of the angle of the shaft, the angle of the pendulum, and the
angular velocities of both, as measured by sensors. Following are three
_reaction_ definitions, each reacting to the angles input, producing a control
output, and implementing one of three control laws.

We here use the new mode extension to encapsulate each one in a separate mode.
The reaction bodies are given in ordinary C code that reads the input values
and calculates an actuation signal. That C code would go on lines 7, 14, and
21 but is abstracted away here because those details are not germane to this
paper. On lines 8, 15, and 22, the calculated control value is sent to the
output port. Lines 9, 16, and 23 use C expressions (abstracted here) to
determine whether a mode change is now required, and, if so, invoke
lf_set_mode to specify the next mode. See Sec. IV-B for the semantics of these
mode transitions.

Next, Fig. 2c illustrates how this controller is used in the actual program,
which is generated into a standalone C program that can be loaded into the
flash memory of an embedded controller and deployed. To interact with the real
world, the Sensor and Actuator reactors also need to be implemented. We skip
the presentation of these for brevity and only import them as for the
Controller. The main reactor on line 5, representing the actual program,
instantiates those two reactors along with the imported Controller and then
connects their ports (lines 9 and 10).

We used the model given by Eker et al. [19] to construct a simple forward-
Euler simulation of an actual pendulum and ran it with our controller. The
results is plotted in Fig. 3. This plot shows that the controller spends a
little more than one second in the SwingUp mode, about 100 msec in the Catch
mode, and then remains in the Stabilize mode.

Figure 3: Plot of behavior using Controller with a simulated pendulum.

We admit that this controller is rather simple and could easily be realized
without the mode extension we propose in this paper. Such a realization is
sketched in Fig. 4. This variant has a preamble of target-language code to
define an enum, and then, in the body of the reaction to sensor inputs, if-
then-else statements are used to determine which control law to invoke.
Although for this example the version without explicit modes is not
unappealing, for more complex systems, we believe that the modal version of
Fig. 2 is more modular and easier to understand. Moreover, Fig. 4a relies on a
hand-written state machine implementation. While this might be acceptable for
just three states, it contradicts the fundamental idea of model-driven
engineering and it is also easily prone to errors, complex to extend, and
hinders formal verification. From a modeling perspective the explicit use of
modes also results in more meaningful diagrams, comparing Fig. 4b to Fig. 2a.
In more advanced modal scenarios, features like mode-local time and history
transitions (explained later) add expressiveness that is not easily replicated
in non-modal LF.

⬇

1target C;

2preamble {=

3 typedef enum {SwingUp, Catch, Stabilize} modes;

4=}

5reactor Controller {

6 input angles:double[];

7 output control:double;

8 state my_mode:modes;

9

10 reaction(angles) -> control {=

11 if (self->my_mode == SwingUp) {

12 ... control law here in C ...

13 lf_set(control, ... control value ... );

14 if ( ... condition ... ) {

15 self->my_mode = Catch;

16 }

17 } else if (self->my_mode == Catch) {

18 ... control law here in C ...

19 lf_set(control, ... control value ... );

20 if ( ... condition ... ) {

21 self->my_mode = Stabilize;

22 }

23 } else {

24 ... control law here in C ...

25 lf_set(control, ... control value ... );

26 if ( ... condition ... ) {

27 self->my_mode = SwingUp;

28 }

29 }

30 =}

31}

(a) LF code

(b) Diagram

Figure 4: Realization of Controller without using modal models.

##  III Reactor-oriented Programming

The reactor-oriented programming paradigm that is central to the LF
coordination language was only introduced recently [21]. It is based based
largely on principles borrowed from well-established paradigms (such as
object-oriended [30], actor-based [13], event-driven [8], flow-based [7],
etc.).

To justify why our contribution extends reactors and not some other model of
computation, we first discuss the key principles of the reactor model and its
advantages that the rest of this paper builds on. Readers already familiar
with that may skip this section. Conversely, we refer readers interested in
more detail, including a formalization, elsewhere [20, 22].

###  III-A Composability and Causality

_Reactors_ are in many ways analogous to objects; they are declared in the
form of an instantiable class, and they offer a form of inheritance. Like
objects, reactors encapsulate state; all state variables in a reactor are
protected, visible to subclasses but otherwise invisible. With objects,
interaction is primarily via method calls. In contrast, reactors have
reactions, ports, timers, and actions, where a _reaction_ is a procedure that
is invoked in response to input, timer, or action events. Unlike a method, a
reaction is not invoked directly, but triggered by the presence of an event.

_Ports_ are terminals through which events are relayed between reactors. Ports
of different reactors can be wired together using connections, enabling a flow
of events. _Actions_ are very similar to ports, but are private and used only
for the scheduling of future events (as opposed to ports, which relay events
that are currently present). There are two kinds of actions: _physical
actions_ , which are meant to be scheduled from an asynchronous context like
an interrupt service routine, and _logical actions_ , which should only be
scheduled during the course of a reaction. While events scheduled using a
logical action is offset with respect to the current tag, events scheduled on
a physical action are offset relative to a measurement from a physical clock.
_Timers_ are actions that are automatically rescheduled with a predefined
periodicity.

Each reaction specifies _triggers_ –ports, actions, or timers that can trigger
it; _sources_ –ports it can read from when triggered; and _effects_ –ports or
actions it may produce an event on. Scoping rules ensure that the data
dependencies expressed in the reaction signature are conservative. Hence,
reaction signatures encode a causality interface [18].

A _composition_ of reactors, then, can be turned into a dependencies graph
that organizes all reactions into partial order that captures all scheduling
constraints that must be observed to ensure that the execution of a reactor
program yields deterministic results. Because this graph is valid irrespective
of the contents of the code that executes when reactions are triggered,
reactions can be treated as a black box. It is this property of reactors that
enables the polyglot nature of LF.

###  III-B Reactivity and Synchronicity

Control is handed to reactions only when there are events that trigger them.
The runtime mechanism behind can be compared to JavaScript’s event loop [24].
The JavaScript event loop, however, is asynchronous, whereas the execution
model of reactors is more like that of the synchronous languages [3], as
execution progresses from one synchronous-reactive “tick” to the next. _Ticks_
correspond to monotonically increasing tags, and only events with a matching
tag are considered present during a particular tick. Outputs produced at a
given tick are logically instantaneous and may consequently trigger more
reactions to occur at the same tick. Importantly, the runtime system ensures
that no reaction executes before all values it may depend on are known. This
is what gives reactors a deterministic semantics.

###  III-C Time and Concurrency

The _tags_ of events delineate a logical timeline, but are also used as a
means to keep the system synchronized with physical time. Tags are pairs
$(t,m)$, where $t$ is a time value and $m$ a microstep index, the latter of
which is only used to enable subsequent ticks to occur without any time
elapsing between them, a concept known as _superdense time_ [25]. The
execution engine starts a new tick once the time value of the earliest
available event tag is greater than the current physical time. This policy
ensures that events scheduled via a _physical action_ (from an asynchronous
thread of execution) can be tagged with the current physical time without
risking out-of-order event tags. The relationship between physical and logical
time in the reactor model gives timers a useful semantics and also permits the
formulation of deadlines [23]. These constructs are particularly practical for
software that operates in cyber-physical systems (like the Furuta pendulum).

Because the execution of reactors is guided by a dependency graph, logically
simultaneous reactions without dependencies between them can transparently be
executed in parallel without introducing any data races, deadlocks, or other
common problems that crop up when multiple threads of execution are involved
[16]. The current runtime implementations in C, C++, and Rust automatically
exploit instances of such parallelism (if the execution platform has multiple
cores). It should be noted that reactions within the same reactor always have
dependencies between them to ensure mutually exclusive access to shared state.
Specifically, the order of declaration in the code determines precedence.

###  III-D Visualization and Pragmatics

The reactor-oriented programming paradigm with components, ports, connections,
and hierarchy, lends itself particularly well to visualizations that can aid
programmers in understanding code. Programming models that are not flow-based
are amenable to control-flow analysis that can deliver graphical renditions to
help explain program behavior, but it is often difficult to determine a
suitable scope or grain for such analysis, making them difficult to automate.
More common are visualization that provide insight in a high-level software
architecture (e.g., class diagrams) but, while easy to automate, these reveal
little about actual program behavior.

LF comes with an automatic interactive diagram synthesis capability, tailored
to enhance developer’s grasp of their code and increase their productivity.
One could say that LF capitalizes on “pragmatics” [33] when it comes to the
handling of models of possibly highly complex systems, with a focus on how to
get the best of both the textual and the graphical worlds. The extension
presented in this paper leverages this capability and augments it with
visualizations tailored to modal reactors. All the LF diagrams, including the
ones presented in this paper, are synthesized automatically from LF code using
a port-aware variant of the well-known Sugiyama algorithm [29], provided by
the Eclipse Layout Kernel (ELK)222https://www.eclipse.org/elk/.

##  IV Modal Reactors

The basic idea of modal reactors is to use the existing reactor model but to
allow for a modal coordination of reactions, by partitioning reactors into
disjoint subsets that are associated with mutually exclusive _modes_. In a
modal reactor, only a single mode can be active at a particular logical time
instant, meaning that activity in other modes is automatically suspended.
_Transitioning_ between modes switches the reactor’s behavior and controls the
starting point of the entered modes. The option to reset or continue with the
mode’s history are common and powerful abstractions that are particularly
helpful in managing complex timed behaviors, which can be extremely error-
prone when carried out manually.

While the ideas behind modal reactors are not new, the guidance by LF’s
fundamental principles towards a polyglot modal coordination layer is novel.
Our goal is to create modal models that are:

  * •

lean a minimal coordination layer that provides the most essential
functionality but still offers maximal versatility and user adjustability;

  * •

polyglot a flexible multi-language wrapper that focuses on the user’s language
and requires only minor adaptation effort;

  * •

concurrent allowing the design of multiple separate modal units acting
independently;

  * •

timed a reliable and precise way to specify time sensitive modal behavior,
even in parallel and distributed environments; and

  * •

deterministic yielding unambiguous and reproducible output behavior for the
same sequence of tagged input events.

Our modal extension to LF embodies these very principles and embraces the
crucial “black box” approach to reactions.

###  IV-A Syntax

The additional syntax required for adding modes is rather minimal. The added
syntax allows reactions to be grouped into modes and includes new keywords for
declaring (initial) modes and specifying transition types. The core LF
language remains unchanged.

Modes can be defined in any reactor. Each mode requires a unique (per reactor)
name and can declare contents that are local to this mode. There must be
exactly one mode marked as initial (see line 5 in Fig. 2). A mode can contain
state variables, timers, actions, reactions, reactor instantiations, and
connections. While the modes cannot be nested in other modes directly,
hierarchical composition is possible through the instantiation of modal
reactors. The main exception in allowed contents in modes are port
declarations, as these are only possible on reactor level. Yet, modes share
the scope with their reactor and, hence, can access ports, state variables,
and parameters of the reactor. Only the contents of other modes are excluded.

Mode transitions are declared within reactions. If a reactor has modes,
reactions are allowed to list them as effects. This enables the use of the
target language API to set the next mode, using lf_set_mode (see also line 9
in Fig. 2b). The compiler will reject the program if the target code
references a mode that is not declared as an effect. The user also has to
specify the type of the transition by adding the modifier reset or history to
the effect. An effect declared as history(<mode>) specifies a _history
transition_ to the mode, rendered in the graphical syntax with an “H” at the
arrowhead (see Fig. 5a).

###  IV-B Modes and Transitions

The basic effect of modes in LF is that only parts that are contained in the
currently active mode, or not contained in any mode, are executed at any point
in time. This also holds for parts that are nested in multiple _ancestor
modes_ due to hierarchy; consequently, all those ancestors must be active in
order to execute. Reactions in inactive modes are simply not executed. All
components that model timing behavior, namely timers, scheduled actions, and
delayed connections, are subject to a concept of _local time_. That means
while a mode is inactive, the progress of time is suspended locally. How the
timing components behave when a mode becomes active depends on the transition
type. A mode can be _reset_ upon entry, returning it to its initial state.
Alternatively, if it was active before, it may continue based on its
_history_. In the latter case all timing components will continue their delays
or period as if no time had passed during inactivity of the mode. Sec. IV-D
will provide further insights to the concept of local time.

Upon reactor startup, the initial mode of each modal reactor is active, others
are inactive. If at a tag $(t,m)$, all reactions of this reactor and all its
contents have finished executing, and a new mode was set in a reaction, the
current mode will be deactivated and the new one will be activated for future
execution. This means no reaction of the newly active mode will execute at tag
$(t,m)$; the earliest possible reaction in the new mode occurs one microstep
later, at $(t,m+1)$. Because of its superdense time model, LF is able to model
a subsequent reaction at the same logical time, but one microstep later.
Hence, if the newly active mode has for example a timer that will elapse with
an offset of zero, it will trigger at $(t,m+1)$. In case the mode itself does
not require an immediate execution in the next microstep, it depends on future
events, just as in the normal behavior of LF. Hence, modes in the same reactor
are always mutually exclusive w. r. t. superdense time. Sec. IV-C will discuss
more details about this design.

A transition is triggered if a new mode is set in a reaction body, as done on
lines 9, 16, and 23 of Fig. 2b. As with setting output ports in reaction, a
new mode can be set multiple times in the same or different reaction. In the
end, the fixed ordering of reactions determines the last effective value that
will be used. The new mode does not have to be a different one; it is possible
for a mode to reset itself via a reset transition.

In case a mode is entered with the reset behavior, all contained modal
reactors are reset to their initial mode (recursively), all local timers are
reset and start again awaiting their initial offset, all events (actions,
timers, delayed connections) that were previously scheduled from within this
mode are discarded, and a newly introduced reset trigger activates associated
reactions in the mode and all contained reactors (recursively).

Thus, whenever a mode is entered with a reset transition, the subsequent
timing behavior is as if the mode was never executed before. By default, state
variables are not reset automatically because it is idiomatic for reactors to
allocate resources or initialize subsystems (e.g., allocate memory or sockets,
register an interrupt, or start a server) in reactions triggered by the
startup, and to store references to these resources in state variables.
Consequently, if startup, as well as shutdown, reactions are used inside
modes, they are subject to special handling when it comes to mode activity, to
ensure correct allocation and deallocation of resources. Sec. IV-E will
elaborate on this topic. In any case, if there are state variables that need
to be reset or reinitialized, then this can be done in a reaction triggered by
reset or by marking their declaration with reset to automate the assignment of
an initial value.

On the other hand, if a mode has been active prior and is then re-entered via
a history transition, no reset is performed. Events originating from timers,
scheduled actions, and delayed connections are adjusted to reflect a remaining
delay equal to the remaining delay recorded at the instant the mode was
previously deactivated. As a consequence, a mode has a notion of local time
that elapses only when the mode is active, see Sec. IV-D.

###  IV-C Timing of Transitions

An important design decision for modes in LF regards the timing of
transitions, i.e., when exactly a transition takes place. There are different
established semantics, the two basic alternatives being an “immediate”
transition or a “delayed” transition where a target mode gets enabled at least
one microstep after the transition is initiated.

With an immediate effect, transitions could occur directly after executing the
initiating reaction, which would instantly activate reactions in the target
mode. This implies dependencies between reactions with transition effects and
reactions in target modes. Such additional dependencies could lead to
causality loops in otherwise legitimate modal models and could reduce
exploitable parallelism. An alternative for timing of transitions could be to
wait until all contents of a mode finished executing but then immediately
switch to the next mode and execute that one still at the same tag. However,
this would raise the question of how to handle the reactivation of the same
mode multiple times at the same tag. Moreover, this would allow an arbitrary
number of mode changes during the same execution instant. In the end, some
notion of a sequential order between mode activations would be necessary,
which is essentially what microsteps are used for in our delayed variant.

In LF, reactions can set a new mode but this has no immediate effect. Only
when the reactor finished executing all its contents, the transition is
performed and the new mode becomes active in the next microstep. With this
design, no two modes in the same reactor can be active at the same tag.
Neither can a transition interfere with ongoing reactions. Yet, this approach
requires resolving potentially “conflicting” transition effects from different
reactions. Here, we apply the same mechanism as already used in setting ports
in LF and determine the effective target mode by relying on the fixed ordering
of reactions within a reactor. In terms of deterministic outcome and
overriding behavior, setting new modes can be considered analogous to
assigning output ports. However, in terms of timing, transition effects
correspond to scheduling actions with a zero delay, which also enforce a
microstep delay to prevent causality cycles.

The design we chose is similar to the design choice in Safety-Critical
Application Development Environment (SCADE) [6], where states within a
reaction are mutually exclusive. It differs from the design choice in
SyncCharts [2] or SCCharts [32], where multiple states may be activated within
one reaction by a sequence of “immediate transitions.” Note that both choices
achieve a deterministic semantics. In the case of SCCharts, determinism is
ensured by means of a predetermined sequential ordering of states.

###  IV-D Local Time

The notion of mode-local time, with the suspension of all timing behavior
within inactive modes, is an established and well-formed principle also found
in modal models in Ptolemy II [17]. The considerations there that favor local
time over alternative approaches also apply to LF. The suspension of time
gives a clear and consistent meaning to the inactivity of modes and provides a
comprehensible state for the mode’s contents upon entry. This especially
favors modularity, as reactors that may be instantiated in modes do not have
to anticipate the fact that their time (driven by timers or scheduled actions)
will advance while their reactions are suppressed. Furthermore, modes allow to
define reactor elements outside of modes, which gives the developer control
over whether time should be local to a mode or not.

(a) The LF Model

(b) The progression of time in each mode and their respective timer

(c) The execution trace with reaction illustration

Figure 5: LF example illustrating the different effects of reset and history
transitions on timers and delays in modes.

Fig. 5 illustrates the different characteristics of local time affecting
timers and actions in the presence of the two transition types. Fig. 5a shows
the generated diagram for a synthetic example program. It consists of two
modes One (the initial mode) and Two, both in the Modal reactor. The next
input toggles between these modes. The input port is controlled by a reaction
at the top level that is triggered by the timer T. After one second, a mode
switch is triggered periodically with a period one second. The modes’ contents
are structured identically. Each has a timer T1/T2 that triggers a reaction
after an initial offset of 100 msec and then periodically after 750 msec. This
reaction then schedules a logical action with a delay of 500 msec (the actual
target code does not add an additional delay over the minimum specified). This
action triggers the second reaction, which writes to the output out. The last
reaction is triggered by the input next and invokes the transition to the
other state. The main difference between the modes is that One is entered via
a history transition, continuing its behavior, while Two is reset.

Fig. 5c illustrates the execution trace of the first 4 seconds of this
program. Below the timeline is the currently active mode and above the
timeline are the model elements that are executed at certain points in time,
together with arrows indicating triggering relations and dashed lines for
distribution through time. For example, at 100 msec, the initial offset of
timer T1 elapses, which leads to the scheduling of the logical action in this
mode. The action triggers the reaction 500 msec later, at 600 msec, and thus
causes an output. The timing diagram illustrates the different handling of
time between history transitions and reset transitions. Specifically, when
mode One is re-entered via a history transition, at time 2000 msec, the action
triggered by T1 before, at time 850 msec, resumes. In contrast, when mode Two
is re-entered via a reset transition, at time 3000 msec, the action triggered
by T2 before, at time 1850 msec, gets discarded.

Fig. 5b illustrates the relation between global time in the environment and
the localized time for each timer in Fig. 5. Since the top-level reactor
TimingExample is not enclosed by any mode, its time always corresponds to the
global time. Mode One is the initial mode and hence progresses in sync with
TimingExample for the first second. During inactivity of mode One the timer is
suspended and does not advance in time. At 2000 msec it continues relative to
this time. T2 only starts advancing when the mode becomes active at 1000 msec.
The reentry via reset at 3000 msec causes the local time to be reset to zero.

In short, from the perspective of timers and actions, time is suspended when a
mode is inactive. This also applies to indirectly nested reactors within
modes. In the same way, connections with logical delays (given in LF by the
after keyword) are affected by local time, if their source lies within a mode.
This corresponds to that fact that delayed connections are to a certain degree
syntactic sugar for connections delayed by a logical action.

###  IV-E Startup and Shutdown

One design challenge we faced was figuring out how to handle start and end of
program execution. LF defines two special triggers, startup and shutdown. A
reaction triggered by startup will execute during the very first tag at which
the reactor exists, and one triggered by shutdown will execute during the very
last tag before the reactor ceases to exist. These are commonly used to set up
a reactor, for example to allocate memory for state variables, initial sensors
or actuators, or start external threads (e.g., to listen for network inputs).
The shutdown reactions subsequently clean up before exiting. What if such
reactions are found within a mode? Should these be executed upon entering or
exiting a mode?

We considered several different options and came to the conclusion that all of
them had some oddities and strange corner cases. We have implemented a
strategy that is simple to explain, deterministic, and enables workarounds for
all the oddities we have been able to identify, but we admit a level of
dissatisfaction. Our solution is a compromise.

First, we invoke startup reactions at most once at the first activation tag of
a mode. Second, we invoke shutdown reactions at the last tag before the
containing reactor ceases to exist (usually just prior to the program
exiting), irrespective of mode, but we only invoke those reactions in modes
that have activated at least once. Hence, every startup has a corresponding
shutdown. Third, as explained earlier, we introduced a new reset trigger for
reactions. Reactions triggered by reset will execute each time a mode is
entered via a reset transition.

Consider, for example, memory allocation and deallocation. These can now be
done safely within a mode in startup and shutdown reactions, although this
strategy will have the disadvantage that memory does not get deallocated while
a mode is inactive. To allocate memory for use only while a mode is active, a
programmer could allocate the memory in a reset reaction and deallocate it in
any reaction that calls lf_set_mode to exit the mode. The programmer would
then have to ensure that every entering transition is a reset transition.

An oddity that results from our design is that shutdown reactions are invoked
even in inactive modes. Normally, no reaction of an inactive mode should be
invoked. This is the only exception, but it ensures that every triggering of a
startup reaction is matched by a corresponding triggering of a shutdown
reaction.

An alternative solution, executing shutdown upon leaving a mode, makes history
transitions infeasible. We also considered scattering shutdown reactions
across multiple consecutive microsteps so that no two distinct modes had
logically simultaneous reactions. This seemed difficult to explain and likely
to lead to even more peculiar oddities. A third possibility we considered was
executing all startup reactions at the beginning, also disregarding whether a
mode is active. But this makes startup reactions as strange as shutdown
reactions, and we felt it was better to have fewer strange behaviors.

###  IV-F Mode Diagrams

As mentioned in Sec. III-D, we consider (automatic) diagramming to be an
important aspect of LF and also adopt modal behavior as a first-class citizen
to this graphical notation. Even if the actual triggering of a mode change is
in the verbatim target code and not part of the LF language itself, the
declaration of modes and potential transitions in the reaction interface is
sufficient to provide the user with mode diagrams. However, one may specify
state transitions at the LF level that do not actually exist in the host code
(but not vice versa as explained in Sec. IV-A). Thus, mode diagrams are
conservative in that they show all possible behaviors, but they may show
transitions that are not realized in the host code.

An important design decision for LF diagrams is how data flow and control flow
should visually relate to each other. In LF, reactors are denoted with rounded
rectangles and their data flow is visualized with rectangular edge routing.
Following established practices for state machine models, modes are added as
rounded rectangles as well but with a different color scheme. Initial states
are indicated with a thicker outline. Fig. 2a illustrates this notation. State
transitions are drawn as splines. For transitions that continue the behavior
in the mode as in Fig. 5a, we add a circled “H” in front of the arrow to
represent that this mode will be entered including its previous history.

In contrast to other LF diagrams in this paper, the transitions in Fig. 2a
also feature labels. LF diagrams offer various ways for a user to influence
the appearance and level of detail in diagram. Accordingly, modes also have
some configuration options, such as the presence of labels. The labels can
provide additional value because they indicate which inputs and/or actions
could cause a mode transition to be taken. Again, labeling is subject to
certain design considerations. Traditionally, transition labels include
triggers and effects. However, this would require an analysis of host code
contradicting the polyglot approach, and the conditions that actually lead to
taking a transition, as well as the effects that result from taking that
transition, might become arbitrarily complex. We therefore opted to restrict
the transition labels to the events that _may_ trigger a reaction, omitting
whatever further logic inside the host code determines whether a transition
will actually be taken. If labels are configured to not be present and leading
to an absence of any distinguishing factors, we bundle multiple transitions
between the same modes into one.

Another, less obvious question is how to integrate reactions dependencies into
the new layer of modes and transitions. One option would be to try to mix all
these edges. However, this would mean that data flow edge may need to cross
the hierarchy level of the mode to connect any content of the mode. We created
several visual mockups for that. All variants that included some form of
cross-hierarchy edges, were considered quite messy as soon as they exceeded a
trivial size. Additionally, the interaction for collapsing modes to hide their
contents and the feasibility with respect to automatic layout algorithms was
considered. In the end, we opted for breaking up these outside connections on
the level of each mode. This makes some connections more implicit but leads to
cleaner diagrams and simplifies the layout problem. For ports, we duplicate
those used in a mode and represent them by their arrow figure. The name is
used to create an association to the original reactor port. In Fig. 2a you can
see this in the angles input triggering reactions. For connections to reactor
elements that are defined outside of modes, e. g. a timer, we create
artificial port-like elements to illustrate their relation.

##  V Implementation

The goal of creating a minimally invasive mode extension is not only reflected
in the language design itself but also in its runtime implementation. LF with
its polyglot approach supports various target languages. At the time of
writing this paper, modes are implemented for C and Python, but extending this
is already planned for future development. Nonetheless, modes have already
been successfully tested for these targets with single-threaded, multi-
threaded, and distributed execution. For the remaining course of this section,
we will provide a generic and reasonably target language-independent view on
the adjustment required to support modes, achieving the behavior described in
Sec. IV. The actual implementation can be found in the LF project on
GitHub.333https://github.com/lf-lang

Code generated by LF consists of two parts. First, the program-specific parts
that represent the components and topology of the program itself, such as
reactors, their actual instantiation, and interconnection. The second part is
a generic runtime environment that among other things handles processing and
scheduling of events in the event queue or triggering and execution of
reactions. The adjustments for extending both parts towards modes are
relatively small. Moreover, they are mostly additive, which means that in the
absence of modes in the source model, there is virtually no difference to an
implementation that does not account for modes444Some data structures require
references to a potentially enclosing mode. This is necessary to enable the
use of pre-compiled reactors in modal reactors. However, this only results in
a minimal memory overhead of pointers that remain unused in the absence of
modes..

The existing runtime implementation needs to be adjusted in two ways. First,
the triggering of reactions must check if a reaction is in an active mode and
otherwise prevent its execution. A trivial approach is to recursively check a
mode and all its parent modes whether they are all the currently active mode,
while any element associated with no mode at all is considered always active.
Shutdown reactions are excluded from this activity check but their mode (if
any) must have had a startup phase, which is additionally recorded when
executing these reactions. Second, the execution life-cycle requires the
handling of transitions. It must be invoked after processing of reactions has
finished but before the logical time advances.

Alg. 1 presents the procedure that handles mode transitions, which includes
performing resets, managing local time, and scheduling special triggers. The
algorithm relies on a few global data structures: (1) the existing event queue
of LF (EventQueue), which manipulation is the sole change to the runtime that
is needed to implement local time; (2) a collection to store events suspended
in local time (SuspendedEvents); and (3) a set of all modal reactor instances
in the model (ModalReactors). The latter is a result of program-specific
generated code, as well as a few new data structures and references. Each
modal reactor $r$ provides access to the following information (presented in a
member notation here). $r_{modes}$ denotes the set of modes in $r$.

$r$.parentMode $\in\\{$Nil$\\}\cup\\{x_{modes}:x\in\text{ModalReactors}\\}$

$r$.initialMode $\in r_{modes}$

$r$.currentMode $\in r_{modes}$

$r$.nextMode $\in\\{$Nil$\\}\cup r_{modes}$

$r$.transition $\in\\{$None, Reset, History$\\}$

$r$.parentMode is either absent or the mode immediately containing $r$. Note
that this models only a unidirectional relation for mode hierarchy. While one
could also consider introducing a list of contained modal reactors, we kept
this notation to stick close to our actual implementation, despite structural
consequences for the algorithm. $r$.initialMode is the mandatory initial mode.
As the parent mode, both values are constant and set up at program start.
$r$.currentMode is the currently active mode w. r. t. to $r$, starting with
the initial mode. Whether the current mode is actually active w. r. t.
execution depends additionally on parent modes. $r$.nextMode and
$r$.transition represent the presence, type, and target of a transition. These
fields are filled if the target code sets a new mode, e. g. in line 9 of Fig.
2b. The transition type is actually inferred from the effect definition.
Furthermore, each mode $m$ in $r_{modes}$ carries additional mode-specific
information.

$m$.reactor $\in\text{ModalReactors}$

$m$.leaveTime $\in\mathbb{T}$

$m$.reset $\in\\{\text{True},\text{False}\\}$

$m$.hadStartup $\in\\{\text{True},\text{False}\\}$

$m$.reactor is a constant reference to the mode’s reactor. $m$.leaveTime
stores the logical time at which this mode was last left. It is initialized
with the start time of the execution. $m$.reset indicates that this mode needs
to be reset as soon as it becomes active (initially False). $m$.hadStartup is
a boolean flag that is set from False to True as soon as the mode is active
for the first time. Finally, each reaction, timer, and action also has a
reference to its immediately enclosing mode, if any exist. This allows
associating events with modes via their trigger.

Algorithm 1 Processing of mode transitions at the end of each execution cycle.

1:for each $r\in$ topdown(ModalReactors) do

2: if $r$.parentMode $\neq$ Nil and

3: $r$.parentMode.reactor.transition $=$ Reset then

4: $r$.nextMode := $r$.initalMode

5: $r$.transition := Reset

6: end if

7:end for

8:for each $r\in$ ModalReactors do

9: if $r$.transition $\neq$ None then

10: for each $e\in$ SuspendedEvents do

11: if $e$.mode $=$ $r$.nextMode then

12: Remove $e$ from SuspendedEvents

13: if $r$.transition $=$ Reset then

14: if $e$ is Timer then

15: $t$ := shift(currentLTime, $e$.timer.offset)

16: Insert $e$ into EventQueue with tag $t$

17: end if

18: else

19: $t$ := shift(currentLTime,

20: $e$.tag - $e$.mode.leaveTime)

21: Insert $e$ into EventQueue with tag $t$

22: end if

23: end if

24: end for

25: if $r$.transition $=$ Reset then

26: $r$.nextMode.reset := True

27: end if

28: $r$.currentMode.leaveTime := currentLTime

29: $r$.currentMode := $r$.nextMode

30: $r$.nextMode := Nil

31: $r$.transition := None

32: end if

33: if isActive($e$.currentMode) then

34: if not $r$.currentMode.hadStartup then

35: Trigger startup reactions in $r$.currentMode

36: at the next microstep

37: end if

38: if $r$.currentMode.reset then

39: $r$.currentMode.reset := False

40: Trigger reset reactions in $r$.currentMode

41: at the next microstep

42: Reset state variables in $r$.currentMode that are

43: marked with reset

44: end if

45: end if

46:end for

47:for each $e\in$ EventQueue do

48: if not isActive($e$.mode) then

49: Remove $e$ from EventQueue

50: Add $e$ to SuspendedEvents

51: end if

52:end for

In the first line of Alg. 1, every modal reactor instance is processed in a
top-down order. This refers to the partial order of mode hierarchy and ensures
that if a mode is entered with a reset, inner modal reactors (line 3)
transition to their initial state with a reset transition recursively.
Afterwards, transitions are processed in a separate iteration. This iteration
is separated from the previous iteration because the hierarchical reset relies
on the presence of transition information in parent modes to reset itself
accordingly (line 3) and this information is now overwritten (line 31). First,
events of the next mode that are suspended in time are processed. At a reset,
all timers are restarted with the initial offset relative to the current time
(line 15). Other events (e. g. scheduled actions) are dropped. For
reintroducing previously suspended events into the event queue, the shift
function is used to create the correct tag w. r. t. superdense time:
$\text{shift}(\text{base}:(t,m),\text{offset}:(t,m))$

$\begin{array}[]{c}=\begin{cases}\text{offset}_{t}>0:&(\text{base}_{t}+\text{offset}_{t},\text{offset}_{m})\\\
\text{offset}_{t}=0:&(\text{base}_{t},\text{base}_{m}+\text{offset}_{m}+1)\end{cases}\end{array}$

This creates a tag that is the base tag shifted by a given offset into the
future. It takes into account that a zero delay offset (w. r. t. the timestamp
$t$) results in a future (incremented) microstep. In case time should continue
due to a history transition (starting line 18), all events are reintroduced
into the event queue with an adjusted target time. Here, the time that mode
was left is subtracted from the original tag (time to happen) of the event, to
get the remaining time at time of leaving, which is used to offset this event
from the current time (line 19). Next, the actual effect of the transitions is
applied to the internal data structures (lines 25 to 32). This includes
marking the mode for reset if necessary, storing the time the mode was left,
setting the new mode, and clearing transition information for use in future
execution. Afterwards, the special reactions are triggered for the current
mode. Note that this takes effect based on mode activity and not triggered by
a transition (line 33). The isActive function relies on the definition
presented before. If the mode was never active before, its startup reaction
will be triggered at the next microstep. This includes reactions in the mode
and in all inner non-modal reactors. Likewise, reset reactions are triggered
when the mode is marked for a reset. Additionally, the automatic reset for the
respective state variables is invoked, and the flag is cleared. Finally, all
events that are associated with now inactive modes are pulled from the event
queue and stored in the suspended events collection (lines 47–52).

In the real implementation of Alg. 1, the procedure includes some additional
consistency checks, optimizations, and handles for some minor corner cases.
However, as these are not relevant for the overall semantics, we left them out
here for ease of readability. Overall, the algorithm is fairly compact while
providing the bulk of semantic functionality for modes.

##  VI Discussion

###  VI-A Strong vs. Weak Preemption

Mode transitions typically imply a _preemption_ of some behavior associated
with the mode that is left. Synchronous statechart dialects, such as
SyncCharts and SCCharts, distinguish between a _strong preemption_ , where
such inner behavior is not executed anymore in the tick that the preemption
takes place, and _weak preemption_ , where modes still execute a “last wish”
in that tick. Thus, it would for example in SyncCharts constitute a compile-
time causality error if a state could emit a signal that would strongly
preempt that state.

Technically, transitions in modal reactors are weak, in the sense that even
when a mode change takes place, all reactions still get to execute at the
current tick. One argument for the absence of strong preemption in the
synchronous sense at the LF level is that it is the modes themselves that
determine transitions to other modes, leading to the aforementioned causality
issues in case of a strong preemption. We considered some alternatives for
adding strong preemption, such as special “initial” reactions that would
determine at the beginning of a reaction whether a preemption should take
place or not, and which might suppress subsequent reactions. However, we
quickly realized that LF already has this capability with no additions. The
decision to take a transition is made in target-language code, and the
programmer is free to make that decision early and prevent further computation
in that mode. Thus, the transitions offered by modal reactors already allow to
realize both types of preemptive behavior.

###  VI-B Transition Types

Sec. IV-D already discussed why we chose to support delayed transitions at the
LF level and not immediate transitions. Some languages, such as SCADE or
SCCharts, also offer a _deferred_ transition that suppresses the immediate
reaction of an entered state, as opposed to non-deferred transitions, that
immediately activate the behavior of the target state. Since modal reactors
never execute target states in the same microstep, one might argue that our
transitions are always deferred.

Statecharts dialects usually use _priorities_ to assign an order to available
transitions with the higher priority transition preempting lower ones. Modes
in LF have exactly the inverse behavior, where the _last_ invocation of
lf_set_mode determines the target mode. An implementation that favors the
first invocation of lf_set_mode could easily be achieved but we prefer a
semantics that conforms with the behavior of ports.

Finally, some statechart dialects also distinguish _deep_ and _shallow_
history transitions, which differ in whether its affect is propagated
downwards in hierarchy or not. Recalling our transitions semantics from Sec.
IV-B and in Alg. 1, it becomes apparent that we currently feature a deep
variant. We briefly considered adding a shallow variant to modal reactors, but
did not consider the added complexity that this would have implied as
justified. Again, we would argue that if this behavior would really be
desired, it could still be realized at target language level.

(a) Example with multiple feeders (reaction and two reactors) to the same
output port (out) but separated by modes.

(b) Example with a cyclic dependency resolved by the use of modes.

Figure 6: Two examples for LF models that can be accepted as
determenistic/causal due to the use of modes.

###  VI-C Modes and Causality

As explained, the availability of reset and continue transitions offers a
level of control over behavior w. r. t. time that is not easily achievable
using simple in-code workarounds. The same holds for the possibility to
express mutual exclusion structurally with modes. This lifts certain modeling
restrictions imposed under the standard LF model of computation. For example,
in the absence of modes, an output port must not be fed by multiple
connections to reactors or a mix of reactions and reactors, as this would be a
potential source of nondeterminism. Modes allow such configurations provided
that each writer is located in a separate mode to ensure mutual exclusivity
between the outputs (see Fig. 6a for an example).

The same reasoning applies to causality problems imposed by feedback loops.
The use of modes enables a more fine-grained, less conservative dependency
analysis. For example, the program in Fig. 6b would be rejected in the absence
of modes due to the following causality loop: in1 – out1 – in2 – out2 – in1.
Mutual exclusivity between the two modes eliminates the causal cycle.

###  VI-D Modes as Mutations

As presented here, modes are designed as core language feature of LF. At the
onset, we also considered to realize modes based on mutations, which are
already part of the formal definition of reactors [21]. However, while this
would be possible to a certain degree, there are methodical considerations
that argue against this. First, mutations are supposed to remodel the topology
of a LF at runtime, while modes are built around the idea of activity and
inactivity and as such always statically present. Second, the creation and
destruction of reactors by mutations at this point does not account for any
previous state. This makes the analogy that a transition is the destruction of
the old mode and the creation of the new one rather complicated if a continue
behavior is desired. As proposed here, continue is simply the absence of a
reset.

###  VI-E Formal Analysis of Modes

The integration of modes in the language offers new opportunities for
verification and model checking, as more structural information is statically
present. However, a limitation of the current design is the location of
transition triggering inside the reaction code. As other effects declared on
reactions, a transition effect to some target mode declared at LF level only
reflects the potential for such an effect. The actual invocation depends on
the execution of the reaction code. This in turn depends on the presence of
any of the triggers and their runtime value. Hence, there is no real static
estimation for active modes without target code execution. However, this is
true in general for any state-dependent verification in LF. With state
variables and ports representing values in the target languages, there is an
implicit limitation to target language independent simulation. Hence, the
declaration of potential transition targets as effects is in line with the
polyglot approach of LF and sufficient for diagram generation and structural
analyses. The extension of verification capabilities including modes is
currently considered for the future development of LF.

##  VII Related Work

We are not aware of other work that aims to create a polyglot modal
coordination layer based on a reactor-like foundation. However, there clearly
is significant related work that our proposal builds on.

The synchronous modeling language SCADE [6] originally had a dataflow focus,
where concurrently operating nodes communicate via streams. However, from
version 6 onwards, it includes state machines as well, based on the mode
extension proposed by Colaço et al. [5]. Their work is perhaps closest in
spirit to what we propose here, also because they manage to enable modes
through a minimal language extension. Specifically, they introduce modes,
quite elegantly, by extending originally boolean clocks, which control
execution in Lustre/SCADE, to a richer type that encodes modes. SCADE
represents a standalone language and while it is able to integrate with its
target languages and coordinate behavior through signals, it does not embody
the rigorous polyglot coordination nature envisioned by LF.

More generally, there are many state machine notations, beyond flat finite-
state machines, that offer feature-rich language constructs. The most
prominent and powerful ones are statecharts by Harel [12], which realize
hierarchical state machines and are also part of Unified Modeling Language
(UML). The statechart dialects that emerged in the context of synchronous
languages, such as SyncCharts [2] or SCCharts [32], are of particular
relevance for modes in LF as their semantics also involve a clear notion of
time and reactions. There is some work on incorporating physical time into the
synchronous model of computation in a way that preserves determinism [28, 9].
However, typically a “multiform notion of time” is based on counting events,
such as the passage of 1 msec.

It is also common practice to express statecharts directly in classical
programming languages without real language extensions, similar to Fig. 4.
Samek describes how to express UML Statecharts in C/C++ [27]. As in UML
Statecharts, this approach does not provide deterministic concurrency. Wagner
et al. describe how to implement FSMs in C [34], but these are flat automata
without any concurrency. Moreover, none of them follows a polyglot
coordination approach.

Similarly, the Akka framework [26] provides means to write actor networks
directly in Java, but without consideration of modes or determinism.

Various proposals have been made to augment mainstream programming languages,
such as C, with a concept of state or modes. The Esterel-C Language (ECL) [15]
is a proposal to extend C by Esterel-like constructs for signal handling and
reactive control flow, and from this program the ECL compiler derives an
Esterel part and a purely sequential C part. FairThreads [4] is another
extension of C inspired by Esterel, implemented via native threads, that
offers macros to express automata. Precision Timed C (PRET-C) [1], which
focuses on temporal predictability and assumes a target architecture with
specific support for thread scheduling and abort handling, and ForeC [35],
which targets multi-core architectures, introduce a modal behavior into C
programs via pause statements. Among these synchronous extensions to C,
perhaps closest to our proposal are SyncCharts in C, which augment C with a
light-weight language extension, realized as C macros, that provides modes
based on SyncCharts [31]. The macros realize states and concurrency by
controlling execution with coarse-grain program counters, technically realized
with ordinary C labels and computed gotos. Determinism is achieved by
dispatching concurrent threads according to (typically static) priorities.

##  VIII Conclusion and Outlook

Modal reactors enable the coordination of reactive behavior in terms of modes
and transitions. While we capitalize of many existing concepts of LF to
achieve our objectives of being lean, polyglot, concurrent, timed, and
deterministic, our design carefully adapts these fundamental principles and
seamlessly integrates into the existing language, diagrams, and tooling. Modes
are a fundamental concept in real-time systems and how designers think about
them. They go beyond specifying low-level stateful behavior in state machines.
Modal coordination in this context enables the orchestration of complex event
processing networks associated with different modes of operation.
Additionally, with mode-local time, it grants a powerful tool for modeling
timed-behavior. Pausing and continuing mode-local behavior is a capability
that is otherwise tedious to achieve in LF.

While modes are already central to a large family of existing programming and
modeling languages, our approach of building modal abstractions into the
polyglot coordination language LF has the advantage of being applicable to a
range of target languages at once. Programmers can still develop the low-level
“business logic” in any target language supported by LF, and may use LF solely
to express modal aspects in a lean, deterministic manner, with diagramming
support, largely irrespective of which other LF facilities might be harnessed
as well. Our implementation currently provides modal support for the C and
Python targets, demonstrating the versatility of our approach. While other
targets will follow, the C target illustrates the suitability for embedded
low-level applications, while Python shows compatibility with a high-level
scripting language commonly used in Cloud and machine learning applications.
We also successfully used modes in LF to control a robot and specify different
modes for driving and collision avoidance. It will be used to teach students
the modeling and design of embedded systems.

A key design decision of modal reactors is that we want to preserve the clear
separation of coordination language (LF) and target language (C, Python, Rust,
…). At the LF level, we express the modal structure, modes encapsulating
components and transitions. We go so far as to define which modes are initial,
and which reactions may trigger which transitions. However, the actual run-
time behavior, concerning invoking transitions and effects, is handled in the
target language via reactions. Yet, the role of the target language only
limited to triggering transitions, while the entire modal infrastructure and
behavior is automatically generated. Due to the separation at the LF level,
modes are abstractions of actual behavior. Whether a mode is actually
reachable or not is not specified at the LF level but depends on the
implementation.

While the static aspects of modes already yield a certain amount of structural
information that could be used for model checking, a natural question is
whether a holistic analysis of both is feasible and worthwhile. To some
extent, this is already taking place during compilation, where for example
type compatibility or, in the case of nodes, the consistency of mode
transitions is checked. However, as discussed in VI-E, a possible future work
would be to perform model checking on LF programs in a “white-box” manner that
also considers the target language, akin for example to SPIN [14]. We also
plan to develop tools for verification and model checking of modal reactors.
Another direction is the exploration of modal models coordinating federated LF
programs.

Finally, we are interested exploring whether modes or alternative (minimal)
language extensions can be used to express the behavior trees in LF.

## References

  * [1] S. Andalam, P. S. Roop, and A. Girault, “Predictable multithreading of embedded applications using PRET-C,” in _Formal Methods and Models for Codesign (MEMOCODE)_. IEEE/ACM, 2010, Conference Proceedings, pp. 159–168.
  * [2] C. André, “Computing SyncCharts reactions,” _Electronic Notes in Theoretical Computer Science_ , vol. 88, pp. 3–19, Oct. 2004.
  * [3] A. Benveniste, P. Caspi, S. Edwards, N. Halbwachs, P. Le Guernic, and R. de Simone, “The synchronous languages 12 years later,” _Proceedings of the IEEE_ , vol. 91, no. 1, pp. 64–83, 2003.
  * [4] F. Boussinot, “Fairthreads: mixing cooperative and preemptive threads in C,” _Concurrency and Computation: Practice and Experience_ , vol. 18, no. 5, pp. 445–469, Apr. 2006.
  * [5] J.-L. Colaço, G. Hamon, and M. Pouzet, “Mixing signals and modes in synchronous data-flow systems,” in _ACM International Conference on Embedded Software (EMSOFT’06)_. Seoul, South Korea: ACM, Oct. 2006, pp. 73–82.
  * [6] J. Colaço, B. Pagano, and M. Pouzet, “SCADE 6: A formal language for embedded critical software development (invited paper),” in _11th International Symposium on Theoretical Aspects of Software Engineering TASE_ , Sophia Antipolis, France, Sep. 2017, pp. 1–11.
  * [7] M. E. Conway, “Design of a separable transition-diagram compiler,” _Communications of the ACM_ , vol. 6, no. 7, pp. 396–408, 1963.
  * [8] F. Dabek, N. Zeldovich, F. Kaashoek, D. Mazières, and R. Morris, “Event-driven programming for robust software,” in _Proceedings of the 10th Workshop on ACM SIGOPS European Workshop_ , ser. EW 10. New York, NY, USA: Association for Computing Machinery, 2002, p. 186–189.
  * [9] S. A. Edwards and J. Hui, “The sparse synchronous model,” in _2020 Forum for Specification and Design Languages (FDL)_ , 2020, pp. 1–8.
  * [10] K. Furuta, M. Yamakita, and S. Kobayashi, “Swing-up control of inverted pendulum using pseudo-state feedback,” _Proceedings of the Institution of Mechanical Engineers, Part I: Journal of Systems and Control Engineering_ , vol. 206, no. 4, pp. 263–269, 1992.
  * [11] G. Hamon and J. Rushby, “An operational semantics for stateflow,” in _International Conference on Fundamental Approaches to Software Engineering_. Springer, 2004, pp. 229–243.
  * [12] D. Harel, “Statecharts: A visual formalism for complex systems,” _Science of computer programming_ , vol. 8, no. 3, pp. 231–274, 1987.
  * [13] C. Hewitt, “Viewing control structures as patterns of passing messages,” _Journal of Artificial Intelligence_ , vol. 8, no. 3, pp. 323–363, 1977.
  * [14] G. J. Holzmann, “Logic verification of ANSI-C code with SPIN,” in _Proceedings of the 7th International SPIN Workshop on SPIN Model Checking and Software Verification_. Berlin, Heidelberg: Springer-Verlag, 2000, p. 131–147.
  * [15] L. Lavagno and E. Sentovich, “ECL: a specification environment for system-level design,” in _Proc. 36th ACM/IEEE Conf. on Design Automation (DAC’99)_. ACM, 1999, pp. 511–516.
  * [16] E. A. Lee, “The problem with threads,” _Computer_ , vol. 39, no. 5, pp. 33–42, 2006.
  * [17] E. A. Lee and S. Tripakis, “Modal models in Ptolemy,” in _3rd International Workshop on Equation-Based Object-Oriented Modeling Languages and Tools (EOOLT)_ , vol. 47. Linköping University Electronic Press, Linköping University, 2010, pp. 11–21.
  * [18] E. A. Lee, H. Zheng, and Y. Zhou, “Causality interfaces and compositional causality analysis,” _Foundations of Interface Technologies (FIT), Satellite to CONCUR, San Francisco, CA_ , vol. 2, pp. 402–405, 2005.
  * [19] J. Liu, J. Eker, J. W. Janneck, and E. A. Lee, “Realistic simulations of embedded control systems,” _IFAC Proceedings Volumes_ , vol. 35, no. 1, pp. 391–396, 2002.
  * [20] M. Lohstroh, “Reactors: A deterministic model of concurrent computation for reactive systems,” Ph.D. dissertation, EECS Department, University of California, Berkeley, Dec 2020. [Online]. Available: http://www2.eecs.berkeley.edu/Pubs/TechRpts/2020/EECS-2020-235.html
  * [21] M. Lohstroh, Í. Íncer Romeo, A. Goens, P. Derler, J. Castrillon, E. A. Lee, and A. Sangiovanni-Vincentelli, “Reactors: A deterministic model for composable reactive systems,” in _8th International Workshop on Model-Based Design of Cyber Physical Systems (CyPhy’19)_ , vol. LNCS 11971\. Springer-Verlag, 2019, Conference Proceedings, p. 27.
  * [22] M. Lohstroh, C. Menard, S. Bateni, and E. A. Lee, “Toward a Lingua Franca for deterministic concurrent systems,” _ACM Transactions on Embedded Computing Systems (TECS), Special Issue on FDL’19_ , vol. 20, no. 4, p. Article 36, May 2021.
  * [23] M. Lohstroh, C. Menard, A. Schulz-Rosengarten, M. Weber, J. Castrillon, and E. A. Lee, “A language for deterministic coordination across multiple timelines,” in _2020 Forum for Specification and Design Languages (FDL)_. IEEE, 2020, pp. 1–8.
  * [24] M. C. Loring, M. Marron, and D. Leijen, “Semantics of asynchronous javascript,” _SIGPLAN Not._ , vol. 52, no. 11, p. 51–62, oct 2017.
  * [25] Z. Manna and A. Pnueli, “Verifying hybrid systems,” in _Hybrid Systems_. Springer, 1992, pp. 4–35.
  * [26] R. Roestenburg, R. Bakker, and R. Williams, _Akka In Action_. Manning Publications Co., 2016.
  * [27] M. Samek, _Practical UML Statecharts in C/C++Event-Driven Programming for Embedded Systems_. Newnes, 2008.
  * [28] A. Schulz-Rosengarten, R. von Hanxleden, F. Mallet, R. de Simone, and J. Deantoni, “Time in SCCharts,” in _Proc. Forum on Specification and Design Languages (FDL ’18)_ , Munich, Germany, September 2018.
  * [29] C. D. Schulze, M. Spönemann, and R. von Hanxleden, “Drawing layered graphs with port constraints,” _Journal of Visual Languages and Computing, Special Issue on Diagram Aesthetics and Layout_ , vol. 25, no. 2, pp. 89–106, 2014\.
  * [30] B. Stroustrup, “What is object-oriented programming?” _IEEE Software_ , vol. 5, no. 3, pp. 10–20, 1988.
  * [31] R. von Hanxleden, “SyncCharts in C—A proposal for light-weight deterministic concurrency,” in _ACM Embedded Software Conference (EMSOFT)_ , 2009, Conference Proceedings, pp. 11–16.
  * [32] R. von Hanxleden _et al._ , “SCCharts: Sequentially constructive Statecharts for safety-critical applications,” in _ACM SIGPLAN Conf. on Programming Language Design and Implementation_ , ser. PLDI ’14. New York, NY, USA: ACM, 2014, pp. 372–383.
  * [33] R. von Hanxleden, E. A. Lee, H. Fuhrmann, A. Schulz-Rosengarten, S. Domrös, M. Lohstroh, S. Bateni, and C. Menard, “Pragmatics twelve years later: a report on Lingua Franca,” in _11th International Symposium on Leveraging Applications of Formal Methods, Verification and Validation (ISoLA)_ , ser. Lecture Notes in Computer Science, vol. 13702\. Rhodes, Greece: Springer, October 2022, pp. 60–89.
  * [34] F. Wagner, R. Schmuki, P. Wolstenholme, and T. W. Thomas, _Modeling Software with Finite State Machines: A Practical Approach_. Auerbach Publications, 2006.
  * [35] E. Yip, A. Girault, P. S. Roop, and M. Biglari-Abhari, “The ForeC synchronous deterministic parallel programming language for multicores,” in _10th IEEE International Symposium on Embedded Multicore/Many-core Systems-on-Chip, MCSOC 2016, Lyon, France, September 21-23, 2016_. IEEE Computer Society, 2016, pp. 297–304.

  *[LF]: Lingua Franca
  *[SCADE]: Safety-Critical Application Development Environment
  *[UML]: Unified Modeling Language


* van der Wel et al. (2011) van der Wel, A., Straughn, A. N., Rix, H. W., et al. 2011, ApJ, 742, 111, doi: 10.1088/0004-637X/742/2/111
  * Virtanen et al. (2020) Virtanen, P., Gommers, R., Oliphant, T. E., et al. 2020, Nature Methods, 17, 261, doi: 10.1038/s41592-019-0686-2
  * Waskom (2021) Waskom, M. L. 2021, Journal of Open Source Software, 6, 3021, doi: 10.21105/joss.03021
  * Weaver et al. (2022) Weaver, J. R., Kauffmann, O. B., Ilbert, O., et al. 2022, ApJS, 258, 11, doi: 10.3847/1538-4365/ac3078
  * Whitaker et al. (2011) Whitaker, K. E., Labbé, I., van Dokkum, P. G., et al. 2011, ApJ, 735, 86, doi: 10.1088/0004-637X/735/2/86
  * Whitaker et al. (2013) Whitaker, K. E., van Dokkum, P. G., Brammer, G., et al. 2013, ApJ, 770, L39, doi: 10.1088/2041-8205/770/2/L39
  * Whitaker et al. (2014) Whitaker, K. E., Franx, M., Leja, J., et al. 2014, ApJ, 795, 104, doi: 10.1088/0004-637X/795/2/104
  * Whitaker et al. (2021a) Whitaker, K. E., Narayanan, D., Williams, C. C., et al. 2021a, ApJ, 922, L30, doi: 10.3847/2041-8213/ac399f
  * Whitaker et al. (2021b) Whitaker, K. E., Williams, C. C., Mowla, L., et al. 2021b, Nature, 597, 485, doi: 10.1038/s41586-021-03806-7
  * Williams et al. (2018) Williams, C. C., Curtis-Lake, E., Hainline, K. N., et al. 2018, ApJS, 236, 33, doi: 10.3847/1538-4365/aabcbb
  * Williams et al. (2021) Williams, C. C., Spilker, J. S., Whitaker, K. E., et al. 2021, ApJ, 908, 54, doi: 10.3847/1538-4357/abcbf6
  * Williams et al. (2009) Williams, R. J., Quadri, R. F., Franx, M., van Dokkum, P., & Labbé, I. 2009, ApJ, 691, 1879, doi: 10.1088/0004-637X/691/2/1879
  * Williams et al. (2010) Williams, R. J., Quadri, R. F., Franx, M., et al. 2010, ApJ, 713, 738, doi: 10.1088/0004-637X/713/2/738
  * Wold et al. (2019) Wold, I. G. B., Kawinwanichakij, L., Stevans, M. L., et al. 2019, ApJS, 240, 5, doi: 10.3847/1538-4365/aaee85
  * Wolf et al. (2009) Wolf, C., Aragón-Salamanca, A., Balogh, M., et al. 2009, Monthly Notices of the Royal Astronomical Society, 393, 1302, doi: 10.1111/j.1365-2966.2008.14204.x
  * Wuyts et al. (2009) Wuyts, S., Franx, M., Cox, T. J., et al. 2009, ApJ, 696, 348, doi: 10.1088/0004-637X/696/1/348
  * Wuyts et al. (2012) Wuyts, S., Förster Schreiber, N. M., Genzel, R., et al. 2012, ApJ, 753, 114, doi: 10.1088/0004-637X/753/2/114