r3855 - in trunk/birnet: . tests
- From: timj svn gnome org
- To: svn-commits-list gnome org
- Subject: r3855 - in trunk/birnet: . tests
- Date: Mon, 14 Aug 2006 19:23:59 -0400 (EDT)
Author: timj
Date: 2006-08-14 19:23:06 -0400 (Mon, 14 Aug 2006)
New Revision: 3855
Modified:
trunk/birnet/ChangeLog
trunk/birnet/birnetsignal.hh
trunk/birnet/birnetsignalslot.hh
trunk/birnet/birnetthread.c
trunk/birnet/birnetthread.h
trunk/birnet/birnetthreadxx.cc
trunk/birnet/birnetutilsxx.cc
trunk/birnet/birnetutilsxx.hh
trunk/birnet/tests/signal.cc
trunk/birnet/tests/threads.cc
Log:
Tue Jul 18 01:14:22 2006 Tim Janik <timj gtk org>
* birnetthreadxx.cc: use birnet_*__chain4init() and
birnet_*__unchain() functions to construct initializer lists for
mutexes and conditions. that way we don't require std::list to be
constructed at static mutex construction time (which can be a
problem).
* birnetthread.h, birnetthread.c: provide chain4init and
unchain variants for recursive mutexes and conditions. this required
reordering of the BirnetRecMutex fields. provide static declaration
macros for recursive mutexes and conditions in C.
* birnetsignalslot.hh: hook trampolines into the destruction phase
of a Deletable, if the instance of a method trampoline is a Deletable.
as a side effect of this, slot-= only works for Deletable instance
methods, *before* the instance is deleted.
* birnetsignal.hh: provide VoidSlot and BoolSlot for convenience.
* birnetutilsxx.hh, birnetutilsxx.cc: implemented class
Deletable::DestructionHook which allowes hooking up (thread safe) of
callbacks into the destruction phase of a Deletable.
* tests/signal.cc: added tests for signal connections on temporary
objects that trigger Deletable destruction hooks.
* tests/threads.cc: test statically declared recursive mutextes and
conditions in C.
Modified: trunk/birnet/ChangeLog
===================================================================
--- trunk/birnet/ChangeLog 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/ChangeLog 2006-08-14 23:23:06 UTC (rev 3855)
@@ -1,3 +1,33 @@
+Tue Jul 18 01:14:22 2006 Tim Janik <timj gtk org>
+
+ * birnetthreadxx.cc: use birnet_*__chain4init() and
+ birnet_*__unchain() functions to construct initializer lists for
+ mutexes and conditions. that way we don't require std::list to be
+ constructed at static mutex construction time (which can be a
+ problem).
+
+ * birnetthread.h, birnetthread.c: provide chain4init and
+ unchain variants for recursive mutexes and conditions. this required
+ reordering of the BirnetRecMutex fields. provide static declaration
+ macros for recursive mutexes and conditions in C.
+
+ * birnetsignalslot.hh: hook trampolines into the destruction phase
+ of a Deletable, if the instance of a method trampoline is a Deletable.
+ as a side effect of this, slot-= only works for Deletable instance
+ methods, *before* the instance is deleted.
+
+ * birnetsignal.hh: provide VoidSlot and BoolSlot for convenience.
+
+ * birnetutilsxx.hh, birnetutilsxx.cc: implemented class
+ Deletable::DestructionHook which allowes hooking up (thread safe) of
+ callbacks into the destruction phase of a Deletable.
+
+ * tests/signal.cc: added tests for signal connections on temporary
+ objects that trigger Deletable destruction hooks.
+
+ * tests/threads.cc: test statically declared recursive mutextes and
+ conditions in C.
+
Fri Jul 7 02:15:50 2006 Tim Janik <timj gtk org>
* tests/infotest.cc: implement file tests in terms of the C++ API
Modified: trunk/birnet/birnetsignal.hh
===================================================================
--- trunk/birnet/birnetsignal.hh 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetsignal.hh 2006-08-14 23:23:06 UTC (rev 3855)
@@ -42,7 +42,7 @@
explicit TrampolineLink() :
next (NULL), prev (NULL), callable (true), with_emitter (false)
{}
- virtual bool operator== (const TrampolineLink &other) const = 0;
+ virtual bool operator== (const TrampolineLink &other) const = 0;
virtual ~TrampolineLink()
{
if (next || prev)
@@ -439,6 +439,10 @@
/* --- Trampoline + Slot + Signal generation --- */
#include <birnet/birnetsignalvariants.hh> // contains multiple versions of "birnetsignaltemplate.hh"
+/* --- predefined slots --- */
+typedef Slot0<void, void> VoidSlot;
+typedef Slot0<bool, void> BoolSlot;
+
/* --- predefined signals --- */
template<class Emitter>
struct SignalFinalize : Signal0 <Emitter, void, ScopeReferenceFinalizationMark> {
@@ -464,6 +468,8 @@
using Signals::CollectorUntil0;
using Signals::CollectorLast;
using Signals::CollectorSum;
+using Signals::VoidSlot;
+using Signals::BoolSlot;
using Signals::SignalFinalize;
using Signals::SignalVoid;
using Signals::Signal;
Modified: trunk/birnet/birnetsignalslot.hh
===================================================================
--- trunk/birnet/birnetsignalslot.hh 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetsignalslot.hh 2006-08-14 23:23:06 UTC (rev 3855)
@@ -38,7 +38,7 @@
Callback callback;
virtual R0 operator() (A1 a1, A2 a2, A3 a3)
{ return callback (a1, a2, a3); }
- ~FunctionTrampoline3() {}
+ virtual ~FunctionTrampoline3() {}
virtual bool operator== (const TrampolineLink &bother) const {
const FunctionTrampoline3 *other = dynamic_cast<const FunctionTrampoline3*> (&bother);
return other and other->callback == callback; }
@@ -48,21 +48,21 @@
{}
};
template<class Class, typename R0, typename A1, typename A2, typename A3>
-class MethodTrampoline3 : public Trampoline3 <R0, A1, A2, A3> {
+class MethodTrampoline3 : public Trampoline3 <R0, A1, A2, A3>, public virtual Deletable::DestructionHook {
friend void FIXME_dummy_friend_for_gcc33();
typedef R0 (Class::*Method) (A1, A2, A3);
Class *instance;
Method method;
virtual R0 operator() (A1 a1, A2 a2, A3 a3)
{ return (instance->*method) (a1, a2, a3); }
- ~MethodTrampoline3() {}
virtual bool operator== (const TrampolineLink &bother) const {
const MethodTrampoline3 *other = dynamic_cast<const MethodTrampoline3*> (&bother);
return other and other->instance == instance and other->method == method; }
+ virtual ~MethodTrampoline3() { deletable_remove_hook (instance); }
+ virtual void deletable_dispose (Deletable &deletable) { instance = NULL; this->callable = false; }
public:
MethodTrampoline3 (Class &obj, Method m) :
- instance (&obj), method (m)
- {}
+ instance (&obj), method (m) { deletable_add_hook (instance); }
};
/* --- Trampoline with Data --- */
@@ -73,7 +73,7 @@
Callback callback; Data data;
virtual R0 operator() (A1 a1, A2 a2, A3 a3)
{ return callback (a1, a2, a3, data); }
- ~DataFunctionTrampoline3() {}
+ virtual ~DataFunctionTrampoline3() {}
virtual bool operator== (const TrampolineLink &bother) const {
const DataFunctionTrampoline3 *other = dynamic_cast<const DataFunctionTrampoline3*> (&bother);
return other and other->callback == callback and other->data == data; }
@@ -83,20 +83,20 @@
{}
};
template<class Class, typename R0, typename A1, typename A2, typename A3, typename Data>
-class DataMethodTrampoline3 : public Trampoline3 <R0, A1, A2, A3> {
+class DataMethodTrampoline3 : public Trampoline3 <R0, A1, A2, A3>, public virtual Deletable::DestructionHook {
friend void FIXME_dummy_friend_for_gcc33();
typedef R0 (Class::*Method) (A1, A2, A3, Data);
Class *instance; Method method; Data data;
virtual R0 operator() (A1 a1, A2 a2, A3 a3)
{ return (instance->*method) (a1, a2, a3, data); }
- ~DataMethodTrampoline3() {}
virtual bool operator== (const TrampolineLink &bother) const {
const DataMethodTrampoline3 *other = dynamic_cast<const DataMethodTrampoline3*> (&bother);
return other and other->instance == instance and other->method == method and other->data == data; }
+ virtual ~DataMethodTrampoline3() { deletable_remove_hook (instance); }
+ virtual void deletable_dispose (Deletable &deletable) { instance = NULL; this->callable = false; }
public:
DataMethodTrampoline3 (Class &obj, Method m, const Data &d) :
- instance (&obj), method (m), data (d)
- {}
+ instance (&obj), method (m), data (d) { deletable_add_hook (instance); }
};
/* --- Slots (Trampoline wrappers) --- */
Modified: trunk/birnet/birnetthread.c
===================================================================
--- trunk/birnet/birnetthread.c 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetthread.c 2006-08-14 23:23:06 UTC (rev 3855)
@@ -1284,8 +1284,8 @@
fallback_rec_mutex_init (BirnetRecMutex *rec_mutex)
{
rec_mutex->owner = NULL;
+ rec_mutex->depth = 0;
birnet_mutex_init (&rec_mutex->mutex);
- rec_mutex->depth = 0;
}
static int
@@ -1471,6 +1471,7 @@
static void
pth_rec_mutex_init (BirnetRecMutex *mutex)
{
+ BIRNET_STATIC_ASSERT (offsetof (BirnetRecMutex, mutex) == 0);
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
@@ -1542,6 +1543,73 @@
}
void
+birnet_mutex__unchain (BirnetMutex *mutex)
+{
+ BirnetMutex *last = NULL, *m = mutex_init_chain;
+ while (m != mutex)
+ {
+ last = m;
+ m = last->mutex_pointer;
+ }
+ if (last)
+ last->mutex_pointer = mutex->mutex_pointer;
+ else
+ mutex_init_chain = mutex->mutex_pointer;
+}
+
+static BirnetMutex *rec_mutex_init_chain = NULL;
+
+void
+birnet_rec_mutex__chain4init (BirnetRecMutex *rec_mutex)
+{
+ BIRNET_STATIC_ASSERT (offsetof (BirnetRecMutex, mutex) == 0);
+ g_assert (rec_mutex->mutex.mutex_pointer == NULL);
+ rec_mutex->mutex.mutex_pointer = rec_mutex_init_chain;
+ rec_mutex_init_chain = &rec_mutex->mutex;
+}
+
+void
+birnet_rec_mutex__unchain (BirnetRecMutex *rec_mutex)
+{
+ BirnetMutex *mutex = (BirnetMutex*) rec_mutex;
+ BirnetMutex *last = NULL, *m = rec_mutex_init_chain;
+ while (m != mutex)
+ {
+ last = m;
+ m = last->mutex_pointer;
+ }
+ if (last)
+ last->mutex_pointer = mutex->mutex_pointer;
+ else
+ rec_mutex_init_chain = mutex->mutex_pointer;
+}
+
+static BirnetCond *cond_init_chain = NULL;
+
+void
+birnet_cond__chain4init (BirnetCond *cond)
+{
+ g_assert (cond->cond_pointer == NULL);
+ cond->cond_pointer = cond_init_chain;
+ cond_init_chain = cond;
+}
+
+void
+birnet_cond__unchain (BirnetCond *cond)
+{
+ BirnetCond *last = NULL, *c = cond_init_chain;
+ while (c != cond)
+ {
+ last = c;
+ c = last->cond_pointer;
+ }
+ if (last)
+ last->cond_pointer = cond->cond_pointer;
+ else
+ cond_init_chain = cond->cond_pointer;
+}
+
+void
_birnet_init_threads (void)
{
BirnetThreadTable *table = get_pth_thread_table ();
@@ -1561,6 +1629,19 @@
mutex_init_chain = mutex->mutex_pointer;
birnet_thread_table.mutex_init (mutex);
}
+ while (rec_mutex_init_chain)
+ {
+ BirnetMutex *mutex = rec_mutex_init_chain;
+ rec_mutex_init_chain = mutex->mutex_pointer;
+ BIRNET_STATIC_ASSERT (offsetof (BirnetRecMutex, mutex) == 0);
+ birnet_thread_table.rec_mutex_init ((BirnetRecMutex*) mutex);
+ }
+ while (cond_init_chain)
+ {
+ BirnetCond *cond = cond_init_chain;
+ cond_init_chain = cond->cond_pointer;
+ birnet_thread_table.cond_init (cond);
+ }
_birnet_init_threads_cxx();
}
Modified: trunk/birnet/birnetthread.h
===================================================================
--- trunk/birnet/birnetthread.h 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetthread.h 2006-08-14 23:23:06 UTC (rev 3855)
@@ -137,6 +137,8 @@
BirnetInt64 max_useconds);
#define birnet_thread_exit(retval) (birnet_thread_table.thread_exit (retval))
#define BIRNET_MUTEX_DECLARE_INITIALIZED(mutexname) BIRNET_MUTEX__DECLARE_INITIALIZED (mutexname)
+#define BIRNET_REC_MUTEX_DECLARE_INITIALIZED(rmnam) BIRNET_REC_MUTEX__DECLARE_INITIALIZED (rmnam)
+#define BIRNET_COND_DECLARE_INITIALIZED(condname) BIRNET_COND__DECLARE_INITIALIZED (condname)
/* --- atomic operations --- */
extern inline void birnet_atomic_int_set (volatile int *atomic,
@@ -182,20 +184,35 @@
#endif
/* --- implementation --- */
-void _birnet_init_threads (void);
-void _birnet_init_threads_cxx (void);
-void* _birnet_thread_self_cxx (void);
-void* _birnet_thread_get_cxx (BirnetThread *thread);
-bool _birnet_thread_set_cxx (BirnetThread *thread,
- void *xxdata);
-void _birnet_thread_cxx_wrap (BirnetThread *thread); /* in birnetthreadxx.cc */
-void _birnet_thread_cxx_delete (void *thread); /* in birnetthreadxx.cc */
-void birnet_mutex__chain4init (BirnetMutex *mutex);
+void _birnet_init_threads (void);
+void _birnet_init_threads_cxx (void);
+void* _birnet_thread_self_cxx (void);
+void* _birnet_thread_get_cxx (BirnetThread *thread);
+bool _birnet_thread_set_cxx (BirnetThread *thread,
+ void *xxdata);
+void _birnet_thread_cxx_wrap (BirnetThread *thread); /* in birnetthreadxx.cc */
+void _birnet_thread_cxx_delete (void *thread); /* in birnetthreadxx.cc */
+void birnet_mutex__chain4init (BirnetMutex *mutex);
+void birnet_mutex__unchain (BirnetMutex *mutex);
+void birnet_rec_mutex__chain4init (BirnetRecMutex *rec_mutex);
+void birnet_rec_mutex__unchain (BirnetRecMutex *rec_mutex);
+void birnet_cond__chain4init (BirnetCond *cond);
+void birnet_cond__unchain (BirnetCond *cond);
#define BIRNET_MUTEX__DECLARE_INITIALIZED(mutexname) \
BirnetMutex mutexname = { 0 }; \
static void __attribute__ ((constructor)) \
BIRNET_CPP_PASTE4 (__birnet_mutex__autoinit, __LINE__, __, mutexname) (void) \
{ birnet_mutex__chain4init (&mutexname); }
+#define BIRNET_REC_MUTEX__DECLARE_INITIALIZED(recmtx) \
+ BirnetRecMutex recmtx = { { 0 } }; \
+ static void __attribute__ ((constructor)) \
+ BIRNET_CPP_PASTE4 (__birnet_rec_mutex__autoinit, __LINE__, __, recmtx) (void) \
+ { birnet_rec_mutex__chain4init (&recmtx); }
+#define BIRNET_COND__DECLARE_INITIALIZED(condname) \
+ BirnetCond condname = { 0 }; \
+ static void __attribute__ ((constructor)) \
+ BIRNET_CPP_PASTE4 (__birnet_cond__autoinit, __LINE__, __, condname) (void) \
+ { birnet_cond__chain4init (&condname); }
union _BirnetCond
{
@@ -209,9 +226,9 @@
};
struct _BirnetRecMutex
{
+ BirnetMutex mutex;
BirnetThread *owner;
- BirnetMutex mutex;
- guint depth;
+ guint depth;
};
struct _BirnetThreadTable
{
Modified: trunk/birnet/birnetthreadxx.cc
===================================================================
--- trunk/birnet/birnetthreadxx.cc 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetthreadxx.cc 2006-08-14 23:23:06 UTC (rev 3855)
@@ -242,14 +242,12 @@
birnet_thread_exit (retval);
}
-static std::list<BirnetMutex*> cxx_init_mutex_list;
-
Mutex::Mutex ()
{
if (birnet_threads_initialized())
birnet_thread_table.mutex_init (&mutex);
else
- cxx_init_mutex_list.push_back (&mutex);
+ birnet_mutex__chain4init (&mutex);
}
Mutex::~Mutex ()
@@ -257,17 +255,15 @@
if (birnet_threads_initialized())
birnet_thread_table.mutex_destroy (&mutex);
else
- cxx_init_mutex_list.remove (&mutex);
+ birnet_mutex__unchain (&mutex);
}
-static std::list<BirnetRecMutex*> cxx_init_rec_mutex_list;
-
RecMutex::RecMutex ()
{
if (birnet_threads_initialized())
birnet_thread_table.rec_mutex_init (&rmutex);
else
- cxx_init_rec_mutex_list.push_back (&rmutex);
+ birnet_rec_mutex__chain4init (&rmutex);
}
RecMutex::~RecMutex ()
@@ -275,17 +271,15 @@
if (birnet_threads_initialized())
birnet_thread_table.rec_mutex_destroy (&rmutex);
else
- cxx_init_rec_mutex_list.remove (&rmutex);
+ birnet_rec_mutex__unchain (&rmutex);
}
-static std::list<BirnetCond*> cxx_init_cond_list;
-
Cond::Cond ()
{
if (birnet_threads_initialized())
birnet_thread_table.cond_init (&cond);
else
- cxx_init_cond_list.push_back (&cond);
+ birnet_cond__chain4init (&cond);
}
Cond::~Cond ()
@@ -293,7 +287,7 @@
if (birnet_threads_initialized())
birnet_thread_table.cond_destroy (&cond);
else
- cxx_init_cond_list.remove (&cond);
+ birnet_cond__unchain (&cond);
}
OwnedMutex::OwnedMutex () :
@@ -302,7 +296,7 @@
if (birnet_threads_initialized())
birnet_thread_table.rec_mutex_init (&m_rec_mutex);
else
- cxx_init_rec_mutex_list.push_back (&m_rec_mutex);
+ birnet_rec_mutex__chain4init (&m_rec_mutex);
}
OwnedMutex::~OwnedMutex()
@@ -311,7 +305,7 @@
if (birnet_threads_initialized())
birnet_thread_table.rec_mutex_destroy (&m_rec_mutex);
else
- cxx_init_rec_mutex_list.remove (&m_rec_mutex);
+ birnet_rec_mutex__unchain (&m_rec_mutex);
}
} // Birnet
@@ -320,24 +314,6 @@
_birnet_init_threads_cxx (void)
{
using namespace Birnet;
- while (!cxx_init_mutex_list.empty())
- {
- BirnetMutex *mutex = cxx_init_mutex_list.front();
- cxx_init_mutex_list.pop_front();
- birnet_thread_table.mutex_init (mutex);
- }
- while (!cxx_init_rec_mutex_list.empty())
- {
- BirnetRecMutex *rmutex = cxx_init_rec_mutex_list.front();
- cxx_init_rec_mutex_list.pop_front();
- birnet_thread_table.rec_mutex_init (rmutex);
- }
- while (!cxx_init_cond_list.empty())
- {
- BirnetCond *cond = cxx_init_cond_list.front();
- cxx_init_cond_list.pop_front();
- birnet_thread_table.cond_init (cond);
- }
}
extern "C" void
Modified: trunk/birnet/birnetutilsxx.cc
===================================================================
--- trunk/birnet/birnetutilsxx.cc 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetutilsxx.cc 2006-08-14 23:23:06 UTC (rev 3855)
@@ -18,7 +18,7 @@
*/
#include "birnetutilsxx.hh"
#include "birnetutils.h"
-#include "birnetthread.h"
+#include "birnetthreadxx.hh"
#include "birnetmsg.h"
#include "birnetcpu.h"
#include <sys/time.h>
@@ -220,6 +220,151 @@
} // Path
+/* --- Deletable --- */
+
+/**
+ * @param deletable possible Deletable* handle
+ * @return TRUE if the hook was added
+ *
+ * Adds the destruction hook to @a deletable if it is non NULL.
+ * The destruction hook is asserted to be so far uninstalled.
+ * This function is MT-safe and may be called from any thread.
+ */
+bool
+Deletable::DestructionHook::deletable_add_hook (Deletable *deletable)
+{
+ if (deletable)
+ {
+ deletable->add_destruction_hook (this);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @param deletable possible Deletable* handle
+ * @return TRUE if the hook was removed
+ *
+ * Removes the destruction hook from @a deletable if it is non NULL.
+ * The destruction hook is asserted to be installed on @a deletable.
+ * This function is MT-safe and may be called from any thread.
+ */
+bool
+Deletable::DestructionHook::deletable_remove_hook (Deletable *deletable)
+{
+ if (deletable)
+ {
+ deletable->remove_destruction_hook (this);
+ return true;
+ }
+ return false;
+}
+
+static struct {
+ Mutex mutex;
+ std::map<Deletable*,Deletable::DestructionHook*> dmap;
+} deletable_maps[19]; /* use prime size for hashing, sum up to roughly 1k (use 83 for 4k) */
+
+/**
+ * @param hook valid destruction hook
+ *
+ * Add an uninstalled destruction hook to the deletable.
+ * This function is MT-safe and may be called from any thread.
+ */
+void
+Deletable::add_destruction_hook (DestructionHook *hook)
+{
+ uint32 hashv = ((gsize) (void*) this) % (sizeof (deletable_maps) / sizeof (deletable_maps[0]));
+ deletable_maps[hashv].mutex.lock();
+ BIRNET_ASSERT (hook);
+ BIRNET_ASSERT (!hook->next);
+ BIRNET_ASSERT (!hook->prev);
+ std::map<Deletable*,DestructionHook*>::iterator it;
+ it = deletable_maps[hashv].dmap.find (this);
+ if (it != deletable_maps[hashv].dmap.end())
+ {
+ hook->next = it->second;
+ it->second = hook;
+ if (hook->next)
+ hook->next->prev = hook;
+ }
+ else
+ deletable_maps[hashv].dmap[this] = hook;
+ deletable_maps[hashv].mutex.unlock();
+ //g_printerr ("DELETABLE-ADD(%p,%p)\n", this, hook);
+}
+
+/**
+ * @param hook valid destruction hook
+ *
+ * Remove a previously added destruction hook.
+ * This function is MT-safe and may be called from any thread.
+ */
+void
+Deletable::remove_destruction_hook (DestructionHook *hook)
+{
+ uint32 hashv = ((gsize) (void*) this) % (sizeof (deletable_maps) / sizeof (deletable_maps[0]));
+ deletable_maps[hashv].mutex.lock();
+ BIRNET_ASSERT (hook);
+ if (hook->next)
+ hook->next->prev = hook->prev;
+ if (hook->prev)
+ hook->prev->next = hook->next;
+ else
+ {
+ std::map<Deletable*,DestructionHook*>::iterator it;
+ it = deletable_maps[hashv].dmap.find (this);
+ BIRNET_ASSERT (it != deletable_maps[hashv].dmap.end());
+ BIRNET_ASSERT (it->second == hook);
+ it->second = hook->next;
+ }
+ hook->prev = NULL;
+ hook->next = NULL;
+ deletable_maps[hashv].mutex.unlock();
+ //g_printerr ("DELETABLE-REM(%p,%p)\n", this, hook);
+}
+
+/**
+ * Invoke all destruction hooks installed on this deletable.
+ */
+void
+Deletable::invoke_destruction_hooks()
+{
+ uint32 hashv = ((gsize) (void*) this) % (sizeof (deletable_maps) / sizeof (deletable_maps[0]));
+ while (TRUE)
+ {
+ /* lookup hook list */
+ deletable_maps[hashv].mutex.lock();
+ std::map<Deletable*,DestructionHook*>::iterator it;
+ DestructionHook *hooks;
+ it = deletable_maps[hashv].dmap.find (this);
+ if (it != deletable_maps[hashv].dmap.end())
+ {
+ hooks = it->second;
+ deletable_maps[hashv].dmap.erase (it);
+ }
+ else
+ hooks = NULL;
+ deletable_maps[hashv].mutex.unlock();
+ /* we're done if all hooks have been procesed */
+ if (!hooks)
+ break;
+ /* process hooks */
+ while (hooks)
+ {
+ DestructionHook *hook = hooks;
+ hooks = hook->next;
+ if (hooks)
+ hooks->prev = NULL;
+ hook->prev = NULL;
+ hook->next = NULL;
+ //g_printerr ("DELETABLE-DIS(%p,%p)\n", this, hook);
+ hook->deletable_dispose (*this);
+ }
+ }
+}
+
+
/* --- DataList --- */
void
DataList::set_data (NodeBase *node)
Modified: trunk/birnet/birnetutilsxx.hh
===================================================================
--- trunk/birnet/birnetutilsxx.hh 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/birnetutilsxx.hh 2006-08-14 23:23:06 UTC (rev 3855)
@@ -105,9 +105,25 @@
}
/* --- Deletable --- */
-class Deletable {
+struct Deletable {
+ class DestructionHook {
+ DestructionHook *prev;
+ DestructionHook *next;
+ friend class Deletable;
+ public:
+ explicit DestructionHook () : prev (NULL), next (NULL) {}
+ virtual void deletable_dispose (Deletable &deletable) = 0;
+ bool deletable_add_hook (void *any) { return false; }
+ bool deletable_add_hook (Deletable *deletable);
+ bool deletable_remove_hook (void *any) { return false; }
+ bool deletable_remove_hook (Deletable *deletable);
+ };
+private:
+ void add_destruction_hook (DestructionHook *hook);
+ void remove_destruction_hook (DestructionHook *hook);
protected:
- virtual ~Deletable() {}
+ void invoke_destruction_hooks ();
+ virtual ~Deletable() { invoke_destruction_hooks(); }
};
/* --- ReferenceCountImpl --- */
@@ -328,7 +344,7 @@
public:
T get_data () { return data; }
T swap (T d) { T result = data; data = d; return result; }
- ~Node()
+ virtual ~Node()
{
if (key)
{
Modified: trunk/birnet/tests/signal.cc
===================================================================
--- trunk/birnet/tests/signal.cc 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/tests/signal.cc 2006-08-14 23:23:06 UTC (rev 3855)
@@ -214,6 +214,83 @@
}
};
+static uint assertion_counter = 0;
+struct TemporaryObject : public virtual Deletable {
+ String msg, msg2;
+ TemporaryObject() :
+ msg ("TemporaryObject"), msg2 ("Blub")
+ {}
+ String string_callback (int i, String s, float f)
+ {
+ assertion_counter++;
+ TPRINT (" callback: %s (%d, %s, %f); [%s]\n", __func__, i, s.c_str(), f, msg.c_str());
+ return __func__;
+ }
+ String string_emitter_callback (Emitter3 &emitter, int i, String s, float f)
+ {
+ assertion_counter++;
+ TPRINT (" callback: %s (%d, %s, %f); [%s]\n", __func__, i, s.c_str(), f, msg.c_str());
+ return __func__;
+ }
+ void void_callback (int i, String s, float f)
+ {
+ assertion_counter++;
+ TPRINT (" callback: %s (%d, %s, %f); [%s]\n", __func__, i, s.c_str(), f, msg2.c_str());
+ }
+ void void_emitter_callback (Emitter3 &emitter, int i, String s, float f)
+ {
+ assertion_counter++;
+ TPRINT (" callback: %s (%d, %s, %f); [%s]\n", __func__, i, s.c_str(), f, msg2.c_str());
+ }
+ void never_ever_call_me (int i, String s, float f)
+ {
+ TASSERT (1 == 0);
+ }
+ static void
+ test_temporary_object (Emitter3 &e3)
+ {
+ TSTART ("Signals, temporary object");
+ uint ac = assertion_counter;
+ {
+ TemporaryObject tobj;
+ e3.sig_mixed += slot (tobj, &TemporaryObject::string_emitter_callback);
+ e3.sig_void_mixed += slot (tobj, &TemporaryObject::never_ever_call_me);
+ e3.sig_mixed += slot (tobj, &TemporaryObject::string_callback);
+ {
+ TemporaryObject tmp2;
+ e3.sig_void_mixed += slot (tmp2, &TemporaryObject::never_ever_call_me);
+ /* auto-disconnected at end of scope */
+ }
+ {
+ Emitter3 tmp_emitter;
+ tmp_emitter.sig_mixed += slot (tobj, &TemporaryObject::string_emitter_callback);
+ tmp_emitter.sig_mixed += slot (tobj, &TemporaryObject::string_callback);
+ tmp_emitter.sig_void_mixed += slot (tobj, &TemporaryObject::never_ever_call_me);
+ TemporaryObject tobj2;
+ tmp_emitter.sig_void_mixed += slot (tobj2, &TemporaryObject::never_ever_call_me);
+ tmp_emitter.sig_void_mixed += slot (tobj2, &TemporaryObject::never_ever_call_me);
+ tmp_emitter.sig_void_mixed -= slot (tobj2, &TemporaryObject::never_ever_call_me);
+ /* remove all slots from tmp_emitter */
+ }
+ e3.sig_void_mixed -= slot (tobj, &TemporaryObject::never_ever_call_me);
+ TASSERT (ac == assertion_counter);
+ e3.test_emissions();
+ TASSERT (ac < assertion_counter);
+ e3.sig_void_mixed += slot (tobj, &TemporaryObject::void_emitter_callback);
+ e3.sig_void_mixed += slot (tobj, &TemporaryObject::void_callback);
+ ac = assertion_counter;
+ e3.test_emissions();
+ TASSERT (ac < assertion_counter);
+ e3.sig_void_mixed += slot (tobj, &TemporaryObject::never_ever_call_me);
+ /* here, Deletable::invoke_destruction_hooks() is called */
+ }
+ ac = assertion_counter;
+ e3.test_emissions(); // all handlers got disconnected
+ TASSERT (ac == assertion_counter);
+ TDONE();
+ }
+};
+
static int tst_counter = 0;
static int
increment_tst_counter (void)
@@ -259,10 +336,14 @@
signal_test.basic_signal_tests();
signal_test.member_pointer_tests();
#endif
+ Emitter3 e3;
+ TemporaryObject::test_temporary_object (e3);
Connection3 c3;
- Emitter3 e3;
+ Connection3 c3b;
c3.test_signal (e3);
- EmitterMany many;
- many.testme();
+ c3b.test_signal (e3);
+ EmitterMany many1, many2;
+ many1.testme();
+ many2.testme();
return 0;
}
Modified: trunk/birnet/tests/threads.cc
===================================================================
--- trunk/birnet/tests/threads.cc 2006-08-14 23:11:22 UTC (rev 3854)
+++ trunk/birnet/tests/threads.cc 2006-08-14 23:23:06 UTC (rev 3855)
@@ -96,6 +96,8 @@
}
static BIRNET_MUTEX_DECLARE_INITIALIZED (static_mutex);
+static BIRNET_REC_MUTEX_DECLARE_INITIALIZED (static_rec_mutex);
+static BIRNET_COND_DECLARE_INITIALIZED (static_cond);
static void
test_threads (void)
@@ -120,6 +122,19 @@
locked = birnet_mutex_trylock (&static_mutex);
TASSERT (locked);
birnet_mutex_unlock (&static_mutex);
+ /* not initializing static_rec_mutex */
+ locked = birnet_rec_mutex_trylock (&static_rec_mutex);
+ TASSERT (locked);
+ locked = birnet_rec_mutex_trylock (&static_rec_mutex);
+ TASSERT (locked);
+ birnet_rec_mutex_unlock (&static_rec_mutex);
+ birnet_rec_mutex_unlock (&static_rec_mutex);
+ locked = birnet_rec_mutex_trylock (&static_rec_mutex);
+ TASSERT (locked);
+ birnet_rec_mutex_unlock (&static_rec_mutex);
+ /* not initializing static_cond */
+ birnet_cond_signal (&static_cond);
+ birnet_cond_broadcast (&static_cond);
/* test C++ mutex */
static Mutex mutex;
static RecMutex rmutex;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]