|
@@ -44,11 +44,11 @@ allocate(size_t size) {
|
|
|
obj = _deleted_chain;
|
|
obj = _deleted_chain;
|
|
|
_deleted_chain = _deleted_chain->_next;
|
|
_deleted_chain = _deleted_chain->_next;
|
|
|
_lock->release();
|
|
_lock->release();
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- assert(obj->_flag == ((PN_int32)obj ^ deleted_chain_flag_hash));
|
|
|
|
|
- obj->_flag = 0;
|
|
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ assert(obj->_flag == (PN_int32)DCF_deleted);
|
|
|
|
|
+ obj->_flag = DCF_alive;
|
|
|
#endif // NDEBUG
|
|
#endif // NDEBUG
|
|
|
- return (Type *)obj;
|
|
|
|
|
|
|
+ return node_to_type(obj);
|
|
|
}
|
|
}
|
|
|
_lock->release();
|
|
_lock->release();
|
|
|
|
|
|
|
@@ -59,11 +59,11 @@ allocate(size_t size) {
|
|
|
TVOLATILE ObjectNode *result = (ObjectNode *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)obj, (void *)next);
|
|
TVOLATILE ObjectNode *result = (ObjectNode *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)obj, (void *)next);
|
|
|
if (result == obj) {
|
|
if (result == obj) {
|
|
|
// We got it.
|
|
// We got it.
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- assert(obj->_flag == ((PN_int32)obj ^ deleted_chain_flag_hash));
|
|
|
|
|
- obj->_flag = 0;
|
|
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ PN_int32 orig_flag = AtomicAdjust::compare_and_exchange(obj->_flag, DCF_deleted, DCF_alive);
|
|
|
|
|
+ assert(orig_flag == (PN_int32)DCF_deleted);
|
|
|
#endif // NDEBUG
|
|
#endif // NDEBUG
|
|
|
- return (Type *)obj;
|
|
|
|
|
|
|
+ return node_to_type(obj);
|
|
|
}
|
|
}
|
|
|
// Someone else grabbed the top link first. Try again.
|
|
// Someone else grabbed the top link first. Try again.
|
|
|
obj = _deleted_chain;
|
|
obj = _deleted_chain;
|
|
@@ -74,16 +74,23 @@ allocate(size_t size) {
|
|
|
// If we get here, the deleted_chain is empty; we have to allocate a
|
|
// If we get here, the deleted_chain is empty; we have to allocate a
|
|
|
// new object from the system pool.
|
|
// new object from the system pool.
|
|
|
|
|
|
|
|
|
|
+ size_t alloc_size = sizeof(Type);
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ // In development mode, we also need to reserve space for _flag.
|
|
|
|
|
+ alloc_size += sizeof(PN_int32);
|
|
|
|
|
+#endif // NDEBUG
|
|
|
|
|
+ size = max(alloc_size, sizeof(ObjectNode));
|
|
|
|
|
+
|
|
|
#ifdef DO_MEMORY_USAGE
|
|
#ifdef DO_MEMORY_USAGE
|
|
|
- obj = (ObjectNode *)(*global_operator_new)(max(sizeof(Type), sizeof(ObjectNode)));
|
|
|
|
|
|
|
+ obj = (ObjectNode *)(*global_operator_new)(alloc_size);
|
|
|
#else
|
|
#else
|
|
|
- obj = (ObjectNode *)malloc(max(sizeof(Type), sizeof(ObjectNode)));
|
|
|
|
|
|
|
+ obj = (ObjectNode *)malloc(alloc_size);
|
|
|
#endif
|
|
#endif
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- obj->_flag = 0;
|
|
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ obj->_flag = DCF_alive;
|
|
|
#endif // NDEBUG
|
|
#endif // NDEBUG
|
|
|
|
|
|
|
|
- return (Type *)obj;
|
|
|
|
|
|
|
+ return node_to_type(obj);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -95,13 +102,19 @@ template<class Type>
|
|
|
INLINE void DeletedChain<Type>::
|
|
INLINE void DeletedChain<Type>::
|
|
|
deallocate(Type *ptr) {
|
|
deallocate(Type *ptr) {
|
|
|
TAU_PROFILE("void DeletedChain<Type>::deallocate(Type *)", " ", TAU_USER);
|
|
TAU_PROFILE("void DeletedChain<Type>::deallocate(Type *)", " ", TAU_USER);
|
|
|
- TVOLATILE ObjectNode *obj = (ObjectNode *)ptr;
|
|
|
|
|
|
|
+ assert(ptr != (Type *)NULL);
|
|
|
|
|
+
|
|
|
|
|
+ TVOLATILE ObjectNode *obj = type_to_node(ptr);
|
|
|
|
|
+
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ PN_int32 orig_flag = AtomicAdjust::compare_and_exchange(obj->_flag, DCF_alive, DCF_deleted);
|
|
|
|
|
+
|
|
|
|
|
+ // If this assertion is triggered, you double-deleted an object.
|
|
|
|
|
+ assert(orig_flag != (PN_int32)DCF_deleted);
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- // We can't *guarantee* that this value is not a legitimate value of
|
|
|
|
|
- // the deleted object, so we can't safely make this assertion.
|
|
|
|
|
- // assert(obj->_flag != ((PN_int32)obj ^ deleted_chain_flag_hash));
|
|
|
|
|
- obj->_flag = (PN_int32)obj ^ deleted_chain_flag_hash;
|
|
|
|
|
|
|
+ // If this assertion is triggered, you tried to delete an object
|
|
|
|
|
+ // that was never allocated, or you have heap corruption.
|
|
|
|
|
+ assert(orig_flag == (PN_int32)DCF_alive);
|
|
|
#endif // NDEBUG
|
|
#endif // NDEBUG
|
|
|
|
|
|
|
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
@@ -126,13 +139,47 @@ deallocate(Type *ptr) {
|
|
|
do {
|
|
do {
|
|
|
next = _deleted_chain;
|
|
next = _deleted_chain;
|
|
|
obj->_next = next;
|
|
obj->_next = next;
|
|
|
- result = (ObjectNode *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)next, (void *)obj);
|
|
|
|
|
|
|
+ result = type_to_node(AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)next, (void *)obj));
|
|
|
// Keep trying until no one else got to _deleted_chain first.
|
|
// Keep trying until no one else got to _deleted_chain first.
|
|
|
} while (result != next);
|
|
} while (result != next);
|
|
|
|
|
|
|
|
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: DeletedChain::node_to_type
|
|
|
|
|
+// Access: Private, Static
|
|
|
|
|
+// Description: Casts an ObjectNode* to a Type*.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+template<class Type>
|
|
|
|
|
+INLINE Type *DeletedChain<Type>::
|
|
|
|
|
+node_to_type(TVOLATILE TYPENAME DeletedChain<Type>::ObjectNode *node) {
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ // In development mode, we increment the pointer so that the
|
|
|
|
|
+ // returned data does not overlap our _flags member.
|
|
|
|
|
+ return (Type *)(((PN_int32 *)node) + 1);
|
|
|
|
|
+#else
|
|
|
|
|
+ return (Type *)node;
|
|
|
|
|
+#endif // NDEBUG
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: DeletedChain::type_to_node
|
|
|
|
|
+// Access: Private, Static
|
|
|
|
|
+// Description: Casts a Type* to an ObjectNode* .
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+template<class Type>
|
|
|
|
|
+INLINE TYPENAME DeletedChain<Type>::ObjectNode *DeletedChain<Type>::
|
|
|
|
|
+type_to_node(Type *ptr) {
|
|
|
|
|
+#ifdef USE_DELETEDCHAINFLAG
|
|
|
|
|
+ // In development mode, we decrement the pointer to undo the
|
|
|
|
|
+ // increment we did above.
|
|
|
|
|
+ return (ObjectNode *)(((PN_int32 *)ptr) - 1);
|
|
|
|
|
+#else
|
|
|
|
|
+ return (ObjectNode *)ptr;
|
|
|
|
|
+#endif // NDEBUG
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: DeletedChain::init_lock
|
|
// Function: DeletedChain::init_lock
|