In order to ensure substitutability, handling of threads (or other implementations of concurrent flows of control) must be well defined at interfaces between components. This specification defines a single threaded (sequential) and a multi-threaded (concurrent) option. For the single threaded option, it also defines an interface by which the client offers means for components to wait for external events. For the multi-threaded option, components are expected to handle external events internally. Components are required to support one of these options but may support both. The terminology and the concepts are explained in 3.3.4.
The specifications in this subsection apply to active API components, i.e., the API Service Element and the API Proxy, as well as to the interfaces provided by the SLE Application. Relevant specifications for the components ‘SLE Operations’ and ‘SLE Utilities’ are defined in 3.4 and 3.5.
API components shall provide one of the following behaviors for interfaces:
NOTE – Sequential behavior and the associated control interface are defined in 3.7.2.
concurrent behavior in which methods of an interface may be invoked concurrently by different flows of control.
NOTE – Concurrent behavior and the associated control interface are defined in 3.7.3.
A component shall provide the same behavior on all interfaces provided to one client and expect the same behavior for the complementary interfaces provided by the client.
API components shall support a control interface according to the behavior provided on their interfaces. This control interface shall provide methods to start and terminate processing of the component.
3.7.2Sequential Behavior
A component providing sequential interface behavior shall be controlled by the interface ISLE_Sequential exported by the component.
Processing of the component shall be started by the method StartSequential(), which shall pass references to the interfaces ISLE_EventMonitor and ISLE_TimerHandler as arguments.
NOTE – The event monitor and its use by the component are defined in . The timer handler and its use by the component are specified in .
The method StartSequential() shall return as soon as processing of the component has started.
The component shall guarantee that calls to complementary interfaces provided by its client are performed in the thread of control that originates from:
a call of the client to one of the interfaces exported by the component;
a call to the method ProcessEvent() in the interface ISLE_EventProcessor passed to the event monitor; or
a call to the method ProcessTimeout() in the interface ISLE_TimeoutProcessor passed to the timer handler.
NOTE – Use of multiple threads within the component is not excluded. However, the component must ensure that no thread created within the component or in a component other than the client enters client code.
The client shall guarantee that all calls to component interfaces are performed in a single thread of control at a time.
NOTE – Use of multiple threads by the client is not excluded, but the client must ensure that calls to the component interfaces are strictly serialized.
For interfaces with sequential behavior, sequence counting for transfer of SLE protocol data units as defined in is not required. The sequence count argument in the associated methods shall be set to zero.
The event monitor shall provide a service to the component to wait for external events.
An event, which the event monitor should wait for, shall be registered with the method AddEvent() passing an event handle and a reference to the interface ISLE_EventProcessor.
NOTE – When events make use of UNIX file descriptors and event types (see annex A.1.1.1.1.1.1.1) AddEvent() must be called separately for read events, write events, and exceptions on a file descriptor, if the event monitor shall report these events.
An event shall be de-registered with the method RemoveEvent(), which references the event handle that shall be removed from the list of monitored events.
The event monitor shall support waiting for several events in parallel. If the event monitor constrains the number of events that can be registered, it shall return an error code indicating ‘overflow’ when this number is exceeded.
NOTE – It is noted that an event monitor with too restrictive constraints can prevent proper operation of the component.
When the event monitor detects an event, it shall call the method ProcessEvent() on the interface that has been registered for that event.
When the event monitor is no longer able to monitor an event for whatever reason, it shall remove the event and inform the event processor using the method MonitorAbort().
NOTE – If more than one event must be removed, the method shall be invoked for every event.
The timer handler shall provide a service to the component to have timers started and be informed when the timer expires.
A timer shall be started by the method StartTimer() passing the timeout value and a reference to the interface ISLE_TimeoutProcessor. When the timer has been started, the method shall provide a timer identifier for later reference.
The timer handler shall allow specifying the timeout value with a resolution of one second.
The timer handler shall support several running timers in parallel. If the timer handler constrains the number of timers that can be running, it shall return an error code indicating ‘overflow’ when this number is exceeded.
NOTE – It is noted that timer handler with too restrictive constraints can prevent proper operation of the component.
When the timer expires, the timer handler shall call the method ProcessTimeout() of the interface ISLE_TimeoutProcessor, which has been registered with the method StartTimer().
The timer handler shall provide the method CancelTimer() of the interface ISLE_TimerHandler, with which an active timer can be cancelled.
The timer handler shall provide the method RestartTimer() of the interface ISLE_TimerHandler, with which an active timer can be cancelled and restarted with a new timeout value.
As an option, the timer handler shall support an invocation identifier to be associated with the activation of a timer.
The invocation identifier shall be passed as an optional argument to the method StartTimer() or RestartTimer() of the interface ISLE_TimerHandler.
The timer handler shall memorize the identifier and pass it to the call of the method ProcessTimeout() in the interface ISLE_TimeoutProcessor when the timer expires.
NOTE – The invocation identifier supports handling of race conditions in a multi-threaded environment. If a timer is restarted just before it expires, a call to the method ProcessTimeout() in the interface ISLE_TimeoutProcessor can actually result from a previous call to StartTimer(). Such race conditions cannot be avoided, but unwanted calls to ProcessTimeout() can be identified and ignored, as the causality of the call can be determined using the invocation identifier.
When the timer handler is no longer able to process an active timer for whatever reason, it shall cancel the timer and inform the timeout processor using the method HandlerAbort().
NOTE – If more than one timer must be aborted, the method shall be invoked for every timer.
Processing of the component shall be terminated by calling the method TerminateSequential() of the interface ISLE_Sequential. The method shall ensure that all events registered by the component are removed from the event monitor and all running timers have been cancelled.
3.7.3Concurrent Behavior
A component providing concurrent interface behavior shall be controlled by the interface ISLE_Concurrent exported by the component.
Processing of the component shall be started by the method StartConcurrent(), which shall return as soon as processing has started.
The component must expect methods in an interface exported to the client to be called concurrently by separate threads of control.
The client of the component must expect methods in an interface passed to the client to be called concurrently by separate threads of control.
In order to support sequence preservation for SLE protocol data units, methods passing PDUs across an interface with concurrent behavior shall support sequence counting.
NOTES
The sequence count refers to the sequence in which PDUs have been received from the network or have been supplied by the application. It is required in a multi-threaded environment, because the sequence is not preserved when different PDUs are processed by different threads. This specification requires components to support sequence counting also in those cases where the specific implementation would preserve the sequence of PDUs. This would be the case when a component uses a single thread for PDUs transferred in one direction.
It is stressed that sequence counting is local to a given interface. For the service element, sequence-counts on the proxy interface can differ from those on the application interface.
The sequence count is a 32 bit unsigned integer.
The sequence count for a BIND invocation or a BIND return transmitted for one association shall be set to one.
NOTE – This implies that sequence counts shall restart at one when an association has been terminated or aborted and a new BIND invocation is issued.
For subsequent PDUs, the sequence-count shall be incremented by one.
Recycling of the sequence count to zero shall be supported.
The receiving entity shall define a window in which it accepts sequence counts. When receiving a sequence count outside of this window for a PDU, which is not a PEER ABORT invocation, it shall reject the PDU with an error code indicating ‘sequence error’.
NOTE – It is not required but recommended that the window size be configurable.
Components providing the concurrent behavior shall handle external events internally without further support by the client.
Processing of the component shall be terminated by the method TerminateConcurrent() of the interface ISLE_Concurrent. The method shall ensure that all threads started by the component are stopped such that graceful termination of the process becomes possible.