00001 #ifndef SAFE_CALLBACK_IMPLEMENTATION_FILE
00002 #define SAFE_CALLBACK_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "safe_callback.h"
00019
00020 #include <basis/guards.h>
00021 #include <basis/istring.h>
00022 #include <basis/mutex.h>
00023 #include <data_struct/byte_hasher.h>
00024 #include <data_struct/hash_table.cpp>
00025 #include <data_struct/static_memory_gremlin.h>
00026
00028
00029 callback_data_block::~callback_data_block() {}
00030
00032
00033 class live_object_info
00034 {
00035 public:
00036 int _references;
00037
00038 live_object_info() : _references(1) {}
00039 };
00040
00042
00043 static bool _live_objects_are_gone = false;
00044
00045
00046
00047 class global_live_objects : public virtual object_base
00048 {
00049 public:
00050 global_live_objects() : _objects(rotating_byte_hasher(), 12) {}
00051
00052
00053 ~global_live_objects() { _live_objects_are_gone = true; }
00054
00055 IMPLEMENT_CLASS_NAME("global_live_objects");
00056
00057
00058 bool listed(void *object) {
00059 auto_synchronizer l(_lock);
00060 live_object_info *loi = NIL;
00061 return _objects.find(object, loi);
00062 }
00063
00064
00065 void add(void *object) {
00066 auto_synchronizer l(_lock);
00067 live_object_info *loi = NIL;
00068 if (!_objects.find(object, loi)) {
00069
00070 _objects.add(object, new live_object_info);
00071 return;
00072 }
00073
00074 loi->_references++;
00075 }
00076
00077
00078
00079 void remove(void *object) {
00080 auto_synchronizer l(_lock);
00081 live_object_info *loi = NIL;
00082 if (!_objects.find(object, loi)) {
00083
00084 return;
00085 }
00086
00087 loi->_references--;
00088 if (!loi->_references) {
00089
00090 _objects.zap(object);
00091 }
00092 }
00093
00094 private:
00095 mutex _lock;
00096 hash_table<void *, live_object_info> _objects;
00097
00098 };
00099
00101
00102 safe_callback::safe_callback()
00103 : _decoupled(false),
00104 _callback_lock(new mutex)
00105 { begin_availability(); }
00106
00107 safe_callback::~safe_callback()
00108 {
00109 if (!_decoupled)
00110 non_continuable_error(class_name(), "destructor",
00111 "the derived safe_callback has not called end_availability() yet.\r\n"
00112 "this violates caveat two of safe_callback (see header).");
00113 WHACK(_callback_lock);
00114 }
00115
00116 SAFE_STATIC(global_live_objects, safe_callback::_invocables, )
00117
00118 void safe_callback::begin_availability()
00119 {
00120
00121
00122
00123
00124 _decoupled = false;
00125 if (_live_objects_are_gone) return;
00126 _invocables().add(this);
00127 }
00128
00129 void safe_callback::end_availability()
00130 {
00131 if (_decoupled) return;
00132 if (_live_objects_are_gone) {
00133
00134 _decoupled = true;
00135 return;
00136 }
00137 _callback_lock->lock();
00138 _invocables().remove(this);
00139 _decoupled = true;
00140 _callback_lock->unlock();
00141
00142
00143 WHACK(_callback_lock);
00144 }
00145
00146 bool safe_callback::invoke_callback(callback_data_block &new_data)
00147 {
00148 auto_synchronizer l(*_callback_lock);
00149
00150 if (!_invocables().listed(this)) return false;
00151
00152 if (_decoupled) return false;
00153
00154
00155
00156
00157
00158
00159
00160 real_callback(new_data);
00161 return true;
00162 }
00163
00164
00165 #endif //SAFE_CALLBACK_IMPLEMENTATION_FILE
00166