From 3010785e58ec3d825f884999ca3138803e20e25d Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 3 Apr 2007 23:20:18 +0000 Subject: [PATCH] attempt to robustify --- dtool/src/dtoolbase/deletedChain.T | 55 +++++++++++++++++++++++++++++- dtool/src/dtoolbase/deletedChain.h | 12 +++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/dtool/src/dtoolbase/deletedChain.T b/dtool/src/dtoolbase/deletedChain.T index a6b541e70b..a71aca370d 100644 --- a/dtool/src/dtoolbase/deletedChain.T +++ b/dtool/src/dtoolbase/deletedChain.T @@ -169,6 +169,32 @@ deallocate(Type *ptr, TypeHandle type_handle) { #endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE } +//////////////////////////////////////////////////////////////////// +// Function: DeletedChain::validate +// Access: Public +// Description: Returns true if the pointer is valid, false if it has +// been deleted or if it was never a valid pointer. +// +// This is only meaningful in debug mode, where +// USE_DELETEDCHAINFLAG is defined. If not, this +// trivially returns true. +//////////////////////////////////////////////////////////////////// +template +INLINE bool DeletedChain:: +validate(const Type *ptr) { + TAU_PROFILE("bool DeletedChain::validate(Type *)", " ", TAU_USER); + if (ptr == (Type *)NULL) { + return false; + } + +#ifdef USE_DELETEDCHAINFLAG + TVOLATILE const ObjectNode *obj = type_to_node((Type *)ptr); + return AtomicAdjust::get(obj->_flag) == DCF_alive; +#else + return true; +#endif // NDEBUG +} + //////////////////////////////////////////////////////////////////// // Function: DeletedChain::node_to_type // Access: Private, Static @@ -213,7 +239,34 @@ template INLINE void DeletedChain:: init_lock() { if (_lock == (MutexImpl *)NULL) { - _lock = new MutexImpl; + do_init_lock(); } } #endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE + +#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE +//////////////////////////////////////////////////////////////////// +// Function: DeletedChain::do_init_lock +// Access: Private +// Description: Allocates the lock pointer if necessary. Makes some +// pains to protect itself from race conditions. +//////////////////////////////////////////////////////////////////// +template +void DeletedChain:: +do_init_lock() { + MutexImpl *lock = new MutexImpl; + + // Even though DELETED_CHAIN_USE_ATOMIC_EXCHANGE is not true, we + // will take advantage of the atomic exchange operation here, at + // startup. We have to rely on something, after all, before we have + // created the first mutex. + MutexImpl *result; + result = (MutexImpl *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_lock, (void *)NULL, (void *)lock); + + if (result != NULL) { + delete lock; + } + + assert(_lock != (MutexImpl *)NULL); +} +#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE diff --git a/dtool/src/dtoolbase/deletedChain.h b/dtool/src/dtoolbase/deletedChain.h index 731ab1b06a..80970b6200 100644 --- a/dtool/src/dtoolbase/deletedChain.h +++ b/dtool/src/dtoolbase/deletedChain.h @@ -39,7 +39,7 @@ #endif #ifndef NDEBUG -// In development mode, we defined USE_DELETEDCHAINFLAG, which +// In development mode, we define USE_DELETEDCHAINFLAG, which // triggers the piggyback of an additional word of data on every // allocated block, so we can ensure that an object is not // double-deleted and that the deleted chain remains intact. @@ -85,6 +85,8 @@ public: INLINE static Type *allocate(size_t size, TypeHandle type_handle); INLINE static void deallocate(Type *ptr, TypeHandle type_handle); + INLINE static bool validate(const Type *ptr); + private: class ObjectNode { public: @@ -117,6 +119,7 @@ private: // If we don't have atomic compare-and-exchange, we need to use a // Mutex to protect the above linked list. static INLINE void init_lock(); + static void do_init_lock(); static MutexImpl *_lock; #endif }; @@ -126,15 +129,18 @@ private: // DeletedChain. #define ALLOC_DELETED_CHAIN(Type) \ inline void *operator new(size_t size) { \ - return (void *)DeletedChain< Type >::allocate(size, get_type_handle(Type)); \ + return (void *)DeletedChain< Type >::allocate(size, get_type_handle(Type)); \ } \ inline void *operator new(size_t size, void *ptr) { \ return ptr; \ } \ inline void operator delete(void *ptr) { \ - DeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \ + DeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \ } \ inline void operator delete(void *, void *) { \ + } \ + inline static bool validate_ptr(const void *ptr) { \ + return DeletedChain< Type >::validate((const Type *)ptr); \ } #include "deletedChain.T"