Startup Process

The runtime process for NUClear has 3 main phases; the Initialization Phase (single threaded), where the system, reactors, and requests are loaded, the Execution Phase (multithreaded) which can be thought of as the general runtime of the system, and the Shutdown Phase (multithreaded), which is the process the system will run through once the shutdown command is executed.

Initialization Phase (single threaded)

There are three main activities which need to occur during the system initialization. These stages will setup the system, before any standard runtime execution occurs. It is important to note that the system will be running on a single thread throughout this phase, and therefore, the order in which the developer lists specific activities is important.

Install the PowerPlant

This phase begins with the installation of the PowerPlant. When installing the PowerPlant, it is recommended to use the NUClear Roles system, as it allows the use of a configuration file for the process.

NUClear::Configuration config;
config.thread_count = 1;
NUClear::PowerPlant plant(config);

Install Reactors

Once the plant is installed, the reactors can be loaded.

plant.install<Reactor1, Reactor2, ... >();

This command will run the reactors constructors, and install them into the PowerPlant. There are two main aspects developers should consider when designing a reactor’s construction.

On Statements

Most of the On Statements which run during a reactor’s construction will setup the binding requests under which Tasks will be created. Any tasks created as a result of local data emission for these reactions will be queued, and will not run until the Execution Phase (multithreaded). Note that this is the standard behaviour, however there are exceptions to this behaviour which developers will find useful. For example:

  • on<Configuration>: This is part of the NUClear Roles system and can be used during a reactors constructor. This request will run immediately, as an in-line binding reaction.

  • on<fileWatcher>: This is part of the NUClear Roles system and can be used during a reactors constructor. This request will run immediately, as an in-line binding reaction.

Data Emission Statements

As the system is single threaded at this time, the order in which reactors are installed can be significantly important. This is pertinent when dealing with any data emissions during reactor construction which are NOT emitted under Scope::Initialise. For example; data emission during the construction of a reactor using Scope::DIRECT, Scope::UDP, or Scope::Network will trigger any necessary activity to run inline. Should any reactions be defined to run as a result of the emission, the task will be generated and also run inline. It is here where the order in which reactors are installed becomes important. Suppose Reactor1 were to emit under Scope::DIRECT, and Reactor2 had a reaction defined to run on the associated datatype. In this case, the reaction defined by Reactor2 would not run, as it was not yet defined at the time of data emission. However, should the roles be reserved, then the reaction would run.

General Rule of Thumb: If a reactor needs to emit data during this phase, it is recommended to use Scope::Initialise. This will put a hold on the data emission, until the next step in the process Initialise Scope Tasks, ensuring that any reactions subscribed to the emission will run. Checkout the Emissions Scope Table for clarity.

Start the PowerPlant

Once the reactors have been installed, and the binding reaction requests have been established, its time to start up the system.

plant.start();

This command will run two main actions before transitioning to the Execution Phase (multithreaded).

Initialise Scope Tasks

Any data emissions which were emitted under a the Scope::Initialise will run at this time. The system is still single threaded, so these emissions will run one by one, in the order they were installed. As the emission run, the associated Tasks will be bound. Tasks generated under these emissions will be queued, but will not start execution until the Execution Phase (multithreaded). Tasks will be queued based on their priority level, then their emission timestamp.

DSL Startup Requests

Any requests using an on<Startup> definition will be generated and will run now. These requests will run one-by-one, using the order in which they were installed. Once these tasks have completed processing, the system will transition to the next phase.

Execution Phase (multithreaded)

This phase is generally referred to as the standard system runtime. During this phase, the threadpool will be started.

Once started, any reactions requested with an on<Always> definition will start running.

The system will then process any reactions requested with an on<MainThread> definition.

From here, any other tasks already queued will be processed and the system will start ticking over as per the setup.

During this phase, the system will be responsive to any of the Managing Reactions commands, as well as any changes to the run time arguments for reactions defined with IO, TCP, UDP, or any other applicable Extension from your system.

The system will tick along, until the shutdown command is given, pushing it into the next phase:

powerplant.shutdown();

Note that all reactors in the system are given a reference to the powerplant object, so that any reactor/reaction with a callback access to the powerPlant. Call the shutdown() command under desired conditions.

Shutdown Phase (multithreaded)

Once the shutdown event is executed, any existing tasks which were already queued will run and finish as normal. Any on<Shutdown>() reaction requests will then be queued (in the order in which they were installed) with Priority::IDLE.

Note that during this phase, any other task which would normally be scheduled as a result of a non-direct emission will be silently dropped, while any tasks which would occur as a result of a Scope::DIRECT emission will interrupt the shutdown process and run as normal.

Emissions Scope Table

Initialization Phase (single threaded)

Execution Phase (multithreaded)

Shutdown Phase (multithreaded)

Scope::LOCAL

Schedules any tasks for reactions which are currently loaded and bound to the emission data. Adds to the queue of tasks to start running when the system shifts to the Execution Phase (multithreaded)

Schedules any tasks for reactions which are bound to the emission data. Adds to the queue of tasks based on the desired Priority level

Any emissions under this scope while the system is in the shutdown phase are ignored.

Scope::DIRECT

Schedules any tasks for reactions which are currently loaded and bound to the emission data. Pauses the initialization phase, and runs the task in-line. The initialization phase continues upon task completion.

Schedules any tasks for reactions which are currently loaded and bound to the emission data. Pauses the task currently executing and runs the new task in-line. The execution phase continues upon task completion.

Schedules any tasks for reactions which are currently loaded and bound to the emission data. Pauses the task currently executing and runs the new task in-line. The shutdown phase continues upon task completion.

Scope::Initialise

Data emitted under this scope during this phase will wait until all reactors have been installed into the powerPlant before triggering any reactions. Any tasks generated as a result of this emission type are the first tasks to run when the powerPlant starts. This is the recommended emission type for this phase of system startup.

Any emissions under this scope while the system is in the execution phase are ignored.

Any emissions under this scope while the system is in the shutdown phase are ignored.

Scope::DELAY

The delay countdown starts at the time of emission. Once the delay time-frame has passed, any tasks for reactions which are currently loaded and bound to the emission data are scheduled. Adds to the queue of tasks to start running when the system shifts to the Execution Phase (multithreaded)

Waits for the associated delay timeframe, then schedules any tasks for reactions which are bound to the emission data. Adds to the queue of tasks based on the desired Priority level

Any emissions under this scope while the system is in the shutdown phase are ignored.

Scope::UDP

Emits the data over the UDP network. Should any UDP reaction request be loaded in the system based on this data emission, schedules the task to run in-line. Pauses the initialization phase, and runs the task in-line. The initialization phase continues upon task completion.

Emits the data over the UDP network. Should any UDP reaction request be loaded in the system based on this data emission, schedules the task to run in-line.

Any emissions under this scope while the system is in the shutdown phase are ignored.

Scope::Network

Emits the data over the NUClear network. Should any network reaction request be loaded in the system based on this data emission, schedules the task to run in-line. Pauses the initialization phase, and runs the task in-line. The initialization phase continues upon task completion.

Emits the data over the NUClear network. Should any network reaction request be loaded in the system based on this data emission, schedules the task to run in-line.

Any emissions under this scope while the system is in the shutdown phase are ignored.