1 #ifndef SAFE_CALLBACK_CLASS
2 #define SAFE_CALLBACK_CLASS
4 /*****************************************************************************\
6 * Name : safe_callback *
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 2001-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include <basis/astring.h>
19 #include <basis/mutex.h>
20 #include <basis/contracts.h>
25 class callback_data_block;
26 class global_live_objects;
28 //! A reasonably easy way to make callbacks safe from shutdown ordering issues.
30 If an object implementing an unsafe, standard callback is destroyed, then
31 all of the pending callbacks on other threads are jeopardized. Objects with
32 unsafe objects will not fare well in a multi-threaded program at all. This
33 class ensures that no callback can ever occur on a dead object, but this
34 promise is subject to the caveats below.
38 if you have synchronization control over objects that you own, please
39 DO NOT have them locked while your callback base class is being destroyed
40 NOR when you call the end_availability() method. allowing them to be locked
41 at those times can result in a program deadlock. ensuring this is a simple
42 matter of having a properly formed destructor, as in caveat two.
46 an object that implements safe_callback MUST invoke the end_availability
47 method as the FIRST thing in its destructor. otherwise, if some portions
48 of the object are shutdown before the safe_callback is stopped, then the
49 active callback invocation can have the rug pulled out from under it and
50 suddenly be working with bad objects. here is an example of a safe
51 destructor implementation: @code
53 my_safe_callback::~my_safe_callback() {
54 // safely revoke this object's listing before other destructions.
56 // destroy other objects now...
57 WHACK(first_thing); //...etc....
60 note also: if your object owns or is derived from more than one
61 safe_callback, then ALL of those must have their end_availability methods
62 invoked before ANY of the other objects owned can be destroyed. we
63 recommend against deriving from more than one safe_callback just for
71 //!< construction signifies that the callback is now in operation.
73 void end_availability();
74 //!< prepares to shut down this object.
75 /*!< This removes the object from the list of available callbacks. this
76 MUST be called in a derived destructor BEFORE any other objects owned by
77 the derived class are destroyed. */
79 virtual ~safe_callback();
80 //!< actually destroys the object.
81 /*!< don't allow this to be called without having invoked
82 end_availability() at the top of your derived class's destructor.
83 otherwise, you have broken your code by failing caveat two, above. */
85 DEFINE_CLASS_NAME("safe_callback");
87 bool decoupled() const { return _decoupled; }
88 //!< if true, then end_availability() was already invoked on the object.
89 /*!< if this is returning true, then one can trust that the object is
90 properly deregistered and safely decoupled from the callback. a return of
91 false means that the object still might be hooked into callbacks and it is
92 not yet safe to destroy the object. */
94 bool invoke_callback(callback_data_block &new_data);
95 //!< this function is invoked by a user of the safe_callback derived object.
96 /*!< this performs some safety checks before invoking the real_callback()
97 method. given the caveats are adhered to, we automatically ensure that the
98 object to be called actually exists in a healthy state. we also enforce
99 that the called object cannot be destroyed until after any active
100 callback invocation is finished, and that any pending callbacks are
101 rejected once the object is invalid.
102 true is returned if the safe callback was actually completed. a false
103 return indicates that the object had already shut down. perhaps that's
104 a sign that the caller should now remove the object if it hasn't already
105 been removed externally... certainly if the call is rejected more than
106 once, there's no reason to keep invoking the callback.
107 each safe_callback implements its own locking to ensure that the
108 object is still alive. thus, derived objects don't need to provide some
109 separate proof of their health. this also allows the derived object
110 to mostly ignore callback-related locking in its own synchronization
111 code (mostly--see caveats above). */
114 virtual void real_callback(callback_data_block &new_data) = 0;
115 //!< derived classes implement this to provide their callback functionality.
116 /*!< this call will be prevented from ever occurring on an invalid "this"
117 pointer (given the caveats above are adhered to). */
120 bool _decoupled; //!< true if we have ended our availability.
121 basis::mutex *_callback_lock; //!< synchronizes access to this object.
122 void begin_availability();
123 //!< allows the safe_callback derived object to be called.
124 /*!< if this was never invoked, then attempts to callback are rejected. */
127 global_live_objects &_invocables();
128 //!< provides access to the program-wide list of healthy callback objects.
129 /*!< this should not be used by anyone external to the safe_callback
135 //! a simple place-holder that anonymizes the type passed to the callback.
137 the virtual destructor above ensures that RTTI can be used if necessary;
138 objects of different class types can be differentiated when passed to the
141 class callback_data_block
144 virtual ~callback_data_block();