78 #define USE_HEAPOBJ_LIST 0
83 #elif USE_HEAPOBJ_LIST
88 # define USE_COMPLEX_MASK 1
90 # define STACK_THRESHOLD (64)
92 # define STACK_THRESHOLD (16*1024)
99 #define NCBI_USE_ERRCODE_X Corelib_Object
125 #ifdef NCBI_COUNTER_64_BIT
164 #if defined(NCBI_COUNTER_NEED_MUTEX)
172 return m_Value +=
delta;
184 #ifdef NCBI_NO_THREADS
201 #ifdef NCBI_WIN32_THREADS
202 TlsSetValue(
key,
nullptr);
204 pthread_setspecific(
key,
nullptr);
208 #ifdef NCBI_WIN32_THREADS
212 TlsSetValue(
key,
nullptr);
227 # ifdef NCBI_WIN32_THREADS
233 # ifndef NCBI_WIN32_THREADS
234 pthread_setspecific(
key, 0);
247 #ifdef NCBI_NO_THREADS
256 # ifdef NCBI_WIN32_THREADS
263 # ifdef NCBI_WIN32_THREADS
267 pthread_setspecific(
key,
set);
292 if ( it->first == ptr ) {
300 s_LastNewPtr =
set.front().first;
311 if ( s_LastNewPtr ) {
317 s_LastNewType =
type;
324 void* last_ptr = s_LastNewPtr;
334 if ( s_LastNewPtr != ptr ) {
356 #ifdef USE_SINGLE_ALLOC
357 #define SINGLE_ALLOC_THRESHOLD ( 2*1024)
358 #define SINGLE_ALLOC_POOL_SIZE (1024*1024)
362 static char* single_alloc_pool = 0;
363 static size_t single_alloc_pool_size = 0;
365 void* single_alloc(
size_t size)
367 if (
size > SINGLE_ALLOC_THRESHOLD ) {
368 return ::operator
new(
size);
370 sx_SingleAllocMutex.Lock();
371 size_t pool_size = single_alloc_pool_size;
373 if (
size > pool_size ) {
374 pool_size = SINGLE_ALLOC_POOL_SIZE;
375 pool = (
char*)
malloc(pool_size);
377 sx_SingleAllocMutex.Unlock();
380 single_alloc_pool = pool;
381 single_alloc_pool_size = pool_size;
384 pool = single_alloc_pool;
386 single_alloc_pool = pool +
size;
387 single_alloc_pool_size = pool_size -
size;
388 sx_SingleAllocMutex.Unlock();
396 #if defined(_DEBUG) && !defined(NCBI_COMPILER_MSVC)
397 # define ALLOC_FILL_MODE_INIT CObject::eAllocFillPattern
398 # define ALLOC_FILL_MODE_DEFAULT CObject::eAllocFillPattern
400 # define ALLOC_FILL_MODE_INIT CObject::eAllocFillZero
401 # define ALLOC_FILL_MODE_DEFAULT CObject::eAllocFillNone
403 #if defined(NCBI_COMPILER_MSVC)
404 # define ALLOC_FILL_BYTE_PATTERN 0xcd
406 # define ALLOC_FILL_BYTE_PATTERN 0xaa
412 const char*
env = ::getenv(
"NCBI_MEMORY_FILL");
464 memset(ptr, 0,
size);
472 void* CObject::operator
new(
size_t size)
477 #ifdef USE_SINGLE_ALLOC
478 void* ptr = single_alloc(
size);
483 void* ptr = ::operator
new(
size);
492 s_heap_obj->push_front(ptr);
496 # if USE_COMPLEX_MASK
507 void CObject::operator
delete(
void* ptr)
515 magic =
static_cast<CObject*
>(ptr)->m_Counter;
531 ::operator
delete(ptr);
536 void* CObject::operator
new(
size_t size,
void* place)
566 if ( !memory_pool ) {
567 return operator new(
size);
569 void* ptr = memory_pool->Allocate(
size);
571 return operator new(
size);
577 # if USE_COMPLEX_MASK
594 magic =
static_cast<CObject*
>(ptr)->m_Counter;
611 memory_pool->Deallocate(ptr);
616 void* CObject::operator
new[](
size_t size)
618 # ifdef NCBI_OS_MSWIN
619 void* ptr = ::operator
new(
size);
621 void* ptr = ::operator
new[](
size);
628 void CObject::operator
delete[](
void* ptr)
631 ::operator
delete(ptr);
633 ::operator
delete[](ptr);
639 # define ObjFatal Fatal
641 # define ObjFatal Critical
661 "Bad s_LastNewType="<<
type<<
684 bool inStack =
false;
686 const void* ptr =
dynamic_cast<const void*
>(
this);
689 list<const void*>::iterator
i =
690 find( s_heap_obj->begin(), s_heap_obj->end(), ptr);
691 inStack = (
i == s_heap_obj->end());
693 s_heap_obj->erase(
i);
697 # if USE_COMPLEX_MASK
698 inStack = GetSecondCounter(
this)->m_Value != main_counter;
703 const char* stackObjectPtr = &stackObject;
704 const char* objectPtr =
reinterpret_cast<const char*
>(
this);
705 # if defined STACK_GROWS_UP
707 (objectPtr < stackObjectPtr) &&
709 # elif defined STACK_GROWS_DOWN
711 (objectPtr > stackObjectPtr) &&
760 "Referenced CObject may not be deleted"<<StackTrace);
766 "CObject is already deleted"<<StackTrace);
771 "CObject is corrupted"<<StackTrace);
790 "CObject::CheckReferenceOverflow: "
791 "CObject's reference counter overflow");
797 "CObject::CheckReferenceOverflow: "
798 "CObject is already deleted");
803 "CObject::CheckReferenceOverflow: "
804 "CObject is corrupted");
846 "CObject was referenced again"<<StackTrace);
851 "CObject is already deleted"<<StackTrace);
855 "CObject is corrupted"<<StackTrace);
873 "CObject::ReleaseReference: "
874 "CObject is already deleted");
878 "CObject::ReleaseReference: "
879 "CObject is corrupted");
892 "CObject::DoNotDeleteThisObject: "
893 "CObject is allocated in heap");
905 m_Counter -= (count & eStateBitsInHeapMask);
915 "CObject::DoNotDeleteThisObject: "
916 "CObject is already deleted");
920 "CObject::DoNotDeleteThisObject: "
921 "CObject is corrupted");
928 #ifndef USE_SINGLE_ALLOC
935 "CObject::DoDeleteThisObject: "
936 "CObject is not allocated in heap");
946 static const TCount eCheckBits = eStateBitsValid | eStateBitsHeapSignature;
947 if ( (count & eCheckBits) == eCheckBits ) {
948 if ( !(count & eStateBitsInHeap) ) {
958 "object was created without heap signature"<<StackTrace);
964 "CObject::DoDeleteThisObject: "
965 "CObject is already deleted");
969 "CObject::DoDeleteThisObject: "
970 "CObject is corrupted");
1007 if ( TAbortOnNull::GetDefault() ) {
1022 if ( TAbortOnNull::GetDefault() ) {
1027 string(
"Attempt to access NULL pointer: ")+
type.
name());
1033 #ifndef NCBI_OBJECT_LOCKER_INLINE
1052 unsigned total_locks = 0;
1057 " @ " << *it->second);
1059 unsigned total_unlocks = 0;
1064 " @ " << *it->second);
1066 if ( total_locks ) {
1069 if ( total_unlocks ) {
1121 m_Locks[object].Locked(locker,
object);
1145 object->AddReference();
1163 object->RemoveReference();
1170 ERR_POST(
Note <<
"UnlockRelease<"<<
typeid(*object).name()<<
">"
1171 "("<<
this<<
", "<<
object<<
")"
1172 " @ " << StackTrace);
1175 object->ReleaseReference();
1233 "Type "<<
type.
name()<<
" must be derived from CObject");
1244 case eNoRef:
return "eNoRef";
1293 : m_Ptr(
NULL), m_WeakPtr(ptr)
1338 "Type "<<
type.
name()<<
" must be derived from CWeakObject");
1346 #ifdef USE_DEBUG_NEW
1348 static bool s_EnvFlag(
const char* env_var_name)
1350 const char*
value = getenv(env_var_name);
1358 unsigned seq_number;
1368 unsigned seq_number;
1372 static const size_t kAllocSizeBefore = 32;
1373 static const size_t kAllocSizeAfter = 32;
1375 static const char kAllocFillBeforeArray = 0xba;
1376 static const char kAllocFillBeforeOne = 0xbb;
1377 static const char kAllocFillInside = 0xdd;
1378 static const char kAllocFillAfter = 0xaa;
1379 static const char kAllocFillFree = 0xee;
1381 static const unsigned kAllocMagicHeader = 0x8b9b0b0b;
1382 static const unsigned kAllocMagicFooter = 0x9e8e0e0e;
1383 static const unsigned kFreedMagicHeader = 0x8b0bdead;
1384 static const unsigned kFreedMagicFooter = 0x9e0edead;
1387 static NCBI_NS_NCBI::CAtomicCounter seq_number;
1388 static const size_t kLogSize = 64 * 1024;
1390 unsigned seq_number;
1404 static SAllocLog alloc_log[kLogSize];
1407 static inline SAllocHeader* get_header(
void* ptr)
1409 return (SAllocHeader*) ((
char*) ptr-kAllocSizeBefore);
1413 static inline void* get_guard_before(SAllocHeader* header)
1415 return (
char*) header +
sizeof(SAllocHeader);
1419 static inline size_t get_guard_before_size()
1421 return kAllocSizeBefore -
sizeof(SAllocHeader);
1425 static inline size_t get_extra_size(
size_t size)
1431 static inline size_t get_guard_after_size(
size_t size)
1433 return kAllocSizeAfter -
sizeof(SAllocFooter) + get_extra_size(
size);
1437 static inline void* get_ptr(SAllocHeader* header)
1439 return (
char*) header + kAllocSizeBefore;
1443 static inline void* get_guard_after(SAllocFooter* footer,
size_t size)
1445 return (
char*)footer-get_guard_after_size(
size);
1449 static inline SAllocFooter* get_footer(SAllocHeader* header,
size_t size)
1451 return (SAllocFooter*)((
char*)get_ptr(header)+
size+get_guard_after_size(
size));
1455 static inline size_t get_total_size(
size_t size)
1457 return size+get_extra_size(
size) + (kAllocSizeBefore+kAllocSizeAfter);
1461 static inline size_t get_all_guards_size(
size_t size)
1463 return get_total_size(
size) - (
sizeof(SAllocHeader)+
sizeof(SAllocFooter));
1467 SAllocLog& start_log(
unsigned number, SAllocLog::EType
type)
1469 SAllocLog& slot = alloc_log[
number % kLogSize];
1470 slot.type = SAllocLog::eInit;
1471 slot.completed =
false;
1472 slot.seq_number =
number;
1480 void memchk(
const void* ptr,
char byte,
size_t size)
1482 for (
const char* p = (
const char*)ptr;
size; ++p, --
size ) {
1490 void* s_alloc_mem(
size_t size,
bool array)
throw()
1492 unsigned number = seq_number.Add(1);
1497 SAllocHeader* header;
1503 log.completed =
true;
1506 SAllocFooter* footer = get_footer(header,
size);
1508 header->magic = kAllocMagicHeader;
1509 footer->magic = kAllocMagicFooter;
1510 header->seq_number = footer->seq_number =
number;
1511 header->size = footer->size =
size;
1512 header->ptr = footer->ptr =
log.ptr = get_ptr(header);
1514 std::memset(get_guard_before(header),
1515 array? kAllocFillBeforeArray: kAllocFillBeforeOne,
1516 get_guard_before_size());
1517 std::memset(get_guard_after(footer,
size),
1519 get_guard_after_size(
size));
1520 std::memset(get_ptr(header), kAllocFillInside,
size);
1522 log.completed =
true;
1523 return get_ptr(header);
1527 void s_free_mem(
void* ptr,
bool array)
1529 unsigned number = seq_number.Add(1);
1531 start_log(
number,
array ? SAllocLog::eDeleteArr: SAllocLog::eDelete);
1535 SAllocHeader* header = get_header(ptr);
1536 if ( header->magic != kAllocMagicHeader ||
1537 header->seq_number >=
number ||
1538 header->ptr != get_ptr(header) ) {
1541 size_t size =
log.size = header->size;
1542 SAllocFooter* footer = get_footer(header,
size);
1543 if ( footer->magic != kAllocMagicFooter ||
1544 footer->seq_number != header->seq_number ||
1545 footer->ptr != get_ptr(header) ||
1546 footer->size !=
size ) {
1550 memchk(get_guard_before(header),
1551 array? kAllocFillBeforeArray: kAllocFillBeforeOne,
1552 get_guard_before_size());
1553 memchk(get_guard_after(footer,
size),
1555 get_guard_after_size(
size));
1557 header->magic = kFreedMagicHeader;
1558 footer->magic = kFreedMagicFooter;
1559 footer->seq_number =
number;
1560 static bool no_clear = s_EnvFlag(
"DEBUG_NEW_NO_FILL_ON_DELETE");
1562 std::memset(get_guard_before(header),
1564 get_all_guards_size(
size));
1566 static bool no_free = s_EnvFlag(
"DEBUG_NEW_NO_FREE_ON_DELETE");
1572 log.completed =
true;
1576 void*
operator new(
size_t size)
throw(std::bad_alloc)
1578 void* ret = s_alloc_mem(
size,
false);
1580 throw std::bad_alloc();
1585 void*
operator new(
size_t size,
const std::nothrow_t&)
throw()
1587 return s_alloc_mem(
size,
false);
1591 void*
operator new[](
size_t size)
throw(std::bad_alloc)
1593 void* ret = s_alloc_mem(
size,
true);
1595 throw std::bad_alloc();
1600 void*
operator new[](
size_t size,
const std::nothrow_t&)
throw()
1602 return s_alloc_mem(
size,
true);
1606 void operator delete(
void* ptr)
throw()
1608 s_free_mem(ptr,
false);
1612 void operator delete(
void* ptr,
const std::nothrow_t&)
throw()
1614 s_free_mem(ptr,
false);
1618 void operator delete[](
void* ptr)
throw()
1620 s_free_mem(ptr,
true);
1624 void operator delete[](
void* ptr,
const std::nothrow_t&)
throw()
1626 s_free_mem(ptr,
true);
@ eEmpty
no filtering at all.
void SetFrame(const string &frame)
void Log(const string &name, const char *value, CDebugDumpFormatter::EValueType type=CDebugDumpFormatter::eValue, const string &comment=kEmptyStr)
void DumpLocks(bool clear=false)
void Unlocked(const CObjectCounterLocker *locker, const CObject *object)
void Locked(const CObjectCounterLocker *locker, const CObject *object)
map< const CObject *, SLocks > TLocks
const_iterator lower_bound(const key_type &key) const
const_iterator end() const
iterator insert(const value_type &val)
container_type::iterator iterator
container_type::value_type value_type
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
TNCBIAtomicValue TValue
Alias TValue for TNCBIAtomicValue.
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
#define ERR_FATAL_X(err_subcode, message)
NCBI_XNCBI_EXPORT void Abort(void)
Smart abort function.
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
@ eDiag_Critical
Critical error message.
void Error(CExceptionArgs_Base &args)
#define NCBI_EXCEPTION_VAR(name, exception_class, err_code, message)
Create an instance of the exception to be thrown later.
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
#define NCBI_EXCEPTION_THROW(exception_var)
Throw an existing exception object.
virtual void x_InitErrCode(CException::EErrCode err_code)
Helper method for initializing error code.
#define THROWS_NONE
Do not use 'throw' dynamic exception specification for C++11 compilers.
EErrCode
Error types that an application can generate.
TErrCode GetErrCode(void) const
#define NCBI_THROW_FMT(exception_class, err_code, message)
The same as NCBI_THROW but with message processed as output to ostream.
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
void RemoveLastReference(TCount count) const
Remove the last reference.
void TransferLock(const CObject *object, const CObjectCounterLocker &old_locker) const
static const int eCounterStep
Skip over the "in heap" bits.
void Clear(void)
Set pointer to NULL from object's destructor.
void CleanWeakRefs(void) const
Method cleaning all CWeakRefs referencing at this moment to the object After calling to this method a...
Uint8 TCount
Alias for value type of counter.
static void ReportLockedObjects(bool clear=false)
Print all currently locked objects of monitored type.
virtual void DoDeleteThisObject(void)
Mark this object as allocated in heap – object can be deleted.
static void StopMonitoring(void)
Stop lock/unlock monitoring.
EAllocFillMode
Control filling of newly allocated memory.
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
static void SetAllocFillMode(EAllocFillMode mode)
CPtrToObjectProxy(CWeakObject *ptr)
static EAllocFillMode GetAllocFillMode(void)
void InitCounter(void)
Initialize counter.
bool x_AddWeakReference(CObject *obj)
Add reference to the object in "weak" manner.
virtual ~CObject(void)
Destructor.
virtual void DoNotDeleteThisObject(void)
Mark this object as not allocated in heap – do not delete this object.
void Relock(const CObject *object) const
void ReleaseReference(void) const
Remove reference without deleting object.
static bool ObjectStateReferencedOnlyOnce(TCount count)
Check if object can be referenced only once.
static NCBI_XNCBI_EXPORT void ThrowNullPointerException(void)
Define method to throw null pointer exception.
virtual void DebugDump(CDebugDumpContext ddc, unsigned int depth) const
Define method for dumping debug information.
virtual ~CWeakObject(void)
static const TCount eCounterBitsCanBeDeleted
Define possible object states.
void Reset(void)
Reset reference object.
void x_InitErrCode(CException::EErrCode err_code) override
Helper method for initializing error code.
void UnlockRelease(const CObject *object) const
virtual void DeleteThis(void)
Virtual method "deleting" this object.
static bool ObjectStateValid(TCount count)
Check if object state is valid.
static bool ObjectStateReferenced(TCount count)
Check if object can be referenced.
NCBI_XNCBI_EXPORT void CheckReferenceOverflow(TCount count) const
Report that counter has overflowed.
static void Delete(const CObject *object)
Check if object is allocated from some memory pool, and delete it correspondingly.
static bool ObjectStateIsAllocatedInPool(TCount count)
Check if object is allocated in memory pool.
static void ReportIncompatibleType(const type_info &type)
static const TCount eCounterValid
Minimal value for valid objects (reference counter is zero) Must be a single bit value.
static void MonitorObjectType(const type_info &type)
Set monitored object type, e.g.
CRef< CPtrToObjectProxy > m_SelfPtrProxy
Proxy object with pointer to this instance.
friend class CPtrToObjectProxy
CObject * GetLockedObject(void)
Lock the object and return pointer to it.
void Unlock(const CObject *object) const
atomic< Uint8 > TCounter
Counter type is CAtomiCounter.
static bool ObjectStateCanBeDeleted(TCount count)
Check if object can be deleted.
void Lock(const CObject *object) const
CObject(void)
Constructor.
static NCBI_XNCBI_EXPORT void ReportIncompatibleType(const type_info &type)
Report about trying to convert incompatible interface fo CObject.
static const TCount eCounterBitsInPlainHeap
Heap signature was found.
TCounter m_Counter
The actual reference counter.
static bool ObjectStateUnreferenced(TCount count)
Check if object can be referenced.
static const TCount eCounterStateMask
Valid object, and object in heap.
@ eDeleted
Attempt to delete a deleted object.
@ eRefDelete
Attempt to delete valid reference.
@ eCorrupted
Object corrupted error.
@ eRefOverflow
Reference overflow error.
@ eHeapState
Attempt to make incorrect in-heap state.
@ eRefUnref
Attempt to make a referenced object an unreferenced one.
@ eNoRef
Attempt to access an object that is unreferenced.
@ eParam_NoThread
Do not use per-thread values.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
TFastMutexGuard CFastMutexGuard
...and backward compatibility
pthread_key_t TTlsKey
Define internal TLS key type.
unsigned int
A callback function used to compare two keys in a database.
Definition of all error codes used in corelib (xncbi.lib).
where both of them are integers Note
const struct ncbi::grid::netcache::search::fields::SIZE size
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
static void s_Cleanup(void *data)
Static variables safety - create on demand, destroy on application termination.
#define NCBI_CONST_UINT8(v)
Memory pool for fast allocation of memory for localized set of CObjects, e.g.
Multi-threading – mutexes; rw-locks; semaphore.
#define ALLOC_FILL_BYTE_PATTERN
static DECLARE_TLS_VAR(void *, s_LastNewPtr)
static CObject::EAllocFillMode sx_InitFillNewMemoryMode(void)
static const CObject::TCount eInitCounterInHeap
Initial counter value for in-heap objects.
static const CObject::TCount eMagicCounterPoolNew
Magic counter value for objects allocated in memory pool.
static void sx_PushLastNewPtrMultiple(void *ptr, CAtomicCounter::TValue type)
static TTlsKey sx_GetLastNewPtrMultipleKey(void)
static void sx_FillNewMemory(void *ptr, size_t size)
bool MonitoredType(const CObject *object)
static CObject::EAllocFillMode sm_AllocFillMode
static const CObject::TCount eInitCounterInPool
Initial counter value for objects allocated in memory pool.
static CAtomicCounter::TValue sx_PopLastNewPtrMultiple(void *ptr)
static const CAtomicCounter::TValue kLastNewTypeMultiple
#define ALLOC_FILL_MODE_INIT
NCBI_PARAM_DEF_EX(bool, NCBI, ABORT_ON_COBJECT_THROW, false, eParam_NoThread, NCBI_ABORT_ON_COBJECT_THROW)
static CSafeStatic< CLocksMonitor > sx_LocksMonitor
static TLastNewPtrMultiple & sx_GetLastNewPtrMultiple(void)
static const CObject::TCount eMagicCounterNew
Magic counter value for object allocated in heap.
NCBI_PARAM_DECL(bool, NCBI, ABORT_ON_COBJECT_THROW)
#define ALLOC_FILL_MODE_DEFAULT
static const CObject::TCount eMagicCounterPoolDeleted
Magic counter value for deleted object allocated in memory pool.
typedef NCBI_PARAM_TYPE(NCBI, ABORT_ON_NULL) TAbortOnNull
static bool sm_AllocFillMode_IsSet
static CAtomicCounter::TValue sx_PopLastNewPtr(void *ptr)
static const type_info * sx_MonitorType
static const CObject::TCount eMagicCounterDeleted
All magic counter values should have all their state bits off.
vector< TLastNewPtrMultipleInfo > TLastNewPtrMultiple
static void sx_PushLastNewPtr(void *ptr, CAtomicCounter::TValue type)
DEFINE_STATIC_FAST_MUTEX(s_WeakRefMutex)
pair< void *, CAtomicCounter::TValue > TLastNewPtrMultipleInfo
static const CObject::TCount eInitCounterNotInHeap
Initial counter value for non-heap objects.
static atomic< TTlsKey > s_LastNewPtrMultiple_key
static TTlsKey sx_GetLastNewPtrMultipleCurrentKey(void)
Portable reference counted smart and weak pointers using CWeakRef, CRef, CObject and CObjectEx.
Multi-threading – classes, functions, and features.
Int4 delta(size_t dimension_, const Int4 *score_)
multimap< const CObjectCounterLocker *, AutoPtr< CStackTrace > > TUnlocks
int LockCount(void) const
multimap< const CObjectCounterLocker *, AutoPtr< CStackTrace > > TLocks
void Locked(const CObjectCounterLocker *locker, const CObject *object)
bool Unlocked(const CObjectCounterLocker *locker)
static void sx_Cleanup(void *ptr)
~SEraseLastNewPtrMultiple()