Harlequin RIP SDK

The event system is used to communicate, filter, and observe events of global interest in a thread-safe manner. More...

Files

file  eventapi.h
 Header file defining the Events system, built on RIP Data Resource (RDR) System.
 
file  eventerrors.h
 Header file defining the Events system result translation.
 

Data Structures

struct  sw_event
 Event structure. More...
 
struct  sw_event_handler
 Event Handler structure. More...
 
struct  sw_event_handlers
 Atomic multiple Handler registration. More...
 
struct  sw_event_api_20110330
 Structure for the Event API version 20110330. More...
 

Macros

#define SW_EVENT_HANDLER_INIT   { NULL, NULL, 0 }
 Static/auto initialiser for sw_event_handler.
 
#define SW_EVENT_HANDLERS_INIT   { NULL, NULL, 0, EVENT_EVENT, SW_EVENT_NORMAL }
 Static/auto initialiser for sw_event_handlers.
 

Typedefs

typedef sw_rdr_type sw_event_type
 A type used to store and communicate Event types.
 
typedef sw_rdr_priority sw_event_priority
 A type used to store and communicate event handler priorities.
 
typedef sw_rdr_id sw_event_id
 Event IDs. More...
 
typedef HqnResult sw_event_result
 A type used for return values from Event handlers. More...
 
typedef struct sw_event_context sw_event_context
 Opaque event context for internal use only. More...
 
typedef sw_event_result(* event_handler) (void *context, sw_event *event)
 The Event Handler prototype. More...
 

Enumerations

enum  {
  EVENT_EVENT = 0 , EVENT_RDR = 100 , EVENT_RESERVE1 = 200 , EVENT_TIMELINE = 300 ,
  EVENT_SKIN = 0x4000 , EVENT_PLUGAPI =0x6000 , EVENT_CORE = 0x8000
}
 Event types. More...
 
enum  { SW_EVENT_DEFAULT = -10000 , SW_EVENT_NORMAL = 0 , SW_EVENT_OVERRIDE = 10000 }
 Event Handler Priorities. More...
 
enum  EVENT_RESULT {
  SW_EVENT_CONTINUE = -2 , SW_EVENT_FORCE_UNHANDLED = -1 , SW_EVENT_HANDLED = HQN_RESULT_SUCCESS , SW_EVENT_ERROR = 1 ,
  SW_EVENT_UNHANDLED = SW_EVENT_CONTINUE
}
 Result values from Event Handlers. More...
 

Functions

sw_rdr_result SwRegisterHandler (sw_event_type type, sw_event_handler *handler, sw_event_priority priority)
 Register an Event Handler. More...
 
sw_rdr_result SwRegisterHandlers (sw_event_handlers *handlers, int count)
 Register multiple Event Handlers atomically. More...
 
sw_rdr_result SwDeregisterHandler (sw_event_type type, sw_event_handler *handler)
 Deregister an Event Handler registered with SwRegisterHandler(). More...
 
sw_rdr_result SwDeregisterHandlers (sw_event_handlers *handlers, int count)
 Deregister multiple Event Handlers. More...
 
sw_rdr_result SwSafeDeregisterHandler (sw_event_type type, sw_event_handler *handler)
 Deregister an Event Handler detecting Handler threading. More...
 
sw_event_result SwEvent (sw_event_type type, void *message, size_t length)
 Generate an event, calling relevant handlers in priority order. More...
 
sw_event_result SwEventTail (sw_event *event)
 Call the remaining Handlers for the current Event, returning the value that would have been returned to the Issuer. More...
 
static HqnResult event_result_translate (sw_event_result result)
 Translate an Event-specific error code to a generic HqnResult error code. More...
 

Detailed Description

The event system is used to communicate, filter, and observe events of global interest in a thread-safe manner.

The event system is a generalized callback system that enables events and associated message structures to be issued by an originator and received by multiple handlers, regardless of the location of originator and handlers. The event system can be used to connect parts of the application together in a flexible and sophisticated manner.

The event system is built on top of the RDR system and uses a number of RDR return values. It is a general-purpose API and may be of use to OEM code in addition to the described RIP uses.

What is an Event?

An event is a identified callback associated with an optional message that is delivered to multiple handlers in a priority order registered for that type of Event.

Event handlers

An event handler is a callback function with the type event_handler. Event handlers may be registered for one or more event types, and can respond to the event by:

The expected behavior of handlers, and how the RIP responds to errors reported by event handlers, is defined by the protocol for the specific event type.

When called, an event handler is called with a context pointer and an event pointer. The context pointer is provided when the event handler is registered, and it can be used to pass the handler information relevant to this particular receiver of an event. The event pointer is provided by the event system, and includes the event type, an address and size defining the message associated with the event, and an event ID. The same event handler function may be registered for multiple event types, and using multiple contexts, and at multiple priorities at the same time. The event handler function can use the event type, message type, and context information to determine what action it is going to perform. Registering an event handler for multiple event types is common, especially for use in the timeline API, where the difference between a normal and an abnormal termination of a timeline is communicated using a different event type. Registering an event handler in multiple contexts is also common, e.g., event handlers may be used to contextualize low-memory handlers to recover memory from multiple caches or objects.

An event handler can be defined and registered thus:

sw_event_result HQNCALL my_callback(void *context, sw_event *event) {
// ...process event...
return SW_EVENT_CONTINUE ; // Pass to other event handlers
}
// ...
sw_event_handler handler = {my_callback, &my_context} ;
if ( SwRegisterHandler(MY_EVENT_TYPE, handler, SW_EVENT_NORMAL) != SW_RDR_SUCCESS ) {
// ...cleanup and return...
}
sw_rdr_result SwRegisterHandler(sw_event_type type, sw_event_handler *handler, sw_event_priority priority)
Register an Event Handler.
HqnResult sw_event_result
A type used for return values from Event handlers.
Definition: eventapi.h:625
@ SW_EVENT_NORMAL
Definition: eventapi.h:564
@ SW_EVENT_CONTINUE
Definition: eventapi.h:600
@ SW_RDR_SUCCESS
Definition: rdrapi.h:617
Event Handler structure.
Definition: eventapi.h:742
Event structure.
Definition: eventapi.h:650

Multiple event handlers can be registered in one call by using SwRegisterHandlers(). This ensures that all events are de-registered if there is a failure in registering any event:

// defined elsewhere:
sw_event_result HQNCALL tl_start(void *context, sw_event *event) ;
sw_event_result HQNCALL tl_ended(void *context, sw_event *event) ;
//...
sw_event_handlers handlers[] = {
{ tl_start, &my_context, 0, EVENT_TIMELINE_START, SW_EVENT_NORMAL },
{ tl_ended, &my_context, 0, EVENT_TIMELINE_ENDED, SW_EVENT_NORMAL },
{ tl_ended, &my_context, 0, EVENT_TIMELINE_ABORTED, SW_EVENT_NORMAL },
} ;
if ( SwRegisterHandlers(handlers, NUM_ARRAY_ITEMS(handlers)) != SW_RDR_SUCCESS ) {
// ...cleanup and return...
}
sw_rdr_result SwRegisterHandlers(sw_event_handlers *handlers, int count)
Register multiple Event Handlers atomically.
#define NUM_ARRAY_ITEMS(_array_)
Definition: std.h:144
@ EVENT_TIMELINE_ENDED
The Timeline has ended.
Definition: timelineapi.h:637
@ EVENT_TIMELINE_START
The Timeline has started.
Definition: timelineapi.h:581
@ EVENT_TIMELINE_ABORTED
The Timeline has aborted.
Definition: timelineapi.h:670
Atomic multiple Handler registration.
Definition: eventapi.h:759

Handlers can be registered even if there is nothing that issues the types of Events registered.

Handlers can be de-registered individually using SwDeregisterHandler() or SwSafeDeregisterHandler(), and de-registered in groups using SwDeregisterHandlers(). However, there are multi-threading concerns when de-registering handlers that may be in use: see Multi-threading issues with events for more detail.

Issuing an event

Events are issued like this:

struct my_event_message message = {
//...message content...
} ;
sw_rdr_result result = SwEvent(MY_EVENT_TYPE, &message, sizeof(message)) ;
sw_event_result SwEvent(sw_event_type type, void *message, size_t length)
Generate an event, calling relevant handlers in priority order.
HqnResult sw_rdr_result
A type used to communicate return values from RDR API calls.
Definition: rdrapi.h:635

Or for purely informational signals with no associated message:

sw_rdr_result result = SwEvent(MY_EVENT_TYPE, 0, 0) ;

Events can be issued even if there are no registered handlers.

Event handler priorities

Multiple handlers can be registered for an Event which will be called in priority order. When there are multiple handlers for a particular Event, the order that those handlers are called may be significant. If this were dictated purely by the chronology of handler registrations, constraints would be made on when and how various systems could register their handlers.

Instead, handlers are registered with a priority. The highest priority handler is called first. If it returns SW_EVENT_CONTINUE, the next highest priority handler will be called, and so on until all handlers for that Event have been called.

Higher priority handlers can prevent lower priority handlers receiving the Event by returning something other than SW_EVENT_CONTINUE (for example, SW_EVENT_HANDLED). This means that a higher priority handler can act as a filter, and can also monitor or change an Event. Handlers can also call the remaining lower priority handlers for an Event multiple times via the SwEventTail() call.

Registering the same handler for the same Event more than once does not actually cause it to be called more than once. Re-registrations are seen as re-prioritization, as they allow the priority of the handler to be changed without first de-registering it. It is permissible for a handler to change its own priority in this way. Note, however, that for the purposes of this definition a "Handler" is a combination of callback function and its private context pointer. It is possible to simultaneously register multiple handler structures that use the same callback function, but with different context pointers.

Event numbers

Event numbers are split into ranges, defined in eventapi.h and sub-divided in core and skin headers elsewhere. Event numbering follows the numbering conventions for DEVICETYPE numbers.

Multi-threading issues with events

The event system can be used to connect anything to anything, across the Skin/Core boundary and from thread to thread. For example, the core RIP interpretation thread uses events to communicate job start, job end, interpretation stage and so on, to the skin, which is running its own thread. Event handlers are called in the thread of the event issuer, not necessarily the thread that registered the handlers. If the skin registers a handler for a core event, that handler will be called in a core thread. Handlers that modify some context that is not part of the event message must therefore be thread safe.

Because handlers often are called by some other thread, it is possible for one thread to try to de-register a handler whilst that handler is actually running in some other thread. Note that it is permissible for a handler to de-register itself, which may be the most natural response to a particular scenario.

However, if a thread wishes to de-register a handler and discard the context that the handler modifies, care must be taken to ensure the handler is not still running (despite having been de-registered) when that context is destroyed. As the event system is built on the RDR system it makes use of RDR locking to achieve this.

If a handler is still running when SwDeregisterHandler() is called, SW_RDR_ERROR_IN_USE is returned. Waiting for the handler to exit so that context can be safely discarded is such a common idiom there is an additional call that may be more convenient in such cases, SwSafeDeregisterHandler(), which will not return while the handler is running. A handler must not use this call in an attempt to de-register itself.

Where code must register or de-register multiple handlers two convenience functions may prove useful: SwRegisterHandlers() and SwDeregisterHandlers(). Both take a list of handlers to register or de-register in one go. Note that in this case the de-registration is "Safe", so also must not be done from any of the handlers being de-registered.

Event usage patterns

There are a number of ways of using the event system:

These various idioms are described in detail in later sections, but in brief: the issuer of a notification event does not care about the return code the handlers return; an issuer of a permission event will or will not carry out some action depending on the return code; an issuer of an implementation event is relying on a handler (typically low priority and referred to as the "default handler") to perform some action, though the return code may have some significance.

In the implementation case, handlers may be registered to replace or modify the expected functionality, or indeed to take advantage of that functionality. For example, an event could be used to send an error message to the skin, which would be expected under such a protocol to have registered a default handler for that event which would log or display the error. This allows a third-party system to register a handler for that Event and augment the error message with additional information by altering or replacing the message. Alternatively, it could use SwEventTail() to send multiple messages to the remaining handlers including, one expects, the default handler.

These types of Events are merely different idioms. They are all implemented by the issuer calling SwEvent() with an optional message and responding to the resulting return code. The exact protocol is defined as part of the definition of a particular event type.

It is possible to combine these various behaviors into a single event. For example, a single event with a default handler of normal priority that returns SW_EVENT_CONTINUE can be seen as both permission for high priority handlers (as they could stop the default handler from being called) and notification for low priority handlers (as they are only called if the default handler carries out its action).

While using the event systems provides a great deal of flexibility for developers, it also requires equivalent responsibility to both document the expected protocols, and for clients to follow those protocols. Arbitrarily suppressing events may cause incorrect functioning of software that relies on them.

Notification events

The simplest use for events is as a notification signal, allowing other systems to react to your system's actions without any direct linkage between them. For example, the RIP notifies interested parties of a job interpretation error with one line:

SwEvent(SWEVT_INTERPRET_ERROR, &error, sizeof(error)) ;
@ SWEVT_INTERPRET_ERROR
Definition: swevents.h:92

The HHR skin registers a handler for this Event in

static sw_event_handlers error_handlers[] = {
{job_error_handler, NULL, 0, SWEVT_INTERPRET_ERROR, SW_EVENT_DEFAULT},
// ...
} ;
// ...
if ( SwRegisterHandlers(error_handlers, NUM_ARRAY_ITEMS(error_handlers)) != SW_RDR_SUCCESS ) {
// ...cleanup and return...
}
@ SW_EVENT_DEFAULT
Definition: eventapi.h:563
#define NULL
Definition of NULL pointer.
Definition: hqtypes.h:37

When it receives the notification event, it extracts the details of the error:

static sw_event_result HQNCALL job_error_handler(void *context,
sw_event *event)
{
SWMSG_ERROR *msg = event->message;
if (msg == NULL || event->length < sizeof(*msg))
if (msg->fail_job && !controlData.fConfigJobFailed) {
// Capture error detail here if desired
controlData.fConfigJobFailed = TRUE;
controlData.jobError.monuid = msg->error_monuid ;
// ...
}
}
#define TRUE
HqBool boolean true value.
Definition: hqtypes.h:508
Definition: swevents.h:354
HqBool fail_job
Definition: swevents.h:366
sw_mon_type error_monuid
Definition: swevents.h:377

Note that SW_EVENT_CONTINUE should usually be used by handlers of notification events. If the handler were to return SW_EVENT_HANDLED, no further handlers would be notified of the event. This is likely to be a protocol error for a notification type event as all handlers would need to know about it.

The idiom of returning SW_EVENT_CONTINUE if the message is missing or if the length is not sufficient is recommended. This protects the application against crashes if used with an older core library than expected, or if a higher priority event handler modifies the event details before forwarding it.

Permission events

More use can be made of the handler's return code by using it to indicate to the event issuer whether something should occur. An example of this can be found in the clrip application's progress event filter. A high priority handler is installed for the SWEVT_MONITOR event:

static sw_event_handler progress_handler = {
progressFilter, &suppressedProgressTypes,
};
if ( SwRegisterHandler(SWEVT_MONITOR, &progress_handler, MON_FILTER) != SW_RDR_SUCCESS ) {
// ...cleanup and return...
}
@ MON_FILTER
Definition: monevent.h:102
static sw_event_result progressFilter(void *ctx, sw_event *evt)
Definition: progevts.c:28
@ SWEVT_MONITOR
Definition: swevents.h:206

The handler checks the type of each event to determine if it should be suppressed. Suppression is implemented by the progressFilter() callback returning SW_EVENT_HANDLED, which prevents any lower priority handler receiving the event:

if (suppressedTypes & messageType) return SW_EVENT_HANDLED;
@ SW_EVENT_HANDLED
Definition: eventapi.h:604

Other handlers for the SWEVT_MONITOR event will only be called for the unsuppressed types (that is, those for which progressFilter() returns SW_EVENT_CONTINUE).

Much like the RDR system it is based on, the event system does not dictate how a protocol is implemented, so care must be taken to consider the best representation in the face of multiple handlers, expected priorities, and error conditions.

Implementation events

In the previous example the event is used as permission before undertaking some action. Another model is to place that action as a default handler for the event. The difference is far from cosmetic.

Consider a theoretical error event, issued by a component: it would be possible for a handler to do its own error handling (that is the intention after all) in fact it may choose to duplicate the existing error mechanism with some subtle difference or addition. Returning SW_EVENT_HANDLED would only tell the error handler not to do what it was going to do it would not indicate if a suitable alternative had been done. In other words, this event idiom already allows an action to be re-implemented, probably by some other system, possibly in the skin, perhaps contextually. However, it is not implicitly clear to the handler how much has already been done before the event was issued, and how much can be disabled by handling it. Such details must be defined as part of the protocol.

The alternative is to place all such actions in a default handler, usually with a very low priority. This has two consequences: first it forces the author to define the effects of that event very clearly; secondly it automatically provides an API for achieving that effect.

The inputs API uses an implementation event to change the queue state. A default handler is registered at SW_EVENT_NORMAL priority, and is passed a message which contains a requested state change: either stop, start, or query the queue state. The default handler will apply a stop or start request, and then update the message to reflect the current state of the queue. The event issuer can then see the applied state after the change. (The input enable event is actually a mixture of patterns: it acts as a notification event for any handler registered below SW_EVENT_NORMAL priority, as a permission or implementation event for handlers above SW_EVENT_NORMAL.) Any code can issue an event to request stopping, starting, or querying the queue state.

Advanced use of events

It is possible for a higher priority handler to modify an event before the remaining handlers get it. Handlers can use the SwEventTail() mechanism to call the remaining handlers, potentially multiple times: modify the results of what the remaining handlers did and then, potentially, return a different value than would normally have been returned. In addition, SW_EVENT_FORCE_UNHANDLED can be used to make it appear that none of the handlers handled the Event, even if one of the remaining handlers had returned SW_EVENT_HANDLED.

An example of this could be a simple event used to report error messages to the RIP skin or device. Consider that an error is reported using an event. A default handler might pick up the error and display a message on the user interface. It is possible that another handler could be used to modify the error message by either suppressing it or, by having the SwEventTail() mechanism call the default handler multiple times to pass on the original message and add an extra line of text. In fact, it could call it multiple times to add further lines of text to display on the user interface before returning SW_EVENT_FORCE_UNHANDLED or SW_EVENT_HANDLED to exit the loop and return to the event issuer. This is done in response to the system generating a single line of text.

The clrip application's monitor event handlers use SwEventTail() to modify colorization state for messages, call the remaining monitor message handlers, and then restore the previous colorization state.

Note that only SW_EVENT_CONTINUE causes the Event to be submitted to the next handler. Any other return value is returned to the caller, which may be the original event issuer, or may be a previous handler that has called SwEventTail(). Using SwEventTail() does not compel you to use any particular return code. The difficulty in using worked examples is distinguishing between syntax mandated by the event system itself, and syntax required by the protocol implemented using the event system. This is why we need to be clear about return codes. SW_EVENT_CONTINUE continues to the next handler (if there is one), or returns SW_EVENT_UNHANDLED to the issuer. Any other return code gets returned to the issuer immediately. It is for this reason that SW_EVENT_CONTINUE and SW_EVENT_UNHANDLED are in fact synonyms, but you should use whichever is most consistent with the idiom in use.

Events defined in the Harlequin RIP and SDK

Many important RIP state changes are communicated by Timeline events, but there are a number of other events issued by the core too, and also events issued by the RIP skin to cause the RIP to act or react.

RIP and SDK events

The Harlequin Core RIP and SDK generates and consumes a number of events. The details of these events and their associated messages can be found in the SDK header files swevents.h. Events and messages associated with halftone screening are defined in the header file htevents.h. Events and associated messages for the eHVD interface are defined in the header file rrevents.h. Events and messages for monitor output are defined in the header file monevent.h. Events and messages associated with timelines are defined in the header file timelineapi.h. The inputs API defines some events and messages in the header file inputsapi.h

Each API description should contain definitions of the events and their associated messages and semantics.

Monitor events

Text sent to the RIP's console or monitor window is delivered through a Monitor Event. Together with Timeline events intercepting monitor events can enhance error reporting, and provide enhanced timing and progress information to OEM code.

Interrupt events

The application or skin code can be used to cancel jobs by issuing interrupt events. You may use Timeline events to capture core job timeline references, and then use these to interrupt a specific job.

Notes on RDR and events

The Event system is tied closely to RDR. The RDR and Event systems can be described using pull and push metaphors; or as passive and active systems.

RDR is a pull mechanism: something requiring an entity can find it (or them) at a certain moment, but the RDR system provides no direct mechanism for managing the lifetime of an individual RDR. It is conceivable that an RDR might be de-registered between something successfully finding it and actually accessing the contents. This must be considered when designing a protocol using RDRs.

The worked examples of publishing RDRs implicitly require that the lifetime of an RDR found by a module will exceed that of the module itself. The RDR system is passive, so there is no automatic usage counting. Entities that can disappear or change asynchronously, or that require lifetime management or long-term locking, should use the Event system or Timelines.

The Event system is a push mechanism: something that knows, has, or is about to remove something, can communicate immediately with interested parties with the possibility of those handlers refusing or modifying the intended behavior.

The RDR system is passive, but the Event system active. Events can also be used to find things, much like the RDR system. The distinction is that handlers are actually called by the Event system. Providers of RDRs are never informed when those RDRs are found, delivered or used.

An event API pointer must be discovered using RDR using class RDR_CLASS_API and type RDR_API_EVENT and assigned to a suitably-named API pointer variable before the API macros are used. The Event system is automatically started when the Harlequin RIP SDK is started. It remains active until the Harlequin RIP SDK is shutdown.

Typedef Documentation

◆ event_handler

typedef sw_event_result( * event_handler) (void *context, sw_event *event)

The Event Handler prototype.

Parameters
[in]contextThe Handler's context pointer as specified in the registered sw_event_handler. This can be whatever the Handler requires. Note that this is a void* and must be cast to whatever type the Handler expects.
[in]eventThe Event details in sw_event format. Note that the Issuer-supplied event->message is a void* and must be cast to whatever type the Event in question is defined to comprise.
Return values
SW_EVENT_CONTINUEto pass on to other Handlers. This does not necessarily mean that this Handler has done nothing. Whether to 'normally' return SW_EVENT_CONTINUE or SW_EVENT_HANDLED is defined on a per-Event basis.
SW_EVENT_HANDLEDto return immediately to the Issuer. No further Handlers are called.
SW_EVENT_ERROR(or higher) to return immediately to the Issuer. No further Handlers are called. Error codes may be defined on a per-Event basis.
SW_EVENT_FORCE_UNHANDLEDto return immediately to the Issuer. No further Handlers are called, but the value returned to the Issuer is SW_EVENT_CONTINUE (also known as SW_EVENT_UNHANDLED).

If all Handlers return SW_EVENT_CONTINUE, this is the value returned to the Issuer. For code clarity SW_EVENT_UNHANDLED is an alias for this value, which can make Issuer code clearer. Also see SW_EVENT_FORCE_UNHANDLED.

◆ sw_event_context

Opaque event context for internal use only.

This is only seen inside the sw_event structure passed to Handlers, and may not be usefully inspected or modified. However, it is necessary for the correct functioning of SwEventTail().

◆ sw_event_id

Event IDs.

IDs are unique per Class and Type, and are either predefined elsewhere or allocated on demand by SwRegisterRDRandID().

◆ sw_event_result

A type used for return values from Event handlers.

This is a subclass of HqnResult that also supports some specific extra error codes generated by events (declared as the EVENT_RESULT enumeration). Before assigning to values of HqnResult type or any of its other subclasses, sw_event_result values must be converted to change the event specific values to HQN_RESULT_SUCCESS or a monitor UID error code greater than MON_CLASS_ERROR. This can be done by including the file eventerrors.h and calling the function event_result_translate().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Event types.

Event numbering follows the numbering conventions for DEVICETYPE numbers.

  • The range 0x00000000-0x0000ffff is reserved for Global Graphics.
  • The range 0xXXXX0000-0xXXXXffff is reserved for customer number XXXX.
  • The range 0xffff0000-0xffffffff is for private use in closed environments.

These ranges are sub-allocated here and elsewhere, eg swevents.h.

Enumerator
EVENT_EVENT 

100 Event system events

EVENT_RDR 

100 RDR system events

EVENT_RESERVE1 

Reserved

EVENT_TIMELINE 

100 Timeline system events

EVENT_SKIN 

8192 Skin events, defined by the skin.

EVENT_PLUGAPI 

8192 Plugin API events, defined in pic/pim/piu/pip.

EVENT_CORE 

32768 Core events, defined by swevents.h

◆ anonymous enum

anonymous enum

Event Handler Priorities.

The highest priority (or most recently registered) Handler for an Event is called first. If it returns SW_EVENT_CONTINUE the next highest will be called, and so on.

These are typical values, but other than the high to low ordering, Handlers can choose whatever priority is appropriate. Handlers can be reprioritised dynamically, even while being executed.

Enumerator
SW_EVENT_DEFAULT 

Known to be a default

SW_EVENT_NORMAL 

The usual case

SW_EVENT_OVERRIDE 

High priority registration

◆ EVENT_RESULT

Result values from Event Handlers.

Handlers for an Event are called in decreasing Priority order until one does NOT return SW_EVENT_CONTINUE. The last return code is returned to the Event Issuer. SW_EVENT_UNHANDLED is an alias for SW_EVENT_CONTINUE which may be clearer in some protocols.

Other than the special behaviour of SW_EVENT_FORCE_UNHANDLED and SW_EVENT_CONTINUE, all other values are returned to the Issuer, so their meaning is defined on a per-Event basis. It may be that some Event uses return values >= SW_EVENT_ERROR to indicate various successful outcomes.

These are chosen such that SW_EVENT_HANDLED == SW_RDR_SUCCESS and SW_EVENT_ERROR == SW_RDR_ERROR for simplicity of implementation.

Enumerator
SW_EVENT_CONTINUE 

Pass Event on to next Handler.

SW_EVENT_FORCE_UNHANDLED 

Immediately return SW_EVENT_UNHANDLED to Issuer.

SW_EVENT_HANDLED 

Return immediately to Issuer.

SW_EVENT_ERROR 

Error, don't pass to any more Handlers. Specific errors are enumerated from here for individual Events, all >= SW_EVENT_ERROR. Or use error codes >= MON_CLASS_ERROR for identifiable error locations.

SW_EVENT_UNHANDLED 

An alias for SW_EVENT_CONTINUE, for Issuer code clarity.

Function Documentation

◆ event_result_translate()

static HqnResult event_result_translate ( sw_event_result  result)
inlinestatic

Translate an Event-specific error code to a generic HqnResult error code.

Parameters
[in]resultOne of the EVENT_RESULT values, or an error value greater than MON_CLASS_ERROR.
Returns
Either HQN_RESULT_SUCCESS, or an error value greater than MON_CLASS_ERROR.

The header file defining this function should be included explicitly in every C or C++ file that calls it.

◆ SwDeregisterHandler()

sw_rdr_result SwDeregisterHandler ( sw_event_type  type,
sw_event_handler handler 
)

Deregister an Event Handler registered with SwRegisterHandler().

Deregisters a previously registered Handler. This can be called by the Handler itself.

Although this guarantees that the Handler will not be called again, it does NOT guarantee that the Handler is not currently threaded.

Parameters
[in]typeThe Event type.
[in]handlerThe sw_event_handler structure previously registered.
Return values
SW_RDR_SUCCESSif successfully deregistered;
SW_RDR_ERROR_IN_USEif the Handler was theaded;
SW_RDR_ERROR_UNKNOWNif the Handler was not registered.

Note that even if SW_RDR_ERROR_IN_USE is returned, the Handler HAS been successfully deregistered, though it may still be threaded. If so, this call can be repeated until it no longer returns SW_RDR_ERROR_IN_USE, or SwSafeDeregisterHandler() called instead to wait for the Handler to exit.

◆ SwDeregisterHandlers()

sw_rdr_result SwDeregisterHandlers ( sw_event_handlers handlers,
int  count 
)

Deregister multiple Event Handlers.

This deregisters a number of Handlers in one call, regardless of errors, and guarantees that they are not threaded on exit.

This is more concise than multiple calls to SwSafeDeregisterHandler(), but is entirely equivalent. If any Handler is not registered an error is returned after all other Handlers have been deregistered.

Parameters
[in]handlersAn array of sw_event_handlers as previously passed to SwRegisterHandlers().
[in]countThe number of entries in this array.
Return values
SW_RDR_SUCCESSif all successfully deregistered;
SW_RDR_ERROR_UNKNOWNif any were not registered. Note that ALL Handlers will have been deregistered, this error is purely informational.

Note that this call cannot be used by a Handler to deregister itself. Be careful not to use this call in any code that can be called from a Handler that is to be deregistered.

◆ SwEvent()

sw_event_result SwEvent ( sw_event_type  type,
void *  message,
size_t  length 
)

Generate an event, calling relevant handlers in priority order.

The meaning, parameters and return values pertinent to a particular Event are defined by the Event owner. Some Events may merely be used as a signal to inform interested parties of a change in state. Some may contain data or a reference to a buffer. Others may require specific return codes for successful completion. This is all up to the Event owner.

Parameters
[in]typeThe event type.
[in]messageThe message pointer for this event. Note that much like the RDR system which underpins the Event system, no interpretation of this pointer is mandated - it may be a pointer to some information, or to a buffer to fill in, or some other arbitrary address such as a memory limit. It may often be NULL.
[in]lengthThe length associated with the above message pointer. Once again, no interpretation is placed on the meaning of this value - it may refer to the length of the message or may be an arbitrary number. This is defined by the issuer of the Event in question. It may often be zero.
Returns
If there are no handlers, or none respond, the return value will be SW_EVENT_CONTINUE. SW_EVENT_UNHANDLED is an alias of this value that may make code clearer. If a handler has acted appropriately, it will return SW_EVENT_HANDLED. Note that either of these cases may be seen as a success or failure by the Event Issuer - this is defined on a per-Event basis. If a handler reports an error, the return value will be >= SW_EVENT_ERROR. Error return values in that range can be defined on a per-Event basis, and may not actually indicate a fault for that Event definition!

◆ SwEventTail()

sw_event_result SwEventTail ( sw_event event)

Call the remaining Handlers for the current Event, returning the value that would have been returned to the Issuer.

This call can only be made by a Handler, passing in the sw_event delivered to it. The remaining Handlers - the "tail" - can be called multiple times if the current Handler wishes. How the return values are combined or what value is ultimately returned is up to the current Handler.

Note that calling SwEventTail() does not automatically prevent the remaining Handlers from being called once more if the current Handler returns SW_EVENT_CONTINUE - see SW_EVENT_FORCE_UNHANDLED.

Parameters
[in]eventThe sw_event structure passed to the Handler. It is permissible for the Handler to change the message and length fields of the sw_event, but the opaque context field must be preserved for SwEventTail() to function.
Returns
As SwEvent(), SW_EVENT_CONTINUE (SW_EVENT_UNHANDLED), SW_EVENT_HANDLED, or an error code >= SW_EVENT_ERROR may be returned by the remaining Handlers, if any. The current Handler may choose to return some other value if it wishes.

◆ SwRegisterHandler()

sw_rdr_result SwRegisterHandler ( sw_event_type  type,
sw_event_handler handler,
sw_event_priority  priority 
)

Register an Event Handler.

This registers a Handler with the Event system, or reregisters a previously registered handler with a different priority. This can be done by the Handler itself while being executed, if it wishes.

Note that SwRegisterHandler is just syntactic sugar for an RDR registration.

Parameters
[in]typeThe Event type.
[in]handlerA sw_event_handler structure containing a pointer to the Event Handler function, and optionally its private context. This structure must continue to exist and not be modified externally until the corresponding SwDeregisterHandler() call.
[in]priorityA priority, as for RDR registrations.
Return values
SW_RDR_SUCCESSif successfully registered.
SW_RDR_ERRORin the unlikely event of too many Handlers being registered.

◆ SwRegisterHandlers()

sw_rdr_result SwRegisterHandlers ( sw_event_handlers handlers,
int  count 
)

Register multiple Event Handlers atomically.

This registers a number of Handlers in one call, and does so atomically - if any fail to register, any that have will be deregistered.

This is more concise than multiple calls to SwRegisterHandler(), but is entirely equivalent.

Parameters
[in]handlersAn array of sw_event_handlers containing a pointer to the Event Handler function, its private context, the Event type and the priority. These structures must continue to exist and not be modified externally until the corresponding SwDeregisterHandlers() call.
[in]countThe number of entries in the handlers array.
Return values
SW_RDR_SUCCESSif successfully registered.
SW_RDR_ERRORin the unlikely event of too many Handlers being registered.

Should this call return an error it is guaranteed that no Handlers are registered or threaded. However, it cannot guarantee that none were called.

◆ SwSafeDeregisterHandler()

sw_rdr_result SwSafeDeregisterHandler ( sw_event_type  type,
sw_event_handler handler 
)

Deregister an Event Handler detecting Handler threading.

This deregisters a Handler immediately like SwDeregisterHandler() but also detects whether the Handler is currently threaded. If so it does not return until the Handler exits.

Parameters
[in]typeThe Event type.
[in]handlerThe sw_event_handler structure previously registered.
Return values
SW_RDR_SUCCESSif successfully deregistered;
SW_RDR_ERROR_UNKNOWNif the Handler is not registered.

Note that this call cannot be used by a Handler to deregister itself. Be careful not to use this call in any code that can be called from the Handler that is to be deregistered.