feisty meow concerns codebase  2.140
processes::safe_callback Class Referenceabstract

A reasonably easy way to make callbacks safe from shutdown ordering issues. More...

#include <safe_callback.h>

Inheritance diagram for processes::safe_callback:

Public Member Functions

 safe_callback ()
 construction signifies that the callback is now in operation. More...
 
void end_availability ()
 prepares to shut down this object. More...
 
virtual ~safe_callback ()
 actually destroys the object. More...
 
 DEFINE_CLASS_NAME ("safe_callback")
 
bool decoupled () const
 if true, then end_availability() was already invoked on the object. More...
 
bool invoke_callback (callback_data_block &new_data)
 this function is invoked by a user of the safe_callback derived object. More...
 
global_live_objects & _invocables ()
 provides access to the program-wide list of healthy callback objects. More...
 

Protected Member Functions

virtual void real_callback (callback_data_block &new_data)=0
 derived classes implement this to provide their callback functionality. More...
 

Detailed Description

A reasonably easy way to make callbacks safe from shutdown ordering issues.

If an object implementing an unsafe, standard callback is destroyed, then all of the pending callbacks on other threads are jeopardized. Objects with unsafe objects will not fare well in a multi-threaded program at all. This class ensures that no callback can ever occur on a dead object, but this promise is subject to the caveats below.

Caveat One:

if you have synchronization control over objects that you own, please DO NOT have them locked while your callback base class is being destroyed NOR when you call the end_availability() method. allowing them to be locked at those times can result in a program deadlock. ensuring this is a simple matter of having a properly formed destructor, as in caveat two.

Caveat Two:

an object that implements safe_callback MUST invoke the end_availability method as the FIRST thing in its destructor. otherwise, if some portions of the object are shutdown before the safe_callback is stopped, then the active callback invocation can have the rug pulled out from under it and suddenly be working with bad objects. here is an example of a safe destructor implementation:

my_safe_callback::~my_safe_callback() {
// safely revoke this object's listing before other destructions.
// destroy other objects now...
WHACK(first_thing); //...etc....
}
void end_availability()
prepares to shut down this object.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121

note also: if your object owns or is derived from more than one safe_callback, then ALL of those must have their end_availability methods invoked before ANY of the other objects owned can be destroyed. we recommend against deriving from more than one safe_callback just for simplicity's sake.

Definition at line 67 of file safe_callback.h.

Constructor & Destructor Documentation

◆ safe_callback()

processes::safe_callback::safe_callback ( )

construction signifies that the callback is now in operation.

Definition at line 109 of file safe_callback.cpp.

◆ ~safe_callback()

processes::safe_callback::~safe_callback ( )
virtual

actually destroys the object.

don't allow this to be called without having invoked end_availability() at the top of your derived class's destructor. otherwise, you have broken your code by failing caveat two, above.

Definition at line 114 of file safe_callback.cpp.

References non_continuable_error, and basis::WHACK().

Member Function Documentation

◆ _invocables()

global_live_objects& processes::safe_callback::_invocables ( )

provides access to the program-wide list of healthy callback objects.

this should not be used by anyone external to the safe_callback implementation.

Referenced by end_availability(), and invoke_callback().

◆ decoupled()

bool processes::safe_callback::decoupled ( ) const
inline

if true, then end_availability() was already invoked on the object.

if this is returning true, then one can trust that the object is properly deregistered and safely decoupled from the callback. a return of false means that the object still might be hooked into callbacks and it is not yet safe to destroy the object.

Definition at line 87 of file safe_callback.h.

◆ DEFINE_CLASS_NAME()

processes::safe_callback::DEFINE_CLASS_NAME ( "safe_callback"  )

◆ end_availability()

void processes::safe_callback::end_availability ( )

prepares to shut down this object.

This removes the object from the list of available callbacks. this MUST be called in a derived destructor BEFORE any other objects owned by the derived class are destroyed.

Definition at line 136 of file safe_callback.cpp.

References _invocables(), basis::mutex::lock(), basis::mutex::unlock(), and basis::WHACK().

◆ invoke_callback()

bool processes::safe_callback::invoke_callback ( callback_data_block new_data)

this function is invoked by a user of the safe_callback derived object.

this performs some safety checks before invoking the real_callback() method. given the caveats are adhered to, we automatically ensure that the object to be called actually exists in a healthy state. we also enforce that the called object cannot be destroyed until after any active callback invocation is finished, and that any pending callbacks are rejected once the object is invalid. true is returned if the safe callback was actually completed. a false return indicates that the object had already shut down. perhaps that's a sign that the caller should now remove the object if it hasn't already been removed externally... certainly if the call is rejected more than once, there's no reason to keep invoking the callback. each safe_callback implements its own locking to ensure that the object is still alive. thus, derived objects don't need to provide some separate proof of their health. this also allows the derived object to mostly ignore callback-related locking in its own synchronization code (mostly–see caveats above).

Definition at line 153 of file safe_callback.cpp.

References _invocables(), and real_callback().

◆ real_callback()

virtual void processes::safe_callback::real_callback ( callback_data_block new_data)
protectedpure virtual

derived classes implement this to provide their callback functionality.

this call will be prevented from ever occurring on an invalid "this" pointer (given the caveats above are adhered to).

Implemented in processes::mail_stop.

Referenced by invoke_callback().


The documentation for this class was generated from the following files: