reactor-c
C Runtime for Lingua Franca
|
#include "lf_types.h"
#include "modes.h"
#include "port.h"
#include "tag.h"
#include "trace.h"
#include "util.h"
Go to the source code of this file.
Macros | |
#define | CONSTRUCTOR(classname) (new_ ## classname) |
#define | SELF_STRUCT_T(classname) (classname ## _self_t) |
#define | _LF_SET(out, val) |
#define | lf_set_array(out, val, length) |
#define | _LF_SET_NEW(out) |
#define | _LF_SET_NEW_ARRAY(out, len) |
#define | lf_set_present(out) |
#define | _LF_SET_TOKEN(out, newtoken) |
#define | _LF_SET_DESTRUCTOR(out, destruct) |
#define | _LF_SET_COPY_CONSTRUCTOR(out, constructor) |
#define | DEADLINE(index) (index & 0x7FFFFFFFFFFF0000) |
#define | OVERLAPPING(chain1, chain2) ((chain1 & chain2) != 0) |
Functions | |
void | _lf_set_present (lf_port_base_t *port) |
void | _lf_executable_preamble (environment_t *env) |
Forward declaration for the executable preamble;. | |
interval_t | lf_get_stp_offset (void) |
void | lf_set_stp_offset (interval_t offset) |
void | lf_print_snapshot (environment_t *env) |
void | lf_request_stop () |
void * | _lf_allocate (size_t count, size_t size, struct allocation_record_t **head) |
void | _lf_free (struct allocation_record_t **head) |
void * | _lf_new_reactor (size_t size) |
void | _lf_free_all_reactors (void) |
void | _lf_free_reactor (self_base_t *self) |
void | _lf_set_default_command_line_options (void) |
void | _lf_start_time_step (environment_t *env) |
void | _lf_initialize_trigger_objects () |
void | _lf_pop_events (environment_t *env) |
trigger_handle_t | _lf_schedule (environment_t *env, trigger_t *trigger, interval_t delay, lf_token_t *token) |
void | _lf_initialize_watchdog_mutexes (void) |
Initialize watchdog mutexes. For any reactor with one or more watchdogs, the self struct should have a non-NULL reactor_mutex field which points to an instance of lf_mutex_t . This function initializes those mutexes. | |
int | _lf_get_upstream_of (int enclave_id, int **result) |
Get the array of ids of enclaves directly upstream of the specified enclave. This updates the specified result pointer to point to a statically allocated array of IDs and returns the length of the array. The implementation is code-generated. | |
int | _lf_get_downstream_of (int enclave_id, int **result) |
Get the array of ids of enclaves directly downstream of the specified enclave. This updates the specified result pointer to point to a statically allocated array of IDs and returns the length of the array. The implementation is code-generated. | |
int | _lf_get_upstream_delay_of (int enclave_id, interval_t **result) |
Retrive the delays on the connections to direct upstream enclaves. This updates the result pointer to point to a statically allocated array of delays. The implementation is code-generated. | |
void | terminate_execution (environment_t *env) |
void | termination () |
trigger_handle_t | _lf_schedule_int (lf_action_base_t *action, interval_t extra_delay, int value) |
event_t * | _lf_create_dummy_event (trigger_t *trigger, instant_t time, event_t *next, unsigned int offset) |
trigger_handle_t | _lf_schedule_token (lf_action_base_t *action, interval_t extra_delay, lf_token_t *token) |
trigger_handle_t | _lf_schedule_value (lf_action_base_t *action, interval_t extra_delay, void *value, size_t length) |
trigger_handle_t | _lf_schedule_copy (lf_action_base_t *action, interval_t offset, void *value, size_t length) |
int | _lf_fd_send_stop_request_to_rti (tag_t stop_tag) |
void | _lf_create_environments () |
Will create and initialize the required number of environments for the program. | |
Copyright (c) 2019, The University of California at Berkeley.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Header file for the infrastructure for the C target of Lingua Franca. This file contains header information used by both the threaded and non-threaded versions of the C runtime.
This header file defines the functions and macros that programmers use in the body of reactions for reading and writing inputs and outputs and scheduling future events. The LF compiler does not parse that C code. This fact strongly affects the design.
The intent of the C target for Lingua Franca not to provide a safe programming environment (The C++ and TypeScript targets are better choices for that), but rather to find the lowest possible overhead implementation of Lingua Franca. The API herein can easily be misused, leading to memory leaks, nondeterminism, or program crashes.
Set the specified output (or input of a contained reactor) to the specified value.
This version is used for primitive types such as int, double, etc. as well as the built-in types bool and string. The value is copied and therefore the variable carrying the value can be subsequently modified without changing the output. This can also be used for structs with a type defined by a typedef so that the type designating string does not end in '*'.
out | The output port (by name) or input of a contained reactor in form input_name.port_name. |
value | The value to insert into the self struct. |
#define _LF_SET_COPY_CONSTRUCTOR | ( | out, | |
constructor | |||
) |
Set the constructor used to copy construct "token->value" received by a downstream mutable input.
out | The output port (by name) or input of a contained reactor in form input_name.port_name. |
constructor | A pointer to a void* function that takes a pointer argument or NULL to use the memcpy operator. |
Set the destructor used to free "token->value" set on "out". That memory will be automatically freed once all downstream reactions no longer need the value.
out | The output port (by name) or input of a contained reactor in form input_name.port_name. |
destruct | A pointer to a void function that takes a pointer argument or NULL to use the default void free(void*) function. |
Version of set() for output types given as 'type*' that allocates a new object of the type of the specified output port.
This macro dynamically allocates enough memory to contain one instance of the output datatype and sets the variable named by the argument to point to the newly allocated memory. The user code can then populate it with whatever value it wishes to send.
This macro also sets the corresponding _is_present variable in the self struct to true (which causes the object message to be sent),
out | The output port (by name). |
Version of set() for output types given as 'type[]'.
This allocates a new array of the specified length, sets the corresponding _is_present variable in the self struct to true (which causes the array message to be sent), and sets the variable given by the first argument to point to the new array so that the user code can populate the array. The freeing of the dynamically allocated array will be handled automatically when the last downstream reader of the message has finished.
out | The output port (by name). |
length | The length of the array to be sent. |
Version of set() for output types given as 'type*' or 'type[]' where you want to forward an input or action without copying it.
The deallocation of memory is delegated to downstream reactors, which automatically deallocate when the reference count drops to zero.
out | The output port (by name). |
token | A pointer to token obtained from an input or action. |
#define DEADLINE | ( | index | ) | (index & 0x7FFFFFFFFFFF0000) |
Macro for extracting the deadline from the index of a reaction. The reaction queue is sorted according to this index, and the use of the deadline here results in an earliest deadline first (EDF) scheduling poicy.
Version of set for output types given as 'type[]' where you want to send a previously dynamically allocated array.
The deallocation is delegated to downstream reactors, which automatically deallocate when the reference count drops to zero. It also sets the corresponding _is_present variable in the self struct to true (which causes the object message to be sent).
out | The output port (by name). |
val | The array to send (a pointer to the first element). |
length | The length of the array to send. |
Version of set() for output types given as 'type[number]'.
This sets the _is_present variable corresponding to the specified output to true (which causes the array message to be sent). The values in the output are normally written directly to the array or struct before or after this is called.
out | The output port (by name). |
Macro for determining whether two reactions are in the same chain (one depends on the other). This is conservative. If it returns false, then they are surely not in the same chain, but if it returns true, they may be in the same chain. This is in reactor_threaded.c to execute reactions in parallel on multiple cores even if their levels are different.
void * _lf_allocate | ( | size_t | count, |
size_t | size, | ||
struct allocation_record_t ** | head | ||
) |
Allocate zeroed-out memory and record the allocated memory on the specified list so that it will be freed when calling _lf_free(allocation_record_t**)
.
count | The number of items of size 'size' to accomodate. |
size | The size of each item. |
head | Pointer to the head of a list on which to record the allocation, or NULL to not record it. |
Allocate memory using calloc (so the allocated memory is zeroed out) and record the allocated memory on the specified self struct so that it will be freed when calling free_reactor(self_base_t)
.
count | The number of items of size 'size' to accomodate. |
size | The size of each item. |
head | Pointer to the head of a list on which to record the allocation, or NULL to not record it. |
event_t * _lf_create_dummy_event | ( | trigger_t * | trigger, |
instant_t | time, | ||
event_t * | next, | ||
unsigned int | offset | ||
) |
Create a dummy event to be used as a spacer in the event queue.
void _lf_create_environments | ( | ) |
Will create and initialize the required number of environments for the program.
void _lf_executable_preamble | ( | environment_t * | env | ) |
Forward declaration for the executable preamble;.
env | Environment in which to execute to preamble |
void _lf_free | ( | struct allocation_record_t ** | head | ) |
Free memory allocated using _lf_allocate(size_t, size_t, allocation_record_t**)
and mark the list empty by setting *head
to NULL.
head | Pointer to the head of a list on which to record the allocation, or NULL to not record it. |
Free memory on the specified allocation record, e.g. allocated by _lf_allocate(size_t, size_t, allocation_record_t**)
. Mark the list empty by setting *head
to NULL.
head | Pointer to the head of a list on which to record the allocation, or NULL to not record it. |
Free all the reactors that are allocated with _lf_new_reactor(size_t)
.
void _lf_free_reactor | ( | self_base_t * | self | ) |
Free memory recorded on the allocations list of the specified reactor.
self | The self struct of the reactor. |
Free memory recorded on the allocations list of the specified reactor and then free the specified self struct.
self | The self struct of the reactor. |
Get the array of ids of enclaves directly downstream of the specified enclave. This updates the specified result pointer to point to a statically allocated array of IDs and returns the length of the array. The implementation is code-generated.
enclave_id | The enclave for which to report downstream IDs. |
result | The pointer to dereference and update to point to the resulting array. |
int _lf_get_upstream_delay_of | ( | int | enclave_id, |
interval_t ** | result | ||
) |
Retrive the delays on the connections to direct upstream enclaves. This updates the result pointer to point to a statically allocated array of delays. The implementation is code-generated.
enclave_id | The enclave for which to search for upstream delays. |
result | The pointer to dereference and update to point to the resulting array. |
Get the array of ids of enclaves directly upstream of the specified enclave. This updates the specified result pointer to point to a statically allocated array of IDs and returns the length of the array. The implementation is code-generated.
enclave_id | The enclave for which to report upstream IDs. |
result | The pointer to dereference and update to point to the resulting array. |
void _lf_initialize_trigger_objects | ( | ) |
Generated function that produces a table containing all triggers (i.e., inputs, timers, and actions).
Initialize watchdog mutexes. For any reactor with one or more watchdogs, the self struct should have a non-NULL reactor_mutex
field which points to an instance of lf_mutex_t
. This function initializes those mutexes.
Function to initialize mutexes for watchdogs
Allocate memory for a new runtime instance of a reactor. This records the reactor on the list of reactors to be freed at termination of the program. If you plan to free the reactor before termination of the program, use _lf_allocate(size_t, size_t, allocation_record_t**)
with a null last argument instead.
size | The size of the self struct, obtained with sizeof(). |
Allocate memory for a new runtime instance of a reactor. This records the reactor on the list of reactors to be freed at termination of the program. If you plan to free the reactor before termination of the program, use calloc instead (which this uses).
size | The size of the self struct, obtained with sizeof(). |
void _lf_pop_events | ( | environment_t * | env | ) |
Pop all events from event_q with timestamp equal to current_time, extract all the reactions triggered by these events, and stick them into the reaction queue.
env | The environment in which we are executing |
Pop all events from event_q with timestamp equal to current_tag.time, extract all the reactions triggered by these events, and stick them into the reaction queue.
env | Environment in which we are executing. |
trigger_handle_t _lf_schedule | ( | environment_t * | env, |
trigger_t * | trigger, | ||
interval_t | extra_delay, | ||
lf_token_t * | token | ||
) |
Internal version of the lf_schedule() function, used by generated _lf_start_timers() function.
env | The environment in which we are executing |
trigger | The action or timer to be triggered. |
delay | Offset of the event release. |
token | The token payload. |
Schedule the specified trigger at env->current_tag.time plus the offset of the specified trigger plus the delay. See schedule_token() in reactor.h for details. This is the internal implementation shared by both the threaded and non-threaded versions.
The value is required to be either NULL or a pointer to a token wrapping the payload. The token carries a reference count, and when the reference count decrements to 0, the will be freed. Hence, it is essential that the payload be in memory allocated using malloc.
There are three conditions under which this function will not actually put an event on the event queue and decrement the reference count of the token (if there is one), which could result in the payload being freed. In all three cases, this function returns 0. Otherwise, it returns a handle to the scheduled trigger, which is an integer greater than 0.
The first condition is that a stop has been requested and the trigger offset plus the extra delay is greater than zero. The second condition is that the trigger offset plus the extra delay is greater that the requested stop time (timeout). The third condition is that the trigger argument is null.
env | Environment in which we are executing. |
trigger | The trigger to be invoked at a later logical time. |
extra_delay | The logical time delay, which gets added to the trigger's minimum delay, if it has one. If this number is negative, then zero is used instead. |
token | The token wrapping the payload or NULL for no payload. |
trigger_handle_t _lf_schedule_copy | ( | lf_action_base_t * | action, |
interval_t | offset, | ||
void * | value, | ||
size_t | length | ||
) |
Schedule an action to occur with the specified value and time offset with a copy of the specified value. If the value is non-null, then it will be copied into newly allocated memory under the assumption that its size is given in the trigger's token object's element_size field multiplied by the specified length. See _lf_schedule_token(), which this uses, for details.
action | Pointer to an action on a self struct. |
offset | The time offset over and above that in the action. |
value | A pointer to the value to copy. |
length | The length, if an array, 1 if a scalar, and 0 if value is NULL. |
Schedule an action to occur with the specified value and time offset with a copy of the specified value. See reactor.h for documentation.
trigger_handle_t _lf_schedule_int | ( | lf_action_base_t * | action, |
interval_t | extra_delay, | ||
int | value | ||
) |
Schedule the specified action with an integer value at a later logical time that depends on whether the action is logical or physical and what its parameter values are. This wraps a copy of the integer value in a token. See schedule_token() for more details.
action | The action to be triggered. |
extra_delay | Extra offset of the event release above that in the action. |
value | The value to send. |
Variant of schedule_value when the value is an integer. See reactor.h for documentation.
action | Pointer to an action on the self struct. |
trigger_handle_t _lf_schedule_token | ( | lf_action_base_t * | action, |
interval_t | extra_delay, | ||
lf_token_t * | token | ||
) |
Schedule the specified action with the specified token as a payload. This will trigger an event at a later logical time that depends on whether the action is logical or physical and what its parameter values are.
logical action: A logical action has an offset (default is zero) and a minimum interarrival time (MIT), which also defaults to zero. The logical time at which this scheduled event will trigger is the current time plus the offset plus the delay argument given to this function. If, however, that time is not greater than a prior triggering of this logical action by at least the MIT, then the one of two things can happen depending on the policy specified for the action. If the action's policy is DROP (default), then the action is simply dropped and the memory pointed to by value argument is freed. If the policy is DEFER, then the time will be increased to equal the time of the most recent triggering plus the MIT.
For the above, "current time" means the logical time of the reaction that is calling this function. Logical actions should always be scheduled within a reaction invocation, never asynchronously from the outside. FIXME: This needs to be checked.
physical action: A physical action has all the same parameters as a logical action, but its timestamp will be the larger of the current physical time and the time it would be assigned if it were a logical action.
There are three conditions under which this function will not actually put an event on the event queue and decrement the reference count of the token (if there is one), which could result in the payload being freed. In all three cases, this function returns 0. Otherwise, it returns a handle to the scheduled trigger, which is an integer greater than 0.
The first condition is that stop() has been called and the time offset of this event is greater than zero. The second condition is that the logical time of the event is greater that the stop time (timeout) that is specified in the target properties or on the command line. The third condition is that the trigger argument is null.
action | The action to be triggered. |
extra_delay | Extra offset of the event release above that in the action. |
token | The token to carry the payload or null for no payload. |
Schedule the specified trigger at env->current_tag.time plus the offset of the specified trigger plus the delay. See reactor.h for documentation.
trigger_handle_t _lf_schedule_value | ( | lf_action_base_t * | action, |
interval_t | extra_delay, | ||
void * | value, | ||
size_t | length | ||
) |
Variant of schedule_token that creates a token to carry the specified value. The value is required to be malloc'd memory with a size equal to the element_size of the specifies action times the length parameter. See _lf_schedule_token() for details.
action | The action to be triggered. |
extra_delay | Extra offset of the event release above that in the action. |
value | Dynamically allocated memory containing the value to send. |
length | The length of the array, if it is an array, or 1 for a scalar and 0 for no payload. |
Variant of schedule_token that creates a token to carry the specified value. See reactor.h for documentation.
Generated function that optionally sets default command-line options.
void _lf_set_present | ( | lf_port_base_t * | port | ) |
Mark the given port's is_present field as true. This is_present field will later be cleaned up by _lf_start_time_step. This assumes that the mutex is not held.
port | A pointer to the port struct. |
Mark the given port's is_present field as true. This is_present field will later be cleaned up by _lf_start_time_step. If the port is unconnected, do nothing. This assumes that the mutex is not held.
port | A pointer to the port struct. |
void _lf_start_time_step | ( | environment_t * | env | ) |
Generated function that resets outputs to be absent at the start of a new time step.
env | The environment in which we are executing |
Use tables to reset is_present fields to false, set intended_tag fields in federated execution to the current_tag, and decrement reference counts between time steps and at the end of execution.
interval_t lf_get_stp_offset | ( | void | ) |
Return the global STP offset on advancement of logical time for federated execution.
void lf_print_snapshot | ( | environment_t * | env | ) |
Print a snapshot of the priority queues used during execution (for debugging).
env | The environment in which we are executing. |
If DEBUG logging is enabled, prints the status of the event queue, the reaction queue, and the executing queue.
env | Environment within which we are executing. |
void lf_request_stop | ( | ) |
Request a stop to execution as soon as possible. In a non-federated execution with only a single enclave, this will occur one microstep later than the current tag. In a federated execution or when there is more than one enclave, it will likely occur at a later tag determined by the RTI so that all federates and enclaves stop at the same tag.
void lf_set_stp_offset | ( | interval_t | offset | ) |
Set the global STP offset on advancement of logical time for federated execution.
offset | A positive time value to be applied as the STP offset. |
void terminate_execution | ( | environment_t * | env | ) |
Function (to be code generated) to terminate execution. This will be invoked after all shutdown actions have completed.
env | The environment in which we are executing |