1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkObjectBase.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkObjectBase.h"
17 #include "vtkDebug.h"
18 #include "vtkDebugLeaks.h"
19 #include "vtkGarbageCollector.h"
20 #include "vtkWeakPointerBase.h"
21
22 #include <cassert>
23 #include <sstream>
24
25 #ifdef VTK_USE_MEMKIND
26 #include <memkind.h>
27 struct memkind* MemkindHandle = nullptr;
28 #endif
29
30 #define vtkBaseDebugMacro(x)
31
32 class vtkObjectBaseToGarbageCollectorFriendship
33 {
34 public:
GiveReference(vtkObjectBase * obj)35 static int GiveReference(vtkObjectBase* obj) { return vtkGarbageCollector::GiveReference(obj); }
TakeReference(vtkObjectBase * obj)36 static int TakeReference(vtkObjectBase* obj) { return vtkGarbageCollector::TakeReference(obj); }
37 };
38
39 class vtkObjectBaseToWeakPointerBaseFriendship
40 {
41 public:
ClearPointer(vtkWeakPointerBase * p)42 static void ClearPointer(vtkWeakPointerBase* p) { p->Object = nullptr; }
43 };
44
45 //------------------------------------------------------------------------------
vtkCustomMalloc(size_t size)46 void* vtkCustomMalloc(size_t size)
47 {
48 #ifdef VTK_USE_MEMKIND
49 if (MemkindHandle == nullptr)
50 {
51 vtkGenericWarningMacro(<< "memkind_malloc() called before memkind initialized.");
52 }
53 else
54 {
55 return memkind_malloc(MemkindHandle, size);
56 }
57 #else
58 (void)size;
59 #endif
60 return nullptr;
61 }
62
63 //------------------------------------------------------------------------------
vtkCustomRealloc(void * p,size_t size)64 void* vtkCustomRealloc(void* p, size_t size)
65 {
66 #ifdef VTK_USE_MEMKIND
67 if (MemkindHandle == nullptr)
68 {
69 vtkGenericWarningMacro(<< "memkind_realloc() called before memkind initialized.");
70 }
71 else
72 {
73 return memkind_realloc(MemkindHandle, p, size);
74 }
75 #else
76 (void)p;
77 (void)size;
78 #endif
79 return nullptr;
80 }
81
82 //------------------------------------------------------------------------------
vtkCustomFree(void * addr)83 void vtkCustomFree(void* addr)
84 {
85 #ifdef VTK_USE_MEMKIND
86 memkind_free(MemkindHandle, addr);
87 #else
88 (void)addr;
89 #endif
90 }
91
92 #if defined(_WIN32) || defined(VTK_USE_MEMKIND)
93 //------------------------------------------------------------------------------
94 // Take control of allocation to avoid dll boundary problems or to use memkind.
operator new(size_t nSize)95 void* vtkObjectBase::operator new(size_t nSize)
96 {
97 #ifdef VTK_USE_MEMKIND
98 return vtkObjectBase::GetCurrentMallocFunction()(nSize);
99 #else
100 return malloc(nSize);
101 #endif
102 }
103
104 //------------------------------------------------------------------------------
operator delete(void * p)105 void vtkObjectBase::operator delete(void* p)
106 {
107 #ifdef VTK_USE_MEMKIND
108 if (static_cast<vtkObjectBase*>(p)->GetIsInMemkind())
109 {
110 vtkCustomFree(p);
111 }
112 else
113 {
114 free(p);
115 }
116 #else
117 free(p);
118 #endif
119 }
120 // take control of ... above
121 #endif
122
123 // ------------------------------------vtkObjectBase----------------------
124 // This operator allows all subclasses of vtkObjectBase to be printed via <<.
125 // It in turn invokes the Print method, which in turn will invoke the
126 // PrintSelf method that all objects should define, if they have anything
127 // interesting to print out.
operator <<(ostream & os,vtkObjectBase & o)128 ostream& operator<<(ostream& os, vtkObjectBase& o)
129 {
130 o.Print(os);
131 return os;
132 }
133
134 //------------------------------------------------------------------------------
135 // Create an object with Debug turned off and modified time initialized
136 // to zero.
vtkObjectBase()137 vtkObjectBase::vtkObjectBase()
138 {
139 this->ReferenceCount = 1;
140 this->WeakPointers = nullptr;
141 #ifdef VTK_DEBUG_LEAKS
142 vtkDebugLeaks::ConstructingObject(this);
143 #endif
144 #ifdef VTK_USE_MEMKIND
145 this->SetIsInMemkind(vtkObjectBase::GetUsingMemkind());
146 #else
147 this->IsInMemkind = false;
148 #endif
149 }
150
151 //------------------------------------------------------------------------------
~vtkObjectBase()152 vtkObjectBase::~vtkObjectBase()
153 {
154 #ifdef VTK_DEBUG_LEAKS
155 vtkDebugLeaks::DestructingObject(this);
156 #endif
157
158 // warn user if reference counting is on and the object is being referenced
159 // by another object
160 if (this->ReferenceCount > 0)
161 {
162 vtkGenericWarningMacro(<< "Trying to delete object with non-zero reference count.");
163 }
164 }
165
166 //------------------------------------------------------------------------------
InitializeObjectBase()167 void vtkObjectBase::InitializeObjectBase()
168 {
169 #ifdef VTK_DEBUG_LEAKS
170 vtkDebugLeaks::ConstructClass(this);
171 #endif // VTK_DEBUG_LEAKS
172 }
173
174 //------------------------------------------------------------------------------
175 #ifdef VTK_WORKAROUND_WINDOWS_MANGLE
176 #undef GetClassName
177 // Define possible mangled names.
GetClassNameA() const178 const char* vtkObjectBase::GetClassNameA() const
179 {
180 return this->GetClassNameInternal();
181 }
GetClassNameW() const182 const char* vtkObjectBase::GetClassNameW() const
183 {
184 return this->GetClassNameInternal();
185 }
186 #endif
GetClassName() const187 const char* vtkObjectBase::GetClassName() const
188 {
189 return this->GetClassNameInternal();
190 }
191
IsTypeOf(const char * name)192 vtkTypeBool vtkObjectBase::IsTypeOf(const char* name)
193 {
194 if (!strcmp("vtkObjectBase", name))
195 {
196 return 1;
197 }
198 return 0;
199 }
200
IsA(const char * name)201 vtkTypeBool vtkObjectBase::IsA(const char* name)
202 {
203 return this->vtkObjectBase::IsTypeOf(name);
204 }
205
GetNumberOfGenerationsFromBaseType(const char * name)206 vtkIdType vtkObjectBase::GetNumberOfGenerationsFromBaseType(const char* name)
207 {
208 if (!strcmp("vtkObjectBase", name))
209 {
210 return 0;
211 }
212 // Return the lowest value for vtkIdType. Because of recursion, the returned
213 // value for derived classes will be this value added to the type distance to
214 // vtkObjectBase. This sum will still be a negative (and, therefore, invalid)
215 // value.
216 return VTK_ID_MIN;
217 }
218
GetNumberOfGenerationsFromBase(const char * name)219 vtkIdType vtkObjectBase::GetNumberOfGenerationsFromBase(const char* name)
220 {
221 return this->vtkObjectBase::GetNumberOfGenerationsFromBaseType(name);
222 }
223
224 // Delete a vtk object. This method should always be used to delete an object
225 // when the new operator was used to create it. Using the C++ delete method
226 // will not work with reference counting.
Delete()227 void vtkObjectBase::Delete()
228 {
229 this->UnRegister(static_cast<vtkObjectBase*>(nullptr));
230 }
231
FastDelete()232 void vtkObjectBase::FastDelete()
233 {
234 // Remove the reference without doing a collection check even if
235 // this object normally participates in garbage collection.
236 this->UnRegisterInternal(nullptr, 0);
237 }
238
Print(ostream & os)239 void vtkObjectBase::Print(ostream& os)
240 {
241 vtkIndent indent;
242
243 this->PrintHeader(os, vtkIndent(0));
244 this->PrintSelf(os, indent.GetNextIndent());
245 this->PrintTrailer(os, vtkIndent(0));
246 }
247
PrintHeader(ostream & os,vtkIndent indent)248 void vtkObjectBase::PrintHeader(ostream& os, vtkIndent indent)
249 {
250 os << indent << this->GetClassName() << " (" << this << ")\n";
251 }
252
253 // Chaining method to print an object's instance variables, as well as
254 // its superclasses.
PrintSelf(ostream & os,vtkIndent indent)255 void vtkObjectBase::PrintSelf(ostream& os, vtkIndent indent)
256 {
257 os << indent << "Reference Count: " << this->ReferenceCount << "\n";
258 }
259
PrintTrailer(ostream & os,vtkIndent indent)260 void vtkObjectBase::PrintTrailer(ostream& os, vtkIndent indent)
261 {
262 os << indent << "\n";
263 }
264
265 // Description:
266 // Sets the reference count (use with care)
SetReferenceCount(int ref)267 void vtkObjectBase::SetReferenceCount(int ref)
268 {
269 this->ReferenceCount = ref;
270 vtkBaseDebugMacro(<< "Reference Count set to " << this->ReferenceCount);
271 }
272
273 //------------------------------------------------------------------------------
Register(vtkObjectBase * o)274 void vtkObjectBase::Register(vtkObjectBase* o)
275 {
276 // Do not participate in garbage collection by default.
277 this->RegisterInternal(o, 0);
278 }
279
280 //------------------------------------------------------------------------------
UnRegister(vtkObjectBase * o)281 void vtkObjectBase::UnRegister(vtkObjectBase* o)
282 {
283 // Do not participate in garbage collection by default.
284 this->UnRegisterInternal(o, 0);
285 }
286
287 //------------------------------------------------------------------------------
RegisterInternal(vtkObjectBase *,vtkTypeBool check)288 void vtkObjectBase::RegisterInternal(vtkObjectBase*, vtkTypeBool check)
289 {
290 // If a reference is available from the garbage collector, use it.
291 // Otherwise create a new reference by incrementing the reference
292 // count.
293 if (!(check && vtkObjectBaseToGarbageCollectorFriendship::TakeReference(this)))
294 {
295 this->ReferenceCount++;
296 }
297 }
298
299 //------------------------------------------------------------------------------
UnRegisterInternal(vtkObjectBase *,vtkTypeBool check)300 void vtkObjectBase::UnRegisterInternal(vtkObjectBase*, vtkTypeBool check)
301 {
302 // If the garbage collector accepts a reference, do not decrement
303 // the count.
304 if (check && this->ReferenceCount > 1 &&
305 vtkObjectBaseToGarbageCollectorFriendship::GiveReference(this))
306 {
307 return;
308 }
309
310 // Decrement the reference count, delete object if count goes to zero.
311 if (--this->ReferenceCount <= 0)
312 {
313 // Clear all weak pointers to the object before deleting it.
314 if (this->WeakPointers)
315 {
316 vtkWeakPointerBase** p = this->WeakPointers;
317 while (*p)
318 {
319 vtkObjectBaseToWeakPointerBaseFriendship::ClearPointer(*p++);
320 }
321 delete[] this->WeakPointers;
322 }
323 #ifdef VTK_DEBUG_LEAKS
324 vtkDebugLeaks::DestructClass(this);
325 #endif
326 delete this;
327 }
328 else if (check)
329 {
330 // The garbage collector did not accept the reference, but the
331 // object still exists and is participating in garbage collection.
332 // This means either that delayed garbage collection is disabled
333 // or the collector has decided it is time to do a check.
334 vtkGarbageCollector::Collect(this);
335 }
336 }
337
338 //------------------------------------------------------------------------------
ReportReferences(vtkGarbageCollector *)339 void vtkObjectBase::ReportReferences(vtkGarbageCollector*)
340 {
341 // vtkObjectBase has no references to report.
342 }
343
344 namespace
345 {
346 #ifdef VTK_HAS_THREADLOCAL
347 #ifdef VTK_USE_MEMKIND
348 thread_local char* MemkindDirectory = nullptr;
349 #endif
350 thread_local bool UsingMemkind = false;
351 thread_local vtkMallocingFunction CurrentMallocFunction = malloc;
352 thread_local vtkReallocingFunction CurrentReallocFunction = realloc;
353 thread_local vtkFreeingFunction CurrentFreeFunction = free;
354 thread_local vtkFreeingFunction AlternateFreeFunction = vtkCustomFree;
355 #else
356 #ifdef VTK_USE_MEMKIND
357 char* MemkindDirectory = nullptr;
358 #endif
359 bool UsingMemkind = false;
360 vtkMallocingFunction CurrentMallocFunction = malloc;
361 vtkReallocingFunction CurrentReallocFunction = realloc;
362 vtkFreeingFunction CurrentFreeFunction = free;
363 vtkFreeingFunction AlternateFreeFunction = vtkCustomFree;
364 #endif
365 }
366
367 //------------------------------------------------------------------------------
SetMemkindDirectory(const char * directoryname)368 void vtkObjectBase::SetMemkindDirectory(const char* directoryname)
369 {
370 #ifndef VTK_HAS_THREADLOCAL
371 vtkGenericWarningMacro(<< "Warning, memkind features are not thread safe on this platform.");
372 #endif
373 #ifdef VTK_USE_MEMKIND
374 if (MemkindDirectory == nullptr && MemkindHandle == nullptr)
375 {
376 MemkindDirectory = strdup(directoryname);
377 int err = 0;
378 if (!strncmp(directoryname, "ALLOCATOR_ONLY", 14))
379 {
380 // This gives us memkind's managed allocator but without extended memory.
381 // It is useful for comparison and has performance benefits from page fault avoidance.
382 MemkindHandle = MEMKIND_DEFAULT;
383 }
384 else
385 {
386 if (!strncmp(directoryname, "DAX_KMEM", 8))
387 {
388 #if MEMKIND_VERSION_MINOR > 9
389 MemkindHandle = MEMKIND_DAX_KMEM;
390 #else
391 vtkGenericWarningMacro(<< "Warning, DAX_KMEM requires memkind >= 1.10");
392 MemkindHandle = MEMKIND_DEFAULT;
393 #endif
394 }
395 else
396 {
397 err = memkind_create_pmem(MemkindDirectory, 0, &MemkindHandle);
398 }
399 }
400 if (err)
401 {
402 perror("memkind_create_pmem()");
403 free(MemkindDirectory);
404 MemkindDirectory = nullptr;
405 }
406 }
407 else
408 {
409 vtkGenericWarningMacro(<< "Warning, can only initialize memkind once.");
410 }
411 #else
412 (void)directoryname;
413 #endif
414 }
415
416 //------------------------------------------------------------------------------
GetUsingMemkind()417 bool vtkObjectBase::GetUsingMemkind()
418 {
419 return UsingMemkind;
420 }
421
422 //------------------------------------------------------------------------------
SetUsingMemkind(bool b)423 void vtkObjectBase::SetUsingMemkind(bool b)
424 {
425 #ifdef VTK_USE_MEMKIND
426 UsingMemkind = b;
427 if (b)
428 {
429 CurrentMallocFunction = vtkCustomMalloc;
430 CurrentReallocFunction = vtkCustomRealloc;
431 CurrentFreeFunction = vtkCustomFree;
432 }
433 else
434 {
435 CurrentMallocFunction = malloc;
436 CurrentReallocFunction = realloc;
437 CurrentFreeFunction = free;
438 }
439 #else
440 // no harm in the above but avoid the cycles if we can
441 (void)b;
442 assert(!b);
443 #endif
444 }
445
446 //------------------------------------------------------------------------------
GetCurrentMallocFunction()447 vtkMallocingFunction vtkObjectBase::GetCurrentMallocFunction()
448 {
449 return CurrentMallocFunction;
450 }
451 //------------------------------------------------------------------------------
GetCurrentReallocFunction()452 vtkReallocingFunction vtkObjectBase::GetCurrentReallocFunction()
453 {
454 return CurrentReallocFunction;
455 }
456 //------------------------------------------------------------------------------
GetCurrentFreeFunction()457 vtkFreeingFunction vtkObjectBase::GetCurrentFreeFunction()
458 {
459 return CurrentFreeFunction;
460 }
461 //------------------------------------------------------------------------------
GetAlternateFreeFunction()462 vtkFreeingFunction vtkObjectBase::GetAlternateFreeFunction()
463 {
464 return AlternateFreeFunction;
465 }
466
467 //------------------------------------------------------------------------------
GetIsInMemkind() const468 bool vtkObjectBase::GetIsInMemkind() const
469 {
470 return this->IsInMemkind;
471 }
472
473 //------------------------------------------------------------------------------
SetIsInMemkind(bool v)474 void vtkObjectBase::SetIsInMemkind(bool v)
475 {
476 #ifdef VTK_USE_MEMKIND
477 this->IsInMemkind = v;
478 #else
479 (void)v;
480 assert(!v);
481 #endif
482 }
483
484 //------------------------------------------------------------------------------
vtkMemkindRAII(bool newValue)485 vtkObjectBase::vtkMemkindRAII::vtkMemkindRAII(bool newValue)
486 {
487 this->Save(newValue);
488 }
489
490 //------------------------------------------------------------------------------
~vtkMemkindRAII()491 vtkObjectBase::vtkMemkindRAII::~vtkMemkindRAII()
492 {
493 this->Restore();
494 }
495
496 //------------------------------------------------------------------------------
Save(bool newValue)497 void vtkObjectBase::vtkMemkindRAII::Save(bool newValue)
498 {
499 #ifdef VTK_USE_MEMKIND
500 this->OriginalValue = vtkObjectBase::GetUsingMemkind();
501 vtkObjectBase::SetUsingMemkind(newValue);
502 #else
503 (void)newValue;
504 #endif
505 }
506
507 //------------------------------------------------------------------------------
Restore()508 void vtkObjectBase::vtkMemkindRAII::Restore()
509 {
510 #ifdef VTK_USE_MEMKIND
511 vtkObjectBase::SetUsingMemkind(this->OriginalValue);
512 #endif
513 }
514