📄 ncbiobj.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbiobj.cpp,v $ * PRODUCTION Revision 1000.5 2004/06/01 19:09:16 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.45 * PRODUCTION * =========================================================================== *//* $Id: ncbiobj.cpp,v 1000.5 2004/06/01 19:09:16 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: * Eugene Vasilchenko * * File Description: * Standard CObject and CRef classes for reference counter based GC * */#include <ncbi_pch.hpp>#include <corelib/ncbiobj.hpp>#include <corelib/ncbimtx.hpp>//#define USE_SINGLE_ALLOC// There was a long and bootless discussion:// is it possible to determine whether the object has been created// on the stack or on the heap.// Correct answer is "it is impossible"// Still, we try to... (we know it is not 100% bulletproof)//// Attempts include://// 1. operator new puts a pointer to newly allocated memory in the list.// Object constructor scans the list, if it finds itself there -// yes, it has been created on the heap. (If it does not find itself// there, it still may have been created on the heap).// This method requires thread synchronization.//// 2. operator new puts a special mask (eCounterNew two times) in the// newly allocated memory. Object constructor looks for this mask,// if it finds it there - yes, it has been created on the heap.//// 3. operator new puts a special mask (single eCounterNew) in the// newly allocated memory. Object constructor looks for this mask,// if it finds it there, it also compares addresses of a variable// on the stack and itself (also using STACK_THRESHOLD). If these two// are "far enough from each other" - yes, the object is on the heap.//// From these three methods, the first one seems to be most reliable,// but also most slow.// Method #2 is hopefully reliable enough// Method #3 is unreliable at all (we saw this)//#define USE_HEAPOBJ_LIST 0#if USE_HEAPOBJ_LIST# include <corelib/ncbi_safe_static.hpp># include <list># include <algorithm>#else# define USE_COMPLEX_MASK 1# if USE_COMPLEX_MASK# define STACK_THRESHOLD (64)# else# define STACK_THRESHOLD (16*1024)# endif#endifBEGIN_NCBI_SCOPE/////////////////////////////////////////////////////////////////////////////// CObject:://DEFINE_STATIC_FAST_MUTEX(sm_ObjectMutex);#if defined(NCBI_COUNTER_NEED_MUTEX)// CAtomicCounter doesn't normally have a .cpp file of its own, so this// goes here instead.DEFINE_STATIC_FAST_MUTEX(sm_AtomicCounterMutex);CAtomicCounter::TValue CAtomicCounter::Add(int delta) THROWS_NONE{ CFastMutexGuard LOCK(sm_AtomicCounterMutex); return m_Value += delta;}#endif#if USE_HEAPOBJ_LISTstatic CSafeStaticPtr< list<const void*> > s_heap_obj;#endif#if USE_COMPLEX_MASKstatic inline CAtomicCounter* GetSecondCounter(CObject* ptr){ return reinterpret_cast<CAtomicCounter*> (ptr + 1);}#endif#ifdef USE_SINGLE_ALLOC#define SINGLE_ALLOC_THRESHOLD ( 2*1024)#define SINGLE_ALLOC_POOL_SIZE (1024*1024)DEFINE_STATIC_FAST_MUTEX(sx_SingleAllocMutex);static char* single_alloc_pool = 0;static size_t single_alloc_pool_size = 0;void* single_alloc(size_t size){ if ( size > SINGLE_ALLOC_THRESHOLD ) { return ::operator new(size); } sx_SingleAllocMutex.Lock(); size_t pool_size = single_alloc_pool_size; char* pool; if ( size > pool_size ) { pool_size = SINGLE_ALLOC_THRESHOLD; pool = (char*) malloc(pool_size); if ( !pool ) { sx_SingleAllocMutex.Unlock(); throw bad_alloc(); } memset(pool, 0, pool_size); single_alloc_pool = pool; single_alloc_pool_size = pool_size; } else { pool = single_alloc_pool; } single_alloc_pool = pool + size; single_alloc_pool_size = pool_size - size; sx_SingleAllocMutex.Unlock(); return pool;}#endif// CObject local new operator to mark allocation in heapvoid* CObject::operator new(size_t size){ _ASSERT(size >= sizeof(CObject)); size = max(size, sizeof(CObject) + sizeof(TCounter));#ifdef USE_SINGLE_ALLOC void* ptr = single_alloc(size);# if USE_COMPLEX_MASK GetSecondCounter(static_cast<CObject*>(ptr))->Set(eCounterNew);# endif// USE_COMPLEX_MASK static_cast<CObject*>(ptr)->m_Counter.Set(eCounterNew); return ptr;#else void* ptr = ::operator new(size);#if USE_HEAPOBJ_LIST {{ CFastMutexGuard LOCK(sm_ObjectMutex); s_heap_obj->push_front(ptr); }}#else// USE_HEAPOBJ_LIST memset(ptr, 0, size);# if USE_COMPLEX_MASK GetSecondCounter(static_cast<CObject*>(ptr))->Set(eCounterNew);# endif// USE_COMPLEX_MASK#endif// USE_HEAPOBJ_LIST static_cast<CObject*>(ptr)->m_Counter.Set(eCounterNew); return ptr;#endif}// CObject local new operator to mark allocation in other memory chunkvoid* CObject::operator new(size_t size, void* place){ _ASSERT(size >= sizeof(CObject));#ifdef USE_SINGLE_ALLOC return place;#else memset(place, 0, size); return place;#endif}// complement placement delete operator -> do nothingvoid CObject::operator delete(void* /*ptr*/, void* /*place*/){}// CObject local new operator to mark allocation in heapvoid* CObject::operator new[](size_t size){#ifdef USE_SINGLE_ALLOC return single_alloc(size);#else# ifdef NCBI_OS_MSWIN void* ptr = ::operator new(size);# else void* ptr = ::operator new[](size);# endif memset(ptr, 0, size); return ptr;#endif}void CObject::operator delete(void* ptr){#ifdef USE_SINGLE_ALLOC#else# ifdef _DEBUG CObject* objectPtr = static_cast<CObject*>(ptr); _ASSERT(objectPtr->m_Counter.Get() == eCounterDeleted || objectPtr->m_Counter.Get() == eCounterNew);# endif ::operator delete(ptr);#endif}void CObject::operator delete[](void* ptr){#ifdef USE_SINGLE_ALLOC#else# ifdef NCBI_OS_MSWIN ::operator delete(ptr);# else ::operator delete[](ptr);# endif#endif}// initialization in debug modevoid CObject::InitCounter(void){ // This code can't use Get(), which may block waiting for an // update that will never happen. // ATTENTION: this code can cause UMR (Uninit Mem Read) -- it's okay here! if ( m_Counter.m_Value != eCounterNew ) { // takes care of statically allocated case m_Counter.Set(eCounterNotInHeap); } else { bool inStack = false;#if USE_HEAPOBJ_LIST const void* ptr = dynamic_cast<const void*>(this); {{ CFastMutexGuard LOCK(sm_ObjectMutex); list<const void*>::iterator i = find( s_heap_obj->begin(), s_heap_obj->end(), ptr); inStack = (i == s_heap_obj->end()); if (!inStack) { s_heap_obj->erase(i); } }}#else // USE_HEAPOBJ_LIST# if USE_COMPLEX_MASK inStack = GetSecondCounter(this)->m_Value != eCounterNew;# endif // USE_COMPLEX_MASK // m_Counter == eCounterNew -> possibly in heap if (!inStack) { char stackObject; const char* stackObjectPtr = &stackObject; const char* objectPtr = reinterpret_cast<const char*>(this); inStack =# ifdef STACK_GROWS_UP (objectPtr < stackObjectPtr) &&# else (objectPtr < stackObjectPtr + STACK_THRESHOLD) &&# endif# ifdef STACK_GROWS_DOWN (objectPtr > stackObjectPtr);# else (objectPtr > stackObjectPtr - STACK_THRESHOLD);# endif }#endif // USE_HEAPOBJ_LIST // surely not in heap if ( inStack ) m_Counter.Set(eCounterNotInHeap); else m_Counter.Set(eCounterInHeap); }}CObject::CObject(void){ InitCounter();}CObject::CObject(const CObject& /*src*/){ InitCounter();}#ifdef _DEBUG# define ObjFatal Fatal#else# define ObjFatal Critical#endifCObject::~CObject(void){ TCount count = m_Counter.Get(); if ( count == TCount(eCounterInHeap) || count == TCount(eCounterNotInHeap) ) { // reference counter is zero -> ok } else if ( ObjectStateValid(count) ) { _ASSERT(ObjectStateReferenced(count)); // referenced object ERR_POST(ObjFatal << "CObject::~CObject: " "Referenced CObject may not be deleted"); } else if ( count == eCounterDeleted ) { // deleted object ERR_POST(ObjFatal << "CObject::~CObject: " "CObject is already deleted"); } else { // bad object ERR_POST(ObjFatal << "CObject::~CObject: " "CObject is corrupted"); } // mark object as deleted m_Counter.Set(eCounterDeleted);}void CObject::CheckReferenceOverflow(TCount count) const{ if ( ObjectStateValid(count) ) { // counter overflow NCBI_THROW(CObjectException, eRefOverflow, "CObject's reference counter overflow"); } else if ( count == eCounterDeleted ) { // deleted object NCBI_THROW(CObjectException, eDeleted, "CObject is already deleted"); } else { // bad object NCBI_THROW(CObjectException, eCorrupted, "CObject is corrupted"); }}void CObject::RemoveLastReference(void) const{ TCount count = m_Counter.Get(); if ( ObjectStateCanBeDeleted(count) ) { if ( count == TCount(eCounterInHeap) ) { // last reference to heap object -> delete delete this; return; } } else { if ( ObjectStateValid(count) ) { // last reference to non heap object -> do nothing return; } } // Error here // restore original value m_Counter.Add(eCounterStep); _ASSERT(!ObjectStateValid(count + eCounterStep)); // bad object ERR_POST(ObjFatal << "CObject::RemoveLastReference: " "Unreferenced CObject may not be released");}void CObject::ReleaseReference(void) const{ TCount count = m_Counter.Add(-eCounterStep) + eCounterStep; if ( ObjectStateReferenced(count) ) { return; } m_Counter.Add(eCounterStep); // undo // error if ( !ObjectStateValid(count) ) { NCBI_THROW(CObjectException, eCorrupted, "CObject is corrupted"); } else { NCBI_THROW(CObjectException, eNoRef, "Unreferenced CObject may not be released"); }}void CObject::DoNotDeleteThisObject(void){ bool is_valid; {{ CFastMutexGuard LOCK(sm_ObjectMutex); TCount count = m_Counter.Get(); is_valid = ObjectStateValid(count); if (is_valid && !ObjectStateReferenced(count)) { m_Counter.Set(eCounterNotInHeap); return; } }} if ( is_valid ) { NCBI_THROW(CObjectException, eRefUnref, "Referenced CObject cannot be made unreferenced one"); } else { NCBI_THROW(CObjectException, eCorrupted, "CObject is corrupted"); }}void CObject::DoDeleteThisObject(void){ {{ CFastMutexGuard LOCK(sm_ObjectMutex); TCount count = m_Counter.Get(); if ( ObjectStateValid(count) ) { if ( !(count & eStateBitsInHeap) ) { m_Counter.Add(eStateBitsInHeap); } return; } }} NCBI_THROW(CObjectException, eCorrupted,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -