Essential API¶
Note
Many file names and identifiers in this API contain placeholders for event, monitor, and synchronous set names. These placeholders are marked by the use of ALLCAPS.
The generated monitoring code is separated into multiple layers, ordered below from lowest to highest. SMEDL specifications are used to generate the monitor layer, and the rest are generated from the architecture specification.
- Monitor
Actual monitor logic for a single SMEDL specification
- Local wrapper
Manages instances, does unicast/multicast routing, and dynamic instantiation for a single monitor
- Global wrapper
Routes events within a single synchronous set to the proper local wrappers or PEDL
- Transport adapters
A “sibling” of the global wrapper in the hierarchy—sends and receives asynchronous events over the selected transport mechanism (RabbitMQ, ROS, etc.)
- Manager
Initiates event handling at the global wrapper and transport adapters and passes asynchronous events between them
Most programs will only need to interact with part of the global wrapper and manager, so those are the only APIs described on this page. (The full API is described at Full API.)
Overview¶
The target program interacts with SMEDL through PEDL events. First, it makes a function call to emit an event. At that point, the event is queued, but the call immediately returns. Then, it makes another call to pass control to the manager. The manager allows all pending synchronous events to be processed and asynchronous events to be sent. This call returns when there are no more events immediately left to process (though there may still be asynchronous events outstanding). Finally, the target program must provide functions of its own for receiving PEDL events back from the monitors.
By default, SMEDL generates a PEDL stub that reads events from a CSV and does all of the above. This allows the monitors to be buildable immediately and can serve as demo code, but most real-world programs will want to replace most or all of this file with actual instrumentation.
For asynchronous PEDL events (that is, those not explicitly placed in a
synchronous set), SMEDL generates a pedl
synchronous set that does nothing
except send and receive PEDL events asynchronously. This allows for the same
API to be used, regardless of synchronization. But, if convenient, the pedl
synchronous set can be dropped, and the target program or its instrumentation
can send and receive events over the asynchronous message channels directly.
For more information on that, go back to SMEDL Programming Interface and visit the page for
the appropriate asynchronous transport.
SMEDL Types¶
Most types in SMEDL correspond directly to a well-known type in C (see
Types). The exception is the opaque
type, represented in C by
SMEDLOpaque
from smedl_types.h
:
-
struct SMEDLOpaque¶
C type representing SMEDL’s
opaque
type-
void *data¶
Pointer to the opaque’s contents
-
size_t size¶
Length of the opaque in bytes
-
void *data¶
For situations where C code needs to store or pass SMEDL values of arbitrary
type, there is SMEDLValue
, also in smedl_types.h
:
-
struct SMEDLValue¶
Represents a SMEDL value of arbitrary type
Event Passing Conventions¶
Many functions in the SMEDL API are used to pass events from one place to another. For consistency, all of these functions use the same signature:
-
int event_passing_function(SMEDLValue *identities, SMEDLValue *params, void *aux)¶
The signature used by every event-passing function in SMEDL.
- Parameters
identities – An array of monitor identities, either the source monitor (for an exported event) or the destination monitor (for an imported event). If the monitor has no identities or or it is a PEDL event, this parameter is ignored and can be safely set to NULL.
params – An array of the event parameters.
aux – Auxiliary data pointer. When one event causes another to be raised, this pointer is passed through untouched. This can be used for provenance information or any other purpose. Some asynchronous transports expect this to point to a particular type of data. NULL is always allowed.
- Returns
Nonzero for success, zero for error
Note that there is no need to specify the length for the identities
or
params
parameters since they are known from the architecture
specification.
The convention that SMEDL follows is that the caller retains responsibility for any allocated memory passed as a parameter. Thus, any event handling function that receives parameter arrays must make a copy if they need to be retained after returning, and the same goes for the contents of any string or opaque values.
Initialization and Cleanup¶
Before emitting any PEDL events or running the manager, SMEDL must be
initialized. If SMEDL is no longer needed, it can also be deinitialized to free
resources. Both of these functions are in the manager,
SYNCSET_manager.h
.
-
int init_manager(void)¶
Initialize SMEDL. Must be called before any other function in the SMEDL API.
- Returns
Nonzero for success, zero for error
-
void free_manager(void)¶
Destroy all monitors and wrappers, close all connections, and free the resources used by SMEDL. May be called if SMEDL monitoring is no longer required.
Emitting PEDL Events¶
PEDL events are sent to PEDL by calling the following function in the global
wrapper, SYNCSET_global_wrapper.h
:
-
int raise_pedl_EVENT(SMEDLValue *identities, SMEDLValue *params, void *aux)¶
Raise a PEDL event. This function queues the event for later processing and immediately returns.
- Parameters
identities – This parameter is provided for consistency with other event passing functions. It is ignored and may safely be set to NULL.
params – Array of event parameters
aux – Auxiliary data pointer. This pointer is passed through to any events triggered by this one. This can be used for provenance information or any other purpose.
- Returns
Nonzero for success, zero for error
To actually process the event, the program must call run_manager()
.
Receiving PEDL Events¶
Whenever run_manager()
is called, it is possible that there might be some
PEDL events for the target program to receive back. For each PEDL event that
can be received, the target program must provide the following function:
-
int perform_pedl_EVENT(SMEDLValue *identities, SMEDLValue *params, void *aux)¶
Receive a PEDL event. Called by SMEDL whenever a PEDL event needs to be returned to the target program.
- Parameters
identities – This parameter is provided for consistency with other event passing functions. It will be set to NULL.
params – Array of event parameters
aux – Auxiliary data pointer. This pointer is passed through directly from whatever event triggered this one.
- Returns
Nonzero for success, zero for error
As noted in Event Passing Conventions, the parameter array and the contents of any strings and opaques may become invalid at any point after the function returns. If they are needed longer than that, be sure to keep a copy.
Running SMEDL¶
SMEDL does not process PEDL and asynchronous events as soon as they are queued.
It only happens when initiated by calling the following function in the
manager, SYNCSET_manager.h
:
-
int run_manager(void)¶
Allow SMEDL to run. When called, the following happens:
SMEDL processes any pending PEDL events.
SMEDL processes any events raised as a result. Synchronous events are passed to the appropriate destination within the synchronous set. Asynchronous events are passed to the transport adapter to be sent out. This continues until there are no more events pending in the global wrapper.
The transport adapter is given a chance to receive any incoming asynchronous events that are ready. These are passed along to the global wrapper for processing, and any events raised as a result are handled as in #2.
Then, the function returns.
- Returns
Nonzero for success, zero for error