NCBI C++ ToolKit
ncbiobj.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbiobj.cpp 99781 2023-05-10 17:44:44Z vasilche $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author:
27  * Eugene Vasilchenko
28  *
29  * File Description:
30  * Standard CObject and CRef classes for reference counter based GC
31  *
32  */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbiobj.hpp>
36 #include <corelib/ncbimtx.hpp>
37 #include <corelib/ncbi_param.hpp>
38 #include <corelib/ncbimempool.hpp>
39 
40 //#define USE_SINGLE_ALLOC
41 //#define USE_DEBUG_NEW
42 
43 #ifdef USE_DEBUG_NEW
44 # include <cstring>
45 #endif
46 
47 // There was a long and bootless discussion:
48 // is it possible to determine whether the object has been created
49 // on the stack or on the heap.
50 // Correct answer is "it is impossible"
51 // Still, we try to... (we know it is not 100% bulletproof)
52 //
53 // Attempts include:
54 //
55 // 1. operator new puts a pointer to newly allocated memory in the list.
56 // Object constructor scans the list, if it finds itself there -
57 // yes, it has been created on the heap. (If it does not find itself
58 // there, it still may have been created on the heap).
59 // This method requires thread synchronization.
60 //
61 // 2. operator new puts a special mask (eMagicCounterNew two times) in the
62 // newly allocated memory. Object constructor looks for this mask,
63 // if it finds it there - yes, it has been created on the heap.
64 //
65 // 3. operator new puts a special mask (single eMagicCounterNew) in the
66 // newly allocated memory. Object constructor looks for this mask,
67 // if it finds it there, it also compares addresses of a variable
68 // on the stack and itself (also using STACK_THRESHOLD). If these two
69 // are "far enough from each other" - yes, the object is on the heap.
70 //
71 // From these three methods, the first one seems to be most reliable,
72 // but also most slow.
73 // Method #2 is hopefully reliable enough
74 // Method #3 is unreliable at all (we saw this)
75 //
76 
77 
78 #define USE_HEAPOBJ_LIST 0
79 #define USE_TLS_PTR 1
80 #if USE_TLS_PTR
81 # include <corelib/ncbithr.hpp>
82 # include <vector>
83 #elif USE_HEAPOBJ_LIST
85 # include <list>
86 # include <algorithm>
87 #else
88 # define USE_COMPLEX_MASK 1
89 # if USE_COMPLEX_MASK
90 # define STACK_THRESHOLD (64)
91 # else
92 # define STACK_THRESHOLD (16*1024)
93 # endif
94 #endif
95 
96 
97 #include <corelib/error_codes.hpp>
98 
99 #define NCBI_USE_ERRCODE_X Corelib_Object
100 
101 
103 
104 class CObject;
105 
106 /// Initial counter value for non-heap objects
109 /// Initial counter value for objects allocated in memory pool
112 /// Initial counter value for in-heap objects
116 #if !USE_TLS_PTR
117 /// Without unambiguous TLS ptr that tracks allocations
118 /// the library has to guess CObject location.
119 /// Here's is a value used to mark 'in stack' allocations.
120 /// Initial counter value for probably non-heap objects (w/ signature)
121 static const CObject::TCount eInitCounterInStack =
123 #endif
124 
125 #ifdef NCBI_COUNTER_64_BIT
126 /// All magic counter values should have all their state bits off.
127 /// Magic counter value for deleted objects
130 /// Magic counter value for object allocated in heap
131 static const CObject::TCount eMagicCounterNew =
133 /// Magic counter value for deleted object allocated in memory pool
136 /// Magic counter value for objects allocated in memory pool
139 #else
140 /// All magic counter values should have all their state bits off.
141 /// Magic counter value for deleted objects
143  0x5b4d9f34 & ~CObject::eCounterStateMask;
144 /// Magic counter value for object allocated in heap
146  0x3423cb13 & ~CObject::eCounterStateMask;
147 /// Magic counter value for deleted object allocated in memory pool
149  0x4229775b & ~CObject::eCounterStateMask;
150 /// Magic counter value for objects allocated in memory pool
152  0x54917ec2 & ~CObject::eCounterStateMask;
153 #endif
154 
155 /////////////////////////////////////////////////////////////////////////////
156 // CObject::
157 //
158 
159 
160 #if !USE_TLS_PTR
161 DEFINE_STATIC_FAST_MUTEX(sm_ObjectMutex);
162 #endif
163 
164 #if defined(NCBI_COUNTER_NEED_MUTEX)
165 // CAtomicCounter doesn't normally have a .cpp file of its own, so this
166 // goes here instead.
167 DEFINE_STATIC_FAST_MUTEX(sm_AtomicCounterMutex);
168 
170 {
171  CFastMutexGuard LOCK(sm_AtomicCounterMutex);
172  return m_Value += delta;
173 }
174 
175 #endif
176 
177 #if USE_TLS_PTR
178 
180 static DECLARE_TLS_VAR(void*, s_LastNewPtr);
182 typedef pair<void*, CAtomicCounter::TValue> TLastNewPtrMultipleInfo;
183 typedef vector<TLastNewPtrMultipleInfo> TLastNewPtrMultiple;
184 #ifdef NCBI_NO_THREADS
185 static TLastNewPtrMultiple* s_LastNewPtrMultiple_ptr;
186 #else
187 static atomic<TTlsKey> s_LastNewPtrMultiple_key;
188 
189 static inline
191 {
192  return s_LastNewPtrMultiple_key.load(memory_order_relaxed);
193 }
194 
196  static void sx_Cleanup(void* ptr)
197  {
198  TLastNewPtrMultiple* set = static_cast<TLastNewPtrMultiple*>(ptr);
200  delete set;
201 #ifdef NCBI_WIN32_THREADS
202  TlsSetValue(key, nullptr);
203 #else
204  pthread_setspecific(key, nullptr);
205 #endif
206  }
208 #ifdef NCBI_WIN32_THREADS
211  delete set;
212  TlsSetValue(key, nullptr);
213 #endif
214  }
215 };
216 
217 static inline
219 {
221  if ( !key ) {
222  DEFINE_STATIC_FAST_MUTEX(s_InitMutex);
223  NCBI_NS_NCBI::CFastMutexGuard guard(s_InitMutex);
224  key = s_LastNewPtrMultiple_key.load(memory_order_acquire);
225  if ( !key ) {
226  do {
227 # ifdef NCBI_WIN32_THREADS
228  _VERIFY((key = TlsAlloc()) != DWORD(-1));
229 # else
230  _VERIFY(pthread_key_create(&key, SEraseLastNewPtrMultiple::sx_Cleanup)==0);
231 # endif
232  } while ( !key );
233 # ifndef NCBI_WIN32_THREADS
234  pthread_setspecific(key, 0);
235 # endif
236  s_LastNewPtrMultiple_key.store(key, memory_order_release);
237  }
238  }
239  return key;
240 }
241 #endif
242 
243 
244 static
246 {
247 #ifdef NCBI_NO_THREADS
248  TLastNewPtrMultiple* set = s_LastNewPtrMultiple_ptr;
249  if ( !set ) {
250  s_LastNewPtrMultiple_ptr = set = new TLastNewPtrMultiple();
251  }
252  return *set;
253 #else
256 # ifdef NCBI_WIN32_THREADS
257  set = (TLastNewPtrMultiple*)TlsGetValue(key);
258 # else
259  set = (TLastNewPtrMultiple*)pthread_getspecific(key);
260 # endif
261  if ( !set ) {
262  set = new TLastNewPtrMultiple();
263 # ifdef NCBI_WIN32_THREADS
264  TlsSetValue(key, set);
265  static thread_local SEraseLastNewPtrMultiple s_Cleanup;
266 # else
267  pthread_setspecific(key, set);
268 # endif
269  }
270  return *set;
271 #endif
272 }
273 
274 
275 static
277 {
278  _ASSERT(s_LastNewPtr);
280  if ( s_LastNewType != kLastNewTypeMultiple ) {
281  set.push_back(TLastNewPtrMultipleInfo(s_LastNewPtr, s_LastNewType));
282  s_LastNewType = kLastNewTypeMultiple;
283  }
284  set.push_back(TLastNewPtrMultipleInfo(ptr, type));
285 }
286 
287 static
289 {
292  if ( it->first == ptr ) {
293  CAtomicCounter::TValue last_type = it->second;
294  swap(*it, set.back());
295  set.pop_back();
296  if ( set.empty() ) {
297  s_LastNewPtr = 0;
298  }
299  else {
300  s_LastNewPtr = set.front().first;
301  }
302  return last_type;
303  }
304  }
305  return 0;
306 }
307 
308 static inline
310 {
311  if ( s_LastNewPtr ) {
312  // multiple
314  }
315  else {
316  s_LastNewPtr = ptr;
317  s_LastNewType = type;
318  }
319 }
320 
321 static inline
323 {
324  void* last_ptr = s_LastNewPtr;
325  if ( !last_ptr ) {
326  return 0;
327  }
328  CAtomicCounter::TValue last_type = s_LastNewType;
329  if ( last_type == kLastNewTypeMultiple ) {
330  // multiple ptrs
331  return sx_PopLastNewPtrMultiple(ptr);
332  }
333  else {
334  if ( s_LastNewPtr != ptr ) {
335  return 0;
336  }
337  s_LastNewPtr = 0;
338  return last_type;
339  }
340 }
341 
342 #endif
343 
344 #if USE_HEAPOBJ_LIST
345 static CSafeStatic< list<const void*> > s_heap_obj;
346 #endif
347 
348 #if USE_COMPLEX_MASK
349 static inline CAtomicCounter* GetSecondCounter(CObject* ptr)
350 {
351  return reinterpret_cast<CAtomicCounter*> (ptr + 1);
352 }
353 #endif
354 
355 
356 #ifdef USE_SINGLE_ALLOC
357 #define SINGLE_ALLOC_THRESHOLD ( 2*1024)
358 #define SINGLE_ALLOC_POOL_SIZE (1024*1024)
359 
360 DEFINE_STATIC_FAST_MUTEX(sx_SingleAllocMutex);
361 
362 static char* single_alloc_pool = 0;
363 static size_t single_alloc_pool_size = 0;
364 
365 void* single_alloc(size_t size)
366 {
367  if ( size > SINGLE_ALLOC_THRESHOLD ) {
368  return ::operator new(size);
369  }
370  sx_SingleAllocMutex.Lock();
371  size_t pool_size = single_alloc_pool_size;
372  char* pool;
373  if ( size > pool_size ) {
374  pool_size = SINGLE_ALLOC_POOL_SIZE;
375  pool = (char*) malloc(pool_size);
376  if ( !pool ) {
377  sx_SingleAllocMutex.Unlock();
378  throw bad_alloc();
379  }
380  single_alloc_pool = pool;
381  single_alloc_pool_size = pool_size;
382  }
383  else {
384  pool = single_alloc_pool;
385  }
386  single_alloc_pool = pool + size;
387  single_alloc_pool_size = pool_size - size;
388  sx_SingleAllocMutex.Unlock();
389  return pool;
390 }
391 #endif
392 
393 
396 #if defined(_DEBUG) && !defined(NCBI_COMPILER_MSVC)
397 # define ALLOC_FILL_MODE_INIT CObject::eAllocFillPattern
398 # define ALLOC_FILL_MODE_DEFAULT CObject::eAllocFillPattern
399 #else
400 # define ALLOC_FILL_MODE_INIT CObject::eAllocFillZero
401 # define ALLOC_FILL_MODE_DEFAULT CObject::eAllocFillNone
402 #endif
403 #if defined(NCBI_COMPILER_MSVC)
404 # define ALLOC_FILL_BYTE_PATTERN 0xcd
405 #else
406 # define ALLOC_FILL_BYTE_PATTERN 0xaa
407 #endif
408 
410 {
412  const char* env = ::getenv("NCBI_MEMORY_FILL");
413  if ( env && *env ) {
414  bool is_set = true;
415  if ( NStr::CompareNocase(env, "NONE") == 0 )
417  else if ( NStr::CompareNocase(env, "ZERO") == 0 )
419  else if ( NStr::CompareNocase(env, "PATTERN") == 0 )
421  else
422  is_set = false;
423  sm_AllocFillMode_IsSet = is_set;
424  }
426  return mode;
427 }
428 
429 
431 {
432  return sm_AllocFillMode;
433 }
434 
435 
437 {
439 }
440 
441 
442 void CObject::SetAllocFillMode(const string& value)
443 {
445  if ( NStr::CompareNocase(value, "NONE") == 0 )
447  else if ( NStr::CompareNocase(value, "ZERO") == 0 )
449  else if ( NStr::CompareNocase(value, "PATTERN") == 0 )
451  else if ( !sm_AllocFillMode_IsSet )
454 }
455 
456 
457 static inline void sx_FillNewMemory(void* ptr, size_t size)
458 {
460  if ( !mode ) {
462  }
463  if ( mode == CObject::eAllocFillZero ) {
464  memset(ptr, 0, size);
465  }
466  else if ( mode == CObject::eAllocFillPattern ) {
467  memset(ptr, ALLOC_FILL_BYTE_PATTERN, size);
468  }
469 }
470 
471 // CObject local new operator to mark allocation in heap
472 void* CObject::operator new(size_t size)
473 {
474  _ASSERT(size >= sizeof(CObject));
475  size = max(size, sizeof(CObject) + sizeof(TCounter));
476 
477 #ifdef USE_SINGLE_ALLOC
478  void* ptr = single_alloc(size);
479  sx_FillNewMemory(ptr, size);
480  //static_cast<CObject*>(ptr)->m_Counter.Set(0);
481  return ptr;
482 #else
483  void* ptr = ::operator new(size);
484 
485 #if USE_TLS_PTR
486  // just remember pointer in TLS
488 #else// !USE_TLS_PTR
489 #if USE_HEAPOBJ_LIST
490  {{
491  CFastMutexGuard LOCK(sm_ObjectMutex);
492  s_heap_obj->push_front(ptr);
493  }}
494 #else// !USE_HEAPOBJ_LIST
495  sx_FillNewMemory(ptr, size);
496 # if USE_COMPLEX_MASK
497  GetSecondCounter(static_cast<CObject*>(ptr))->Set(eMagicCounterNew);
498 # endif// USE_COMPLEX_MASK
499 #endif// USE_HEAPOBJ_LIST
500  static_cast<CObject*>(ptr)->m_Counter = eMagicCounterNew;
501 #endif// USE_TLS_PTR
502  return ptr;
503 #endif
504 }
505 
506 
507 void CObject::operator delete(void* ptr)
508 {
509  // Can be called either from regular destruction (with counter initialized)
510  // or before CObject constructor is called (counter is not set yet).
511 #if USE_TLS_PTR
512 # ifdef _DEBUG
513  TCount magic = sx_PopLastNewPtr(ptr);
514  if ( !magic ) { // counter already initialized
515  magic = static_cast<CObject*>(ptr)->m_Counter;
516  }
517 # else// !_DEBUG
518  // Just remove saved operator new info.
519  sx_PopLastNewPtr(ptr);
520 # endif// _DEBUG
521 #else// !USE_TLS_PTR
522 # ifdef _DEBUG
523  TCount magic = static_cast<CObject*>(ptr)->m_Counter;
524 # endif// _DEBUG
525 #endif// USE_TLS_PTR
526 
527  // magic can be equal to:
528  // 1. eMagicCounterDeleted when memory is freed after CObject destructor.
529  // 2. eMagicCounterNew when memory is freed before CObject constructor.
530  _ASSERT(magic == eMagicCounterDeleted || magic == eMagicCounterNew);
531  ::operator delete(ptr);
532 }
533 
534 
535 // CObject local new operator to mark allocation in other memory chunk
536 void* CObject::operator new(size_t size, void* place)
537 {
538  _ASSERT(size >= sizeof(CObject));
539  sx_FillNewMemory(place, size);
540  //static_cast<CObject*>(ptr)->m_Counter.Set(0);
541  return place;
542 }
543 
544 // complement placement delete operator -> do nothing
545 void CObject::operator delete(void* _DEBUG_ARG(ptr), void* /*place*/)
546 {
547  // Can be called either from regular destruction (with counter initialized)
548  // or before CObject constructor is called (counter is not set yet).
549 #if !USE_TLS_PTR
550 # ifdef _DEBUG
551  CObject* objectPtr = static_cast<CObject*>(ptr);
552  TCount magic = objectPtr->m_Counter;
553  // magic can be equal to:
554  // 1. eMagicCounterDeleted when memory is freed after CObject destructor.
555  // 2. 0 when memory is freed before CObject constructor.
556  _ASSERT(magic == eMagicCounterDeleted || magic == 0);
557 # endif// _DEBUG
558 #endif// USE_TLS_PTR
559 }
560 
561 
562 // CObject new operator from memory pool
563 void* CObject::operator new(size_t size, CObjectMemoryPool* memory_pool)
564 {
565  _ASSERT(size >= sizeof(CObject));
566  if ( !memory_pool ) {
567  return operator new(size);
568  }
569  void* ptr = memory_pool->Allocate(size);
570  if ( !ptr ) {
571  return operator new(size);
572  }
573 #if USE_TLS_PTR
574  // just remember pointer in TLS
576 #else// !USE_TLS_PTR
577 # if USE_COMPLEX_MASK
578  GetSecondCounter(static_cast<CObject*>(ptr))->Set(eMagicCounterPoolNew);
579 # endif// USE_COMPLEX_MASK
580  static_cast<CObject*>(ptr)->m_Counter = eMagicCounterPoolNew;
581 #endif// USE_TLS_PTR
582  return ptr;
583 }
584 
585 // complement pool delete operator
586 void CObject::operator delete(void* ptr, CObjectMemoryPool* memory_pool)
587 {
588  // Can be called either from regular destruction (with counter initialized)
589  // or before CObject constructor is called (counter is not set yet).
590 #if USE_TLS_PTR
591 # ifdef _DEBUG
592  TCount magic = sx_PopLastNewPtr(ptr);
593  if ( !magic ) { // counter already initialized
594  magic = static_cast<CObject*>(ptr)->m_Counter;
595  }
596 # else// !_DEBUG
597  // Just remove saved operator new info.
598  sx_PopLastNewPtr(ptr);
599 # endif// _DEBUG
600 #else// !USE_TLS_PTR
601 # ifdef _DEBUG
602  TCount magic = static_cast<CObject*>(ptr)->m_Counter;
603 # endif//_DEBUG
604 #endif// USE_TLS_PTR
605 
606  // magic can be equal to:
607  // 1. eMagicCounterPoolDeleted when freed after CObject destructor.
608  // 2. eMagicCounterPoolNew when freed before CObject constructor.
610  magic == eMagicCounterPoolNew);
611  memory_pool->Deallocate(ptr);
612 }
613 
614 
615 // CObject local new operator to mark allocation in heap
616 void* CObject::operator new[](size_t size)
617 {
618 # ifdef NCBI_OS_MSWIN
619  void* ptr = ::operator new(size);
620 # else
621  void* ptr = ::operator new[](size);
622 # endif
623  sx_FillNewMemory(ptr, size);
624  return ptr;
625 }
626 
627 
628 void CObject::operator delete[](void* ptr)
629 {
630 #ifdef NCBI_OS_MSWIN
631  ::operator delete(ptr);
632 #else
633  ::operator delete[](ptr);
634 #endif
635 }
636 
637 
638 #ifdef _DEBUG
639 # define ObjFatal Fatal
640 #else
641 # define ObjFatal Critical
642 #endif
643 
644 // initialization in debug mode
645 inline
647 {
648 #if USE_TLS_PTR
650  switch ( type ) {
651  case eMagicCounterNew:
652  // allocated in heap
654  break;
656  // allocated in memory pool
658  break;
659  default:
660  ERR_POST_X(1, ObjFatal << "CObject::InitCounter: "
661  "Bad s_LastNewType="<<type<<
662  " at "<<StackTrace);
663  // something is broken in TLS data
664  // mark as not in heap
666  break;
667  }
668  }
669  else {
670  // surely not in heap
672  }
673 #else
674  // This code can't use Get(), which may block waiting for an
675  // update that will never happen.
676  // ATTENTION: this code can cause UMR (Uninit Mem Read) -- it's okay here!
677  TCount main_counter = m_Counter;
678  if ( main_counter != eMagicCounterNew &&
679  main_counter != eMagicCounterPoolNew ) {
680  // takes care of statically allocated case
682  }
683  else {
684  bool inStack = false;
685 #if USE_HEAPOBJ_LIST
686  const void* ptr = dynamic_cast<const void*>(this);
687  {{
688  CFastMutexGuard LOCK(sm_ObjectMutex);
689  list<const void*>::iterator i =
690  find( s_heap_obj->begin(), s_heap_obj->end(), ptr);
691  inStack = (i == s_heap_obj->end());
692  if (!inStack) {
693  s_heap_obj->erase(i);
694  }
695  }}
696 #else // USE_HEAPOBJ_LIST
697 # if USE_COMPLEX_MASK
698  inStack = GetSecondCounter(this)->m_Value != main_counter;
699 # endif // USE_COMPLEX_MASK
700  // m_Counter == main_counter -> possibly in heap
701  if ( !inStack ) {
702  char stackObject;
703  const char* stackObjectPtr = &stackObject;
704  const char* objectPtr = reinterpret_cast<const char*>(this);
705 # if defined STACK_GROWS_UP
706  inStack =
707  (objectPtr < stackObjectPtr) &&
708  (objectPtr > stackObjectPtr - STACK_THRESHOLD);
709 # elif defined STACK_GROWS_DOWN
710  inStack =
711  (objectPtr > stackObjectPtr) &&
712  (objectPtr < stackObjectPtr + STACK_THRESHOLD);
713 # else
714  inStack =
715  (objectPtr < stackObjectPtr + STACK_THRESHOLD) &&
716  (objectPtr > stackObjectPtr - STACK_THRESHOLD);
717 # endif
718  }
719 #endif // USE_HEAPOBJ_LIST
720 
721  if ( inStack ) {
722  // surely not in heap
723  m_Counter = eInitCounterInStack;
724  }
725  else if ( main_counter == eMagicCounterNew ) {
726  // allocated in heap
728  }
729  else {
730  // allocated in memory pool
732  }
733  }
734 #endif
735 }
736 
737 
739 {
740  InitCounter();
741 }
742 
743 
744 CObject::CObject(const CObject& /*src*/)
745 {
746  InitCounter();
747 }
748 
749 
751 {
752  TCount count = m_Counter;
753  if ( ObjectStateUnreferenced(count) ) {
754  // reference counter is zero -> ok
755  }
756  else if ( ObjectStateValid(count) ) {
758  // referenced object
759  ERR_POST_X(1, ObjFatal << "CObject::~CObject: "
760  "Referenced CObject may not be deleted"<<StackTrace);
761  }
762  else if ( count == eMagicCounterDeleted ||
763  count == eMagicCounterPoolDeleted ) {
764  // deleted object
765  ERR_POST_X(2, ObjFatal << "CObject::~CObject: "
766  "CObject is already deleted"<<StackTrace);
767  }
768  else {
769  // bad object
770  ERR_POST_X(3, ObjFatal << "CObject::~CObject: "
771  "CObject is corrupted"<<StackTrace);
772  }
773  // mark object as deleted
774  TCount final_magic;
775  if ( ObjectStateIsAllocatedInPool(count) ) {
776  final_magic = eMagicCounterPoolDeleted;
777  }
778  else {
779  final_magic = eMagicCounterDeleted;
780  }
781  m_Counter = final_magic;
782 }
783 
784 
786 {
787  if ( ObjectStateValid(count) ) {
788  // counter overflow
789  NCBI_THROW(CObjectException, eRefOverflow,
790  "CObject::CheckReferenceOverflow: "
791  "CObject's reference counter overflow");
792  }
793  else if ( count == eMagicCounterDeleted ||
794  count == eMagicCounterPoolDeleted ) {
795  // deleted object
797  "CObject::CheckReferenceOverflow: "
798  "CObject is already deleted");
799  }
800  else {
801  // bad object
802  NCBI_THROW(CObjectException, eCorrupted,
803  "CObject::CheckReferenceOverflow: "
804  "CObject is corrupted");
805  }
806 }
807 
808 
810 {
811  TCount count = m_Counter;
812  // Counter could be changed by some other thread,
813  // we should take care of that.
814  if ( (count & eInitCounterInHeap) == eInitCounterInHeap ) {
815  delete this;
816  }
817  else {
820  }
821 }
822 
823 
825 {
826  if ( ObjectStateCanBeDeleted(count) ) {
827  // last reference to heap object -> delete it
828  if ( ObjectStateUnreferenced(count) ) {
829  const_cast<CObject*>(this)->DeleteThis();
830  return;
831  }
832  }
833  else {
834  if ( ObjectStateValid(count) ) {
835  // last reference to non heap object -> do nothing
836  return;
837  }
838  }
839 
840  // Error here
841  // restore original value
842  count = (m_Counter += eCounterStep);
843  // bad object
844  if ( ObjectStateValid(count) ) {
845  ERR_POST_X(4, ObjFatal << "CObject::RemoveLastReference: "
846  "CObject was referenced again"<<StackTrace);
847  }
848  else if ( count == eMagicCounterDeleted ||
849  count == eMagicCounterPoolDeleted ) {
850  ERR_POST_X(5, ObjFatal << "CObject::RemoveLastReference: "
851  "CObject is already deleted"<<StackTrace);
852  }
853  else {
854  ERR_POST_X(6, ObjFatal << "CObject::RemoveLastReference: "
855  "CObject is corrupted"<<StackTrace);
856  }
857 }
858 
859 
861 {
862  TCount count = (m_Counter -= eCounterStep);
863  if ( ObjectStateValid(count) ) {
864  return;
865  }
866  m_Counter += eCounterStep; // undo
867 
868  // error
869  if ( count == eMagicCounterDeleted ||
870  count == eMagicCounterPoolDeleted ) {
871  // deleted object
872  NCBI_THROW(CObjectException, eCorrupted,
873  "CObject::ReleaseReference: "
874  "CObject is already deleted");
875  }
876  else {
877  NCBI_THROW(CObjectException, eCorrupted,
878  "CObject::ReleaseReference: "
879  "CObject is corrupted");
880  }
881 }
882 
883 
885 {
886  TCount count;
887 #if USE_TLS_PTR
888  count = m_Counter;
889  if ( ObjectStateValid(count) ) {
890  if ( ObjectStateCanBeDeleted(count) ) {
891  NCBI_THROW(CObjectException, eHeapState,
892  "CObject::DoNotDeleteThisObject: "
893  "CObject is allocated in heap");
894  }
895  // no-op
896  return;
897  }
898 #else
899  {{
900  CFastMutexGuard LOCK(sm_ObjectMutex);
901  count = m_Counter;
902  if ( ObjectStateValid(count) ) {
903  // valid and unreferenced
904  // reset all 'in heap' flags -> make it non-heap without signature
905  m_Counter -= (count & eStateBitsInHeapMask);
906  return;
907  }
908  }}
909 #endif
910 
911  if ( count == eMagicCounterDeleted ||
912  count == eMagicCounterPoolDeleted ) {
913  // deleted object
914  NCBI_THROW(CObjectException, eCorrupted,
915  "CObject::DoNotDeleteThisObject: "
916  "CObject is already deleted");
917  }
918  else {
919  NCBI_THROW(CObjectException, eCorrupted,
920  "CObject::DoNotDeleteThisObject: "
921  "CObject is corrupted");
922  }
923 }
924 
925 
927 {
928 #ifndef USE_SINGLE_ALLOC
929  TCount count;
930 #if USE_TLS_PTR
931  count = m_Counter;
932  if ( ObjectStateValid(count) ) {
933  if ( !ObjectStateCanBeDeleted(count) ) {
934  NCBI_THROW(CObjectException, eHeapState,
935  "CObject::DoDeleteThisObject: "
936  "CObject is not allocated in heap");
937  }
938  // no-op
939  return;
940  }
941 #else
942  {{
943  CFastMutexGuard LOCK(sm_ObjectMutex);
944  count = m_Counter;
945  // DoDeleteThisObject is not allowed for stack objects
946  static const TCount eCheckBits = eStateBitsValid | eStateBitsHeapSignature;
947  if ( (count & eCheckBits) == eCheckBits ) {
948  if ( !(count & eStateBitsInHeap) ) {
949  // set 'in heap' flag
950  m_Counter += eStateBitsInHeap;
951  }
952  return;
953  }
954  }}
955 #endif
956  if ( ObjectStateValid(count) ) {
957  ERR_POST_X(7, ObjFatal << "CObject::DoDeleteThisObject: "
958  "object was created without heap signature"<<StackTrace);
959  }
960  else if ( count == eMagicCounterDeleted ||
961  count == eMagicCounterPoolDeleted ) {
962  // deleted object
963  NCBI_THROW(CObjectException, eCorrupted,
964  "CObject::DoDeleteThisObject: "
965  "CObject is already deleted");
966  }
967  else {
968  NCBI_THROW(CObjectException, eCorrupted,
969  "CObject::DoDeleteThisObject: "
970  "CObject is corrupted");
971  }
972 #endif
973 }
974 
975 
976 NCBI_PARAM_DECL(bool, NCBI, ABORT_ON_COBJECT_THROW);
977 NCBI_PARAM_DEF_EX(bool, NCBI, ABORT_ON_COBJECT_THROW, false,
978  eParam_NoThread, NCBI_ABORT_ON_COBJECT_THROW);
979 
981 {
983  if ( NCBI_PARAM_TYPE(NCBI, ABORT_ON_COBJECT_THROW)::GetDefault() ) {
984  Abort();
985  }
986 }
987 
988 void CObject::DebugDump(CDebugDumpContext ddc, unsigned int /*depth*/) const
989 {
990  ddc.SetFrame("CObject");
991  ddc.Log("address", dynamic_cast<const CDebugDumpable*>(this), 0);
992 // ddc.Log("memory starts at", dynamic_cast<const void*>(this));
993 // ddc.Log("onHeap", CanBeDeleted());
994 }
995 
996 
997 NCBI_PARAM_DECL(bool, NCBI, ABORT_ON_NULL);
998 NCBI_PARAM_DEF_EX(bool, NCBI, ABORT_ON_NULL, false,
999  eParam_NoThread, NCBI_ABORT_ON_NULL);
1000 typedef NCBI_PARAM_TYPE(NCBI, ABORT_ON_NULL) TAbortOnNull;
1001 
1003 {
1004 #ifdef _DEBUG
1005  ERR_POST(Error << "NULL pointer exception: " << CStackTrace());
1006 #endif
1007  if ( TAbortOnNull::GetDefault() ) {
1008  Abort();
1009  }
1010  NCBI_EXCEPTION_VAR(ex,
1011  CCoreException, eNullPtr, "Attempt to access NULL pointer.");
1012  ex.SetSeverity(eDiag_Critical);
1014 }
1015 
1016 
1018 {
1019 #ifdef _DEBUG
1020  ERR_POST(Error << "NULL pointer exception: " << CStackTrace());
1021 #endif
1022  if ( TAbortOnNull::GetDefault() ) {
1023  Abort();
1024  }
1025  NCBI_EXCEPTION_VAR(ex,
1026  CCoreException, eNullPtr,
1027  string("Attempt to access NULL pointer: ")+type.name());
1028  ex.SetSeverity(eDiag_Critical);
1030 }
1031 
1032 
1033 #ifndef NCBI_OBJECT_LOCKER_INLINE
1034 
1035 static const type_info* sx_MonitorType = 0;
1036 
1038 {
1039 public:
1041  {
1042  DumpLocks(true);
1043  }
1044 
1045  struct SLocks {
1046  SLocks(void) : m_Object(0) {}
1049 
1050  void Dump(void) const
1051  {
1052  unsigned total_locks = 0;
1053  ITERATE ( TLocks, it, m_Locks ) {
1054  ++total_locks;
1055  ERR_POST(Note << "Locked<"<<sx_MonitorType->name()<<">"
1056  "("<<it->first<<","<<m_Object<<")"
1057  " @ " << *it->second);
1058  }
1059  unsigned total_unlocks = 0;
1060  ITERATE ( TUnlocks, it, m_Unlocks ) {
1061  ++total_unlocks;
1062  ERR_POST(Note << "Unlocked<"<<sx_MonitorType->name()<<">"
1063  "("<<it->first<<","<<m_Object<<")"
1064  " @ " << *it->second);
1065  }
1066  if ( total_locks ) {
1067  ERR_POST(Note << "Total locks for "<<m_Object<<": "<<total_locks);
1068  }
1069  if ( total_unlocks ) {
1070  ERR_POST(Note << "Total unlocks for "<<m_Object<<": "<<total_unlocks);
1071  }
1072  }
1073  int LockCount(void) const
1074  {
1075  return int(m_Locks.size() - m_Unlocks.size());
1076  }
1077  void Locked(const CObjectCounterLocker* locker, const CObject* object)
1078  {
1079  _ASSERT(LockCount() >= 0);
1080  if ( !m_Object ) {
1081  m_Object = object;
1082  }
1083  m_Locks.insert(TLocks::value_type(locker, new CStackTrace()));
1084  }
1085  bool Unlocked(const CObjectCounterLocker* locker)
1086  {
1087  _ASSERT(LockCount() > 0);
1088  TLocks::iterator lock = m_Locks.lower_bound(locker);
1089  if ( lock != m_Locks.end() ) {
1090  m_Locks.erase(lock);
1091  }
1092  else {
1094  }
1095  if ( LockCount() <= 0 ) {
1096  m_Locks.clear();
1097  m_Unlocks.clear();
1098  return true;
1099  }
1100  return false;
1101  }
1102 
1106  };
1107 
1108  void DumpLocks(bool clear = false)
1109  {
1110  CFastMutexGuard guard(m_Mutex);
1111  ITERATE ( TLocks, it, m_Locks ) {
1112  it->second.Dump();
1113  }
1114  if ( clear ) {
1115  m_Locks.clear();
1116  }
1117  }
1118  void Locked(const CObjectCounterLocker* locker, const CObject* object)
1119  {
1120  CFastMutexGuard guard(m_Mutex);
1121  m_Locks[object].Locked(locker, object);
1122  }
1123  void Unlocked(const CObjectCounterLocker* locker, const CObject* object)
1124  {
1125  CFastMutexGuard guard(m_Mutex);
1126  if ( m_Locks[object].Unlocked(locker) ) {
1127  m_Locks.erase(object);
1128  }
1129  }
1130 private:
1134 };
1135 
1137 
1138 inline bool MonitoredType(const CObject* object)
1139 {
1140  return sx_MonitorType && *sx_MonitorType == typeid(*object);
1141 }
1142 
1143 void CObjectCounterLocker::Lock(const CObject* object) const
1144 {
1145  object->AddReference();
1146  if ( MonitoredType(object) ) {
1147  sx_LocksMonitor.Get().Locked(this, object);
1148  }
1149 }
1150 
1151 
1152 void CObjectCounterLocker::Relock(const CObject* object) const
1153 {
1154  Lock(object);
1155 }
1156 
1157 
1158 void CObjectCounterLocker::Unlock(const CObject* object) const
1159 {
1160  if ( MonitoredType(object) ) {
1161  sx_LocksMonitor.Get().Unlocked(this, object);
1162  }
1163  object->RemoveReference();
1164 }
1165 
1166 
1168 {
1169  if ( MonitoredType(object) ) {
1170  ERR_POST(Note << "UnlockRelease<"<<typeid(*object).name()<<">"
1171  "("<<this<<", "<<object<<")"
1172  " @ " << StackTrace);
1173  sx_LocksMonitor.Get().Unlocked(this, object);
1174  }
1175  object->ReleaseReference();
1176 }
1177 
1178 
1180  const CObjectCounterLocker& old_locker) const
1181 {
1182  if ( MonitoredType(object) ) {
1183  sx_LocksMonitor.Get().Locked(this, object);
1184  sx_LocksMonitor.Get().Unlocked(&old_locker, object);
1185  }
1186 }
1187 
1188 
1190 {
1191  StopMonitoring();
1192  sx_MonitorType = &type;
1193 }
1194 
1195 
1197 {
1198  if ( sx_MonitorType ) {
1199  ReportLockedObjects(true);
1200  sx_MonitorType = 0;
1201  }
1202 }
1203 
1204 
1206 {
1207  sx_LocksMonitor.Get().DumpLocks(clear);
1208 }
1209 #else
1210 void CObjectCounterLocker::MonitorObjectType(const type_info& )
1211 {
1212 }
1213 
1214 
1216 {
1217 }
1218 
1219 
1221 {
1222 }
1223 #endif
1224 
1225 
1227 {
1228 #ifdef _DEBUG
1229  ERR_FATAL_X(8, "Type "<<type.name()<<" must be derived from CObject"
1230  << StackTrace);
1231 #else
1232  NCBI_THROW_FMT(CCoreException, eInvalidArg,
1233  "Type "<<type.name()<<" must be derived from CObject");
1234 #endif
1235 }
1236 
1237 const char* CObjectException::GetErrCodeString(void) const
1238 {
1239  switch (GetErrCode()) {
1240  case eRefDelete: return "eRefDelete";
1241  case eDeleted: return "eDeleted";
1242  case eCorrupted: return "eCorrupted";
1243  case eRefOverflow: return "eRefOverflow";
1244  case eNoRef: return "eNoRef";
1245  case eRefUnref: return "eRefUnref";
1246  case eHeapState: return "eHeapState";
1247  default: return CException::GetErrCodeString();
1248  }
1249 }
1250 
1251 
1253 
1254 
1256  : m_SelfPtrProxy( new CPtrToObjectProxy(this) )
1257 {
1258 }
1259 
1260 
1262 {
1263  m_SelfPtrProxy->Clear();
1264 }
1265 
1266 
1267 inline
1269 {
1270  CObject::TCount newCount = obj->m_Counter += CObject::eCounterStep;
1271 
1272  if ( CObject::ObjectStateReferencedOnlyOnce(newCount) ) {
1274  return false;
1275  }
1276  return true;
1277 }
1278 
1279 void
1281 {
1282  m_SelfPtrProxy->Clear();
1283  m_SelfPtrProxy.Reset(new CPtrToObjectProxy(const_cast<CWeakObject*>(this)));
1284 }
1285 
1286 
1288 {
1289 }
1290 
1291 
1293  : m_Ptr(NULL), m_WeakPtr(ptr)
1294 {
1295 }
1296 
1297 
1299 {
1300 }
1301 
1302 
1304 {
1305  CFastMutexGuard guard(s_WeakRefMutex);
1306 
1307  m_Ptr = NULL;
1308  m_WeakPtr = NULL;
1309 }
1310 
1311 
1313 {
1314  if ( !m_WeakPtr )
1315  return NULL;
1316 
1317  CFastMutexGuard guard(s_WeakRefMutex);
1318 
1319  // m_Ptr is set to NULL in CWeakObject destructor and always under mutex,
1320  // and always together with m_WeakPtr.
1321  // So if m_WeakPtr here is not NULL then it will be possible to execute
1322  // x_AddWeakReference() without interfering with destructor.
1324  return NULL;
1325  }
1326 
1327  return m_Ptr;
1328 }
1329 
1330 
1332 {
1333 #ifdef _DEBUG
1334  ERR_FATAL_X(8, "Type "<<type.name()<<" must be derived from CWeakObject"
1335  << StackTrace);
1336 #else
1337  NCBI_THROW_FMT(CCoreException, eInvalidArg,
1338  "Type "<<type.name()<<" must be derived from CWeakObject");
1339 #endif
1340 }
1341 
1342 
1343 
1345 
1346 #ifdef USE_DEBUG_NEW
1347 
1348 static bool s_EnvFlag(const char* env_var_name)
1349 {
1350  const char* value = getenv(env_var_name);
1351  return value && (*value == 'Y' || *value == 'y' || *value == '1');
1352 }
1353 
1354 
1355 struct SAllocHeader
1356 {
1357  unsigned magic;
1358  unsigned seq_number;
1359  size_t size;
1360  void* ptr;
1361 };
1362 
1363 
1364 struct SAllocFooter
1365 {
1366  void* ptr;
1367  size_t size;
1368  unsigned seq_number;
1369  unsigned magic;
1370 };
1371 
1372 static const size_t kAllocSizeBefore = 32;
1373 static const size_t kAllocSizeAfter = 32;
1374 
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;
1380 
1381 static const unsigned kAllocMagicHeader = 0x8b9b0b0b;
1382 static const unsigned kAllocMagicFooter = 0x9e8e0e0e;
1383 static const unsigned kFreedMagicHeader = 0x8b0bdead;
1384 static const unsigned kFreedMagicFooter = 0x9e0edead;
1385 
1386 DEFINE_STATIC_FAST_MUTEX(s_alloc_mutex);
1387 static NCBI_NS_NCBI::CAtomicCounter seq_number;
1388 static const size_t kLogSize = 64 * 1024;
1389 struct SAllocLog {
1390  unsigned seq_number;
1391  enum EType {
1392  eEmpty = 0,
1393  eInit,
1394  eNew,
1395  eNewArr,
1396  eDelete,
1397  eDeleteArr
1398  };
1399  char type;
1400  char completed;
1401  size_t size;
1402  void* ptr;
1403 };
1404 static SAllocLog alloc_log[kLogSize];
1405 
1406 
1407 static inline SAllocHeader* get_header(void* ptr)
1408 {
1409  return (SAllocHeader*) ((char*) ptr-kAllocSizeBefore);
1410 }
1411 
1412 
1413 static inline void* get_guard_before(SAllocHeader* header)
1414 {
1415  return (char*) header + sizeof(SAllocHeader);
1416 }
1417 
1418 
1419 static inline size_t get_guard_before_size()
1420 {
1421  return kAllocSizeBefore - sizeof(SAllocHeader);
1422 }
1423 
1424 
1425 static inline size_t get_extra_size(size_t size)
1426 {
1427  return (-size) & 7;
1428 }
1429 
1430 
1431 static inline size_t get_guard_after_size(size_t size)
1432 {
1433  return kAllocSizeAfter - sizeof(SAllocFooter) + get_extra_size(size);
1434 }
1435 
1436 
1437 static inline void* get_ptr(SAllocHeader* header)
1438 {
1439  return (char*) header + kAllocSizeBefore;
1440 }
1441 
1442 
1443 static inline void* get_guard_after(SAllocFooter* footer, size_t size)
1444 {
1445  return (char*)footer-get_guard_after_size(size);
1446 }
1447 
1448 
1449 static inline SAllocFooter* get_footer(SAllocHeader* header, size_t size)
1450 {
1451  return (SAllocFooter*)((char*)get_ptr(header)+size+get_guard_after_size(size));
1452 }
1453 
1454 
1455 static inline size_t get_total_size(size_t size)
1456 {
1457  return size+get_extra_size(size) + (kAllocSizeBefore+kAllocSizeAfter);
1458 }
1459 
1460 
1461 static inline size_t get_all_guards_size(size_t size)
1462 {
1463  return get_total_size(size) - (sizeof(SAllocHeader)+sizeof(SAllocFooter));
1464 }
1465 
1466 
1467 SAllocLog& start_log(unsigned number, SAllocLog::EType type)
1468 {
1469  SAllocLog& slot = alloc_log[number % kLogSize];
1470  slot.type = SAllocLog::eInit;
1471  slot.completed = false;
1472  slot.seq_number = number;
1473  slot.ptr = 0;
1474  slot.size = 0;
1475  slot.type = type;
1476  return slot;
1477 }
1478 
1479 
1480 void memchk(const void* ptr, char byte, size_t size)
1481 {
1482  for ( const char* p = (const char*)ptr; size; ++p, --size ) {
1483  if ( *p != byte ) {
1484  std::abort();
1485  }
1486  }
1487 }
1488 
1489 
1490 void* s_alloc_mem(size_t size, bool array) throw()
1491 {
1492  unsigned number = seq_number.Add(1);
1493  SAllocLog& log =
1494  start_log(number, array? SAllocLog::eNewArr: SAllocLog::eNew);
1495  log.size = size;
1496 
1497  SAllocHeader* header;
1498  {{
1499  NCBI_NS_NCBI::CFastMutexGuard guard(s_alloc_mutex);
1500  header = (SAllocHeader*)std::malloc(get_total_size(size));
1501  }}
1502  if ( !header ) {
1503  log.completed = true;
1504  return 0;
1505  }
1506  SAllocFooter* footer = get_footer(header, size);
1507 
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);
1513 
1514  std::memset(get_guard_before(header),
1515  array? kAllocFillBeforeArray: kAllocFillBeforeOne,
1516  get_guard_before_size());
1517  std::memset(get_guard_after(footer, size),
1518  kAllocFillAfter,
1519  get_guard_after_size(size));
1520  std::memset(get_ptr(header), kAllocFillInside, size);
1521 
1522  log.completed = true;
1523  return get_ptr(header);
1524 }
1525 
1526 
1527 void s_free_mem(void* ptr, bool array)
1528 {
1529  unsigned number = seq_number.Add(1);
1530  SAllocLog& log =
1531  start_log(number, array ? SAllocLog::eDeleteArr: SAllocLog::eDelete);
1532  if ( ptr ) {
1533  log.ptr = ptr;
1534 
1535  SAllocHeader* header = get_header(ptr);
1536  if ( header->magic != kAllocMagicHeader ||
1537  header->seq_number >= number ||
1538  header->ptr != get_ptr(header) ) {
1539  abort();
1540  }
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 ) {
1547  abort();
1548  }
1549 
1550  memchk(get_guard_before(header),
1551  array? kAllocFillBeforeArray: kAllocFillBeforeOne,
1552  get_guard_before_size());
1553  memchk(get_guard_after(footer, size),
1554  kAllocFillAfter,
1555  get_guard_after_size(size));
1556 
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");
1561  if ( !no_clear ) {
1562  std::memset(get_guard_before(header),
1563  kAllocFillFree,
1564  get_all_guards_size(size));
1565  }
1566  static bool no_free = s_EnvFlag("DEBUG_NEW_NO_FREE_ON_DELETE");
1567  if ( !no_free ) {
1568  NCBI_NS_NCBI::CFastMutexGuard guard(s_alloc_mutex);
1569  std::free(header);
1570  }
1571  }
1572  log.completed = true;
1573 }
1574 
1575 
1576 void* operator new(size_t size) throw(std::bad_alloc)
1577 {
1578  void* ret = s_alloc_mem(size, false);
1579  if ( !ret )
1580  throw std::bad_alloc();
1581  return ret;
1582 }
1583 
1584 
1585 void* operator new(size_t size, const std::nothrow_t&) throw()
1586 {
1587  return s_alloc_mem(size, false);
1588 }
1589 
1590 
1591 void* operator new[](size_t size) throw(std::bad_alloc)
1592 {
1593  void* ret = s_alloc_mem(size, true);
1594  if ( !ret )
1595  throw std::bad_alloc();
1596  return ret;
1597 }
1598 
1599 
1600 void* operator new[](size_t size, const std::nothrow_t&) throw()
1601 {
1602  return s_alloc_mem(size, true);
1603 }
1604 
1605 
1606 void operator delete(void* ptr) throw()
1607 {
1608  s_free_mem(ptr, false);
1609 }
1610 
1611 
1612 void operator delete(void* ptr, const std::nothrow_t&) throw()
1613 {
1614  s_free_mem(ptr, false);
1615 }
1616 
1617 
1618 void operator delete[](void* ptr) throw()
1619 {
1620  s_free_mem(ptr, true);
1621 }
1622 
1623 
1624 void operator delete[](void* ptr, const std::nothrow_t&) throw()
1625 {
1626  s_free_mem(ptr, true);
1627 }
1628 
1629 #endif
@ eEmpty
no filtering at all.
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CCoreException –.
Definition: ncbiexpt.hpp:1476
void SetFrame(const string &frame)
Definition: ddumpable.cpp:137
void Log(const string &name, const char *value, CDebugDumpFormatter::EValueType type=CDebugDumpFormatter::eValue, const string &comment=kEmptyStr)
Definition: ddumpable.cpp:151
CFastMutex –.
Definition: ncbimtx.hpp:667
void DumpLocks(bool clear=false)
Definition: ncbiobj.cpp:1108
TLocks m_Locks
Definition: ncbiobj.cpp:1133
void Unlocked(const CObjectCounterLocker *locker, const CObject *object)
Definition: ncbiobj.cpp:1123
void Locked(const CObjectCounterLocker *locker, const CObject *object)
Definition: ncbiobj.cpp:1118
~CLocksMonitor(void)
Definition: ncbiobj.cpp:1040
map< const CObject *, SLocks > TLocks
Definition: ncbiobj.cpp:1131
CFastMutex m_Mutex
Definition: ncbiobj.cpp:1132
CObjectException –.
Definition: ncbiobj.hpp:74
CObject –.
Definition: ncbiobj.hpp:180
CPtrToObjectProxy –.
Definition: ncbiobj.hpp:2400
CSafeStatic<>::
CWeakObject –.
Definition: ncbiobj.hpp:2443
void erase(iterator pos)
Definition: map.hpp:167
void clear()
Definition: map.hpp:169
void clear()
Definition: map.hpp:309
size_type size() const
Definition: map.hpp:288
void erase(iterator pos)
Definition: map.hpp:307
const_iterator lower_bound(const key_type &key) const
Definition: map.hpp:294
const_iterator end() const
Definition: map.hpp:292
iterator insert(const value_type &val)
Definition: map.hpp:305
Definition: set.hpp:45
bool empty() const
Definition: set.hpp:133
static int type
Definition: getdata.c:31
static HENV env
Definition: transaction2.c:38
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define NULL
Definition: ncbistd.hpp:225
TNCBIAtomicValue TValue
Alias TValue for TNCBIAtomicValue.
Definition: ncbicntr.hpp:73
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:278
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
#define ERR_FATAL_X(err_subcode, message)
Definition: ncbidiag.hpp:556
NCBI_XNCBI_EXPORT void Abort(void)
Smart abort function.
Definition: ncbidiag.cpp:8147
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
@ eDiag_Critical
Critical error message.
Definition: ncbidiag.hpp:654
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_EXCEPTION_VAR(name, exception_class, err_code, message)
Create an instance of the exception to be thrown later.
Definition: ncbiexpt.hpp:684
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
#define NCBI_EXCEPTION_THROW(exception_var)
Throw an existing exception object.
Definition: ncbiexpt.hpp:688
virtual void x_InitErrCode(CException::EErrCode err_code)
Helper method for initializing error code.
Definition: ncbiexpt.cpp:567
#define THROWS_NONE
Do not use 'throw' dynamic exception specification for C++11 compilers.
Definition: ncbiexpt.hpp:74
EErrCode
Error types that an application can generate.
Definition: ncbiexpt.hpp:884
TErrCode GetErrCode(void) const
Definition: ncbiexpt.hpp:1493
#define NCBI_THROW_FMT(exception_class, err_code, message)
The same as NCBI_THROW but with message processed as output to ostream.
Definition: ncbiexpt.hpp:719
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
void RemoveLastReference(TCount count) const
Remove the last reference.
Definition: ncbiobj.cpp:824
void TransferLock(const CObject *object, const CObjectCounterLocker &old_locker) const
Definition: ncbiobj.cpp:1179
static const int eCounterStep
Skip over the "in heap" bits.
Definition: ncbiobj.hpp:342
void Clear(void)
Set pointer to NULL from object's destructor.
Definition: ncbiobj.cpp:1303
void CleanWeakRefs(void) const
Method cleaning all CWeakRefs referencing at this moment to the object After calling to this method a...
Definition: ncbiobj.cpp:1280
Uint8 TCount
Alias for value type of counter.
Definition: ncbiobj.hpp:310
static void ReportLockedObjects(bool clear=false)
Print all currently locked objects of monitored type.
Definition: ncbiobj.cpp:1205
virtual void DoDeleteThisObject(void)
Mark this object as allocated in heap – object can be deleted.
Definition: ncbiobj.cpp:926
CObject * m_Ptr
Definition: ncbiobj.hpp:2420
static void StopMonitoring(void)
Stop lock/unlock monitoring.
Definition: ncbiobj.cpp:1196
EAllocFillMode
Control filling of newly allocated memory.
Definition: ncbiobj.hpp:286
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbiobj.cpp:1237
static void SetAllocFillMode(EAllocFillMode mode)
Definition: ncbiobj.cpp:436
CPtrToObjectProxy(CWeakObject *ptr)
Definition: ncbiobj.cpp:1292
static EAllocFillMode GetAllocFillMode(void)
Definition: ncbiobj.cpp:430
void InitCounter(void)
Initialize counter.
Definition: ncbiobj.cpp:646
bool x_AddWeakReference(CObject *obj)
Add reference to the object in "weak" manner.
Definition: ncbiobj.cpp:1268
virtual ~CObject(void)
Destructor.
Definition: ncbiobj.cpp:750
virtual void DoNotDeleteThisObject(void)
Mark this object as not allocated in heap – do not delete this object.
Definition: ncbiobj.cpp:884
void Relock(const CObject *object) const
Definition: ncbiobj.cpp:1152
CWeakObject * m_WeakPtr
Definition: ncbiobj.hpp:2421
void ReleaseReference(void) const
Remove reference without deleting object.
Definition: ncbiobj.cpp:860
static bool ObjectStateReferencedOnlyOnce(TCount count)
Check if object can be referenced only once.
Definition: ncbiobj.hpp:447
static NCBI_XNCBI_EXPORT void ThrowNullPointerException(void)
Define method to throw null pointer exception.
Definition: ncbiobj.cpp:1002
virtual void DebugDump(CDebugDumpContext ddc, unsigned int depth) const
Define method for dumping debug information.
Definition: ncbiobj.cpp:988
virtual ~CWeakObject(void)
Definition: ncbiobj.cpp:1261
static const TCount eCounterBitsCanBeDeleted
Define possible object states.
Definition: ncbiobj.hpp:335
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
void x_InitErrCode(CException::EErrCode err_code) override
Helper method for initializing error code.
Definition: ncbiobj.cpp:980
void UnlockRelease(const CObject *object) const
Definition: ncbiobj.cpp:1167
virtual void DeleteThis(void)
Virtual method "deleting" this object.
Definition: ncbiobj.cpp:809
static bool ObjectStateValid(TCount count)
Check if object state is valid.
Definition: ncbiobj.hpp:426
static bool ObjectStateReferenced(TCount count)
Check if object can be referenced.
Definition: ncbiobj.hpp:433
NCBI_XNCBI_EXPORT void CheckReferenceOverflow(TCount count) const
Report that counter has overflowed.
Definition: ncbiobj.cpp:785
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.
Definition: ncbiobj.hpp:418
CWeakObject(void)
Definition: ncbiobj.cpp:1255
static void ReportIncompatibleType(const type_info &type)
Definition: ncbiobj.cpp:1226
static const TCount eCounterValid
Minimal value for valid objects (reference counter is zero) Must be a single bit value.
Definition: ncbiobj.hpp:352
~CPtrToObjectProxy(void)
Definition: ncbiobj.cpp:1298
static void MonitorObjectType(const type_info &type)
Set monitored object type, e.g.
Definition: ncbiobj.cpp:1189
CRef< CPtrToObjectProxy > m_SelfPtrProxy
Proxy object with pointer to this instance.
Definition: ncbiobj.hpp:2474
friend class CPtrToObjectProxy
Definition: ncbiobj.hpp:2471
CObject * GetLockedObject(void)
Lock the object and return pointer to it.
Definition: ncbiobj.cpp:1312
void Unlock(const CObject *object) const
Definition: ncbiobj.cpp:1158
atomic< Uint8 > TCounter
Counter type is CAtomiCounter.
Definition: ncbiobj.hpp:309
static bool ObjectStateCanBeDeleted(TCount count)
Check if object can be deleted.
Definition: ncbiobj.hpp:410
virtual ~CObjectEx(void)
Definition: ncbiobj.cpp:1287
void Lock(const CObject *object) const
Definition: ncbiobj.cpp:1143
CObject(void)
Constructor.
Definition: ncbiobj.cpp:738
static NCBI_XNCBI_EXPORT void ReportIncompatibleType(const type_info &type)
Report about trying to convert incompatible interface fo CObject.
Definition: ncbiobj.cpp:1331
static const TCount eCounterBitsInPlainHeap
Heap signature was found.
Definition: ncbiobj.hpp:337
TCounter m_Counter
The actual reference counter.
Definition: ncbiobj.hpp:400
static bool ObjectStateUnreferenced(TCount count)
Check if object can be referenced.
Definition: ncbiobj.hpp:440
static const TCount eCounterStateMask
Valid object, and object in heap.
Definition: ncbiobj.hpp:355
@ eAllocFillNone
Definition: ncbiobj.hpp:287
@ eAllocFillZero
Definition: ncbiobj.hpp:288
@ eAllocFillPattern
Definition: ncbiobj.hpp:289
@ eDeleted
Attempt to delete a deleted object.
Definition: ncbiobj.hpp:79
@ eRefDelete
Attempt to delete valid reference.
Definition: ncbiobj.hpp:78
@ eCorrupted
Object corrupted error.
Definition: ncbiobj.hpp:80
@ eRefOverflow
Reference overflow error.
Definition: ncbiobj.hpp:81
@ eHeapState
Attempt to make incorrect in-heap state.
Definition: ncbiobj.hpp:85
@ eRefUnref
Attempt to make a referenced object an unreferenced one.
Definition: ncbiobj.hpp:83
@ eNoRef
Attempt to access an object that is unreferenced.
Definition: ncbiobj.hpp:82
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
Definition: ncbistr.cpp:219
TFastMutexGuard CFastMutexGuard
...and backward compatibility
Definition: ncbimtx.hpp:391
pthread_key_t TTlsKey
Define internal TLS key type.
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
Definition of all error codes used in corelib (xncbi.lib).
where both of them are integers Note
int i
mdb_mode_t mode
Definition: lmdb++.h:38
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
Definition: pointer.h:1227
static void s_Cleanup(void *data)
Static variables safety - create on demand, destroy on application termination.
#define NCBI_CONST_UINT8(v)
Definition: ncbi_std.h:196
Memory pool for fast allocation of memory for localized set of CObjects, e.g.
#define STACK_THRESHOLD
Definition: ncbimtx.cpp:66
Multi-threading – mutexes; rw-locks; semaphore.
#define ObjFatal
Definition: ncbiobj.cpp:639
#define ALLOC_FILL_BYTE_PATTERN
Definition: ncbiobj.cpp:406
static DECLARE_TLS_VAR(void *, s_LastNewPtr)
static CObject::EAllocFillMode sx_InitFillNewMemoryMode(void)
Definition: ncbiobj.cpp:409
static const CObject::TCount eInitCounterInHeap
Initial counter value for in-heap objects.
Definition: ncbiobj.cpp:113
static const CObject::TCount eMagicCounterPoolNew
Magic counter value for objects allocated in memory pool.
Definition: ncbiobj.cpp:151
static void sx_PushLastNewPtrMultiple(void *ptr, CAtomicCounter::TValue type)
Definition: ncbiobj.cpp:276
static TTlsKey sx_GetLastNewPtrMultipleKey(void)
Definition: ncbiobj.cpp:218
static void sx_FillNewMemory(void *ptr, size_t size)
Definition: ncbiobj.cpp:457
bool MonitoredType(const CObject *object)
Definition: ncbiobj.cpp:1138
static CObject::EAllocFillMode sm_AllocFillMode
Definition: ncbiobj.cpp:394
static const CObject::TCount eInitCounterInPool
Initial counter value for objects allocated in memory pool.
Definition: ncbiobj.cpp:110
static CAtomicCounter::TValue sx_PopLastNewPtrMultiple(void *ptr)
Definition: ncbiobj.cpp:288
static const CAtomicCounter::TValue kLastNewTypeMultiple
Definition: ncbiobj.cpp:179
#define ALLOC_FILL_MODE_INIT
Definition: ncbiobj.cpp:397
NCBI_PARAM_DEF_EX(bool, NCBI, ABORT_ON_COBJECT_THROW, false, eParam_NoThread, NCBI_ABORT_ON_COBJECT_THROW)
static CSafeStatic< CLocksMonitor > sx_LocksMonitor
Definition: ncbiobj.cpp:1136
static TLastNewPtrMultiple & sx_GetLastNewPtrMultiple(void)
Definition: ncbiobj.cpp:245
static const CObject::TCount eMagicCounterNew
Magic counter value for object allocated in heap.
Definition: ncbiobj.cpp:145
NCBI_PARAM_DECL(bool, NCBI, ABORT_ON_COBJECT_THROW)
#define ALLOC_FILL_MODE_DEFAULT
Definition: ncbiobj.cpp:398
static const CObject::TCount eMagicCounterPoolDeleted
Magic counter value for deleted object allocated in memory pool.
Definition: ncbiobj.cpp:148
typedef NCBI_PARAM_TYPE(NCBI, ABORT_ON_NULL) TAbortOnNull
static bool sm_AllocFillMode_IsSet
Definition: ncbiobj.cpp:395
static CAtomicCounter::TValue sx_PopLastNewPtr(void *ptr)
Definition: ncbiobj.cpp:322
static const type_info * sx_MonitorType
Definition: ncbiobj.cpp:1035
static const CObject::TCount eMagicCounterDeleted
All magic counter values should have all their state bits off.
Definition: ncbiobj.cpp:142
vector< TLastNewPtrMultipleInfo > TLastNewPtrMultiple
Definition: ncbiobj.cpp:183
static void sx_PushLastNewPtr(void *ptr, CAtomicCounter::TValue type)
Definition: ncbiobj.cpp:309
DEFINE_STATIC_FAST_MUTEX(s_WeakRefMutex)
pair< void *, CAtomicCounter::TValue > TLastNewPtrMultipleInfo
Definition: ncbiobj.cpp:182
static const CObject::TCount eInitCounterNotInHeap
Initial counter value for non-heap objects.
Definition: ncbiobj.cpp:107
static atomic< TTlsKey > s_LastNewPtrMultiple_key
Definition: ncbiobj.cpp:187
static TTlsKey sx_GetLastNewPtrMultipleCurrentKey(void)
Definition: ncbiobj.cpp:190
Portable reference counted smart and weak pointers using CWeakRef, CRef, CObject and CObjectEx.
Multi-threading – classes, functions, and features.
T max(T x_, T y_)
void abort()
Int4 delta(size_t dimension_, const Int4 *score_)
static BOOL number
Definition: pcregrep.c:193
@ eNew
unsigned int DWORD
Definition: sqltypes.h:98
NCBI
Definition: static_set.hpp:72
multimap< const CObjectCounterLocker *, AutoPtr< CStackTrace > > TUnlocks
Definition: ncbiobj.cpp:1048
int LockCount(void) const
Definition: ncbiobj.cpp:1073
void Dump(void) const
Definition: ncbiobj.cpp:1050
multimap< const CObjectCounterLocker *, AutoPtr< CStackTrace > > TLocks
Definition: ncbiobj.cpp:1047
void Locked(const CObjectCounterLocker *locker, const CObject *object)
Definition: ncbiobj.cpp:1077
bool Unlocked(const CObjectCounterLocker *locker)
Definition: ncbiobj.cpp:1085
const CObject * m_Object
Definition: ncbiobj.cpp:1103
static void sx_Cleanup(void *ptr)
Definition: ncbiobj.cpp:196
Definition: type.c:6
const char * name
Definition: type.c:8
#define _ASSERT
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Tue Apr 30 06:42:25 2024 by modify_doxy.py rev. 669887