tibrvEventOnComplete
Function Type
Declaration
typedef void (*tibrvEventOnComplete
) (
tibrvEvent destroyedEvent,
void* closure);
Purpose
A program can destroy an event object even when its callback function is running in one or more threads. Multi-threaded programs can define functions of this type to discover when all callback functions in progress have completed.
Parameter |
Description |
|
This parameter receives the event object. This object is identical to the object that the program created to express event interest. However, by the time this function runs, the event is already destroyed; this function cannot use the event object in Rendezvous calls. |
|
This parameter receives the closure data, which the program supplied in the call that created the event object. |
Remarks
This type of function is important in two situations:
• | An event callback function calls tibrvEvent_DestroyEx() to destroy its event, and the program must do additional processing after the rest of the callback function has completed. |
• | Several threads dispatch an event (so the event callback function can be running in several threads) and the program must do additional processing after the callback function has completed in all threads. |
Upon return from tibrvEvent_DestroyEx(), the destroyed event’s callback function can no longer begin to run. However, in each thread where the callback function is already in progress, that callback function does continue to run until complete.
tibrvEvent_DestroyEx() accepts a completion function argument of type tibrvEventOnComplete. Rendezvous software ensures that the completion function runs when the last callback-in-progress has completed.
Timing and Context
This completion function can run in two situations:
• | Completion when Callback Functions are in Progress illustrates a situation in which the program calls tibrvEvent_DestroyEx() while callback functions of the destroyed event are in progress. When the last of those callback functions completes, Rendezvous software runs the completion function immediately, in the same thread as the callback function that completes last. |
• | Completion when Callback Functions are Not in Progress illustrates a situation in which the program calls tibrvEvent_DestroyEx() when the destroyed event’s callback function is not running in any thread. In this case, tibrvEvent_DestroyEx() calls the completion function before returning. |
Notice that in this situation, the completion function runs in the program context, instead of the usual context of a callback function. In rare instances, deadlock can occur, resulting from unintended interactions between mutex operations in the program context before the destroy call, and mutex operations in the program’s completion function code.
To protect against this type of deadlock, programmers can use a straightforward thought-experiment as a preventive test. Expand the completion function code immediately after the call to tibrvEvent_DestroyEx()—as it would run when the destroyed event’s callback function is not running in any thread. Trace mutex locking activity within this context to determine whether the resulting code could violate established rules for proper use of mutex locks.
...
mutex lock operations
...
tibrvEvent_DestroyEx()
expand completion function code here, and check for violations of mutex rules
...
Potential violations and conflicts usually become apparent during this exercise. Remember, it is the programmer’s responsibility to prevent deadlock.
Figure 175: Completion when Callback Functions are in Progress
Figure 176: Completion when Callback Functions are Not in Progress