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... | |
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.
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.
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:
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:
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.
Events are issued like this:
Or for purely informational signals with no associated message:
Events can be issued even if there are no registered handlers.
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 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.
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.
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.
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:
The HHR skin registers a handler for this Event in
When it receives the notification event, it extracts the details of the error:
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.
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:
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:
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.
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.
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.
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.
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.
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.
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.
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 sw_event_result( * event_handler) (void *context, sw_event *event) |
The Event Handler prototype.
[in] | context | The 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] | event | The 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. |
SW_EVENT_CONTINUE | to 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_HANDLED | to 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_UNHANDLED | to 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.
typedef struct sw_event_context 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().
typedef sw_rdr_id sw_event_id |
Event IDs.
IDs are unique per Class and Type, and are either predefined elsewhere or allocated on demand by SwRegisterRDRandID().
typedef HqnResult 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().
anonymous enum |
Event types.
Event numbering follows the numbering conventions for DEVICETYPE numbers.
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 |
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 |
enum 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. |
|
inlinestatic |
Translate an Event-specific error code to a generic HqnResult error code.
[in] | result | One of the EVENT_RESULT values, 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.
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.
[in] | type | The Event type. |
[in] | handler | The sw_event_handler structure previously registered. |
SW_RDR_SUCCESS | if successfully deregistered; |
SW_RDR_ERROR_IN_USE | if the Handler was theaded; |
SW_RDR_ERROR_UNKNOWN | if 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.
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.
[in] | handlers | An array of sw_event_handlers as previously passed to SwRegisterHandlers(). |
[in] | count | The number of entries in this array. |
SW_RDR_SUCCESS | if all successfully deregistered; |
SW_RDR_ERROR_UNKNOWN | if 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.
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.
[in] | type | The event type. |
[in] | message | The 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] | length | The 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. |
>= 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! 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.
[in] | event | The 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. |
>= 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. 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.
[in] | type | The Event type. |
[in] | handler | A 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] | priority | A priority, as for RDR registrations. |
SW_RDR_SUCCESS | if successfully registered. |
SW_RDR_ERROR | in the unlikely event of too many Handlers being registered. |
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.
[in] | handlers | An 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] | count | The number of entries in the handlers array. |
SW_RDR_SUCCESS | if successfully registered. |
SW_RDR_ERROR | in 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.
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.
[in] | type | The Event type. |
[in] | handler | The sw_event_handler structure previously registered. |
SW_RDR_SUCCESS | if successfully deregistered; |
SW_RDR_ERROR_UNKNOWN | if 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.