new fortune
[feisty_meow.git] / nucleus / library / processes / safe_callback.h
1 #ifndef SAFE_CALLBACK_CLASS
2 #define SAFE_CALLBACK_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : safe_callback                                                     *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
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 \*****************************************************************************/
17
18 #include <basis/astring.h>
19 #include <basis/mutex.h>
20 #include <basis/contracts.h>
21
22 namespace processes {
23
24 // forward.
25 class callback_data_block;
26 class global_live_objects;
27
28 //! A reasonably easy way to make callbacks safe from shutdown ordering issues.
29 /*!
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.
35
36   Caveat One:
37
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.
43
44   Caveat Two:
45
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
52
53     my_safe_callback::~my_safe_callback() {
54       // safely revoke this object's listing before other destructions.
55       end_availability();
56       // destroy other objects now...
57       WHACK(first_thing);  //...etc....
58     } @endcode
59
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
64   simplicity's sake.
65 */
66
67 class safe_callback
68 {
69 public:
70   safe_callback();
71     //!< construction signifies that the callback is now in operation.
72
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. */
78
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. */
84
85   DEFINE_CLASS_NAME("safe_callback");
86
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. */
93
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). */
112
113 protected:
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). */
118
119 private:
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. */
125
126 public:
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
130     implementation. */
131 };
132
133 //////////////
134
135 //! a simple place-holder that anonymizes the type passed to the callback.
136 /*!
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
139   callback.
140 */
141 class callback_data_block
142 {
143 public:
144   virtual ~callback_data_block();
145 };
146  
147 //////////////
148
149 } //namespace.
150
151 #endif
152