1 /* 2 Copyright (c) 2005-2020 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_tbbmalloc_internal_H 18 #define __TBB_tbbmalloc_internal_H 19 20 #include "TypeDefinitions.h" /* Also includes customization layer Customize.h */ 21 22 #if USE_PTHREAD 23 // Some pthreads documentation says that <pthreads.h> must be first header. 24 #include <pthread.h> 25 typedef pthread_key_t tls_key_t; 26 #elif USE_WINTHREAD 27 #include <windows.h> 28 typedef DWORD tls_key_t; 29 #else 30 #error Must define USE_PTHREAD or USE_WINTHREAD 31 #endif 32 33 #include <atomic> 34 35 // TODO: *BSD also has it 36 #define BACKEND_HAS_MREMAP __linux__ 37 #define CHECK_ALLOCATION_RANGE MALLOC_DEBUG || MALLOC_ZONE_OVERLOAD_ENABLED || MALLOC_UNIXLIKE_OVERLOAD_ENABLED 38 39 #include "oneapi/tbb/detail/_config.h" // for __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 40 #include "oneapi/tbb/detail/_template_helpers.h" 41 #if __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 42 #define _EXCEPTION_PTR_H /* prevents exception_ptr.h inclusion */ 43 #define _GLIBCXX_NESTED_EXCEPTION_H /* prevents nested_exception.h inclusion */ 44 #endif 45 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <limits.h> // for CHAR_BIT 49 #include <string.h> // for memset 50 #if MALLOC_CHECK_RECURSION 51 #include <new> /* for placement new */ 52 #endif 53 #include "oneapi/tbb/scalable_allocator.h" 54 #include "tbbmalloc_internal_api.h" 55 56 /********* Various compile-time options **************/ 57 58 #if !__TBB_DEFINE_MIC && __TBB_MIC_NATIVE 59 #error Intel(R) Many Integrated Core Compiler does not define __MIC__ anymore. 60 #endif 61 62 #define MALLOC_TRACE 0 63 64 #if MALLOC_TRACE 65 #define TRACEF(x) printf x 66 #else 67 #define TRACEF(x) ((void)0) 68 #endif /* MALLOC_TRACE */ 69 70 #define ASSERT_TEXT NULL 71 72 #define COLLECT_STATISTICS ( MALLOC_DEBUG && MALLOCENV_COLLECT_STATISTICS ) 73 #ifndef USE_INTERNAL_TID 74 #define USE_INTERNAL_TID COLLECT_STATISTICS || MALLOC_TRACE 75 #endif 76 77 #include "Statistics.h" 78 79 // call yield for whitebox testing, skip in real library 80 #ifndef WhiteboxTestingYield 81 #define WhiteboxTestingYield() ((void)0) 82 #endif 83 84 85 /********* End compile-time options **************/ 86 87 namespace rml { 88 89 namespace internal { 90 91 #if __TBB_MALLOC_LOCACHE_STAT 92 extern intptr_t mallocCalls, cacheHits; 93 extern intptr_t memAllocKB, memHitKB; 94 #endif 95 96 //! Utility template function to prevent "unused" warnings by various compilers. 97 template<typename T> 98 void suppress_unused_warning( const T& ) {} 99 100 /********** Various global default constants ********/ 101 102 /* 103 * Default huge page size 104 */ 105 static const size_t HUGE_PAGE_SIZE = 2 * 1024 * 1024; 106 107 /********** End of global default constatns *********/ 108 109 /********** Various numeric parameters controlling allocations ********/ 110 111 /* 112 * slabSize - the size of a block for allocation of small objects, 113 * it must be larger than maxSegregatedObjectSize. 114 */ 115 const uintptr_t slabSize = 16*1024; 116 117 /* 118 * Large blocks cache cleanup frequency. 119 * It should be power of 2 for the fast checking. 120 */ 121 const unsigned cacheCleanupFreq = 256; 122 123 /* 124 * Alignment of large (>= minLargeObjectSize) objects. 125 */ 126 const size_t largeObjectAlignment = estimatedCacheLineSize; 127 128 /* 129 * This number of bins in the TLS that leads to blocks that we can allocate in. 130 */ 131 const uint32_t numBlockBinLimit = 31; 132 133 /********** End of numeric parameters controlling allocations *********/ 134 135 class BlockI; 136 class Block; 137 struct LargeMemoryBlock; 138 struct ExtMemoryPool; 139 struct MemRegion; 140 class FreeBlock; 141 class TLSData; 142 class Backend; 143 class MemoryPool; 144 struct CacheBinOperation; 145 extern const uint32_t minLargeObjectSize; 146 147 enum DecreaseOrIncrease { 148 decrease, increase 149 }; 150 151 class TLSKey { 152 tls_key_t TLS_pointer_key; 153 public: 154 bool init(); 155 bool destroy(); 156 TLSData* getThreadMallocTLS() const; 157 void setThreadMallocTLS( TLSData * newvalue ); 158 TLSData* createTLS(MemoryPool *memPool, Backend *backend); 159 }; 160 161 template<typename Arg, typename Compare> 162 inline void AtomicUpdate(std::atomic<Arg>& location, Arg newVal, const Compare &cmp) 163 { 164 static_assert(sizeof(Arg) == sizeof(intptr_t), "Type of argument must match AtomicCompareExchange type."); 165 Arg old = location.load(std::memory_order_acquire); 166 for (; cmp(old, newVal); ) { 167 if (location.compare_exchange_strong(old, newVal)) 168 break; 169 // TODO: do we need backoff after unsuccessful CAS? 170 //old = val; 171 } 172 } 173 174 // TODO: make BitMaskBasic more general 175 // TODO: check that BitMaskBasic is not used for synchronization 176 // (currently, it fits BitMaskMin well, but not as suitable for BitMaskMax) 177 template<unsigned NUM> 178 class BitMaskBasic { 179 static const unsigned SZ = (NUM-1)/(CHAR_BIT*sizeof(uintptr_t))+1; 180 static const unsigned WORD_LEN = CHAR_BIT*sizeof(uintptr_t); 181 182 std::atomic<uintptr_t> mask[SZ]; 183 184 protected: 185 void set(size_t idx, bool val) { 186 MALLOC_ASSERT(idx<NUM, ASSERT_TEXT); 187 188 size_t i = idx / WORD_LEN; 189 int pos = WORD_LEN - idx % WORD_LEN - 1; 190 if (val) { 191 mask[i].fetch_or(1ULL << pos); 192 } else { 193 mask[i].fetch_and(~(1ULL << pos)); 194 } 195 } 196 int getMinTrue(unsigned startIdx) const { 197 unsigned idx = startIdx / WORD_LEN; 198 int pos; 199 200 if (startIdx % WORD_LEN) { 201 // only interested in part of a word, clear bits before startIdx 202 pos = WORD_LEN - startIdx % WORD_LEN; 203 uintptr_t actualMask = mask[idx].load(std::memory_order_relaxed) & (((uintptr_t)1<<pos) - 1); 204 idx++; 205 if (-1 != (pos = BitScanRev(actualMask))) 206 return idx*WORD_LEN - pos - 1; 207 } 208 209 while (idx<SZ) 210 if (-1 != (pos = BitScanRev(mask[idx++].load(std::memory_order_relaxed)))) 211 return idx*WORD_LEN - pos - 1; 212 return -1; 213 } 214 public: 215 void reset() { for (unsigned i=0; i<SZ; i++) mask[i].store(0, std::memory_order_relaxed); } 216 }; 217 218 template<unsigned NUM> 219 class BitMaskMin : public BitMaskBasic<NUM> { 220 public: 221 void set(size_t idx, bool val) { BitMaskBasic<NUM>::set(idx, val); } 222 int getMinTrue(unsigned startIdx) const { 223 return BitMaskBasic<NUM>::getMinTrue(startIdx); 224 } 225 }; 226 227 template<unsigned NUM> 228 class BitMaskMax : public BitMaskBasic<NUM> { 229 public: 230 void set(size_t idx, bool val) { 231 BitMaskBasic<NUM>::set(NUM - 1 - idx, val); 232 } 233 int getMaxTrue(unsigned startIdx) const { 234 int p = BitMaskBasic<NUM>::getMinTrue(NUM-startIdx-1); 235 return -1==p? -1 : (int)NUM - 1 - p; 236 } 237 }; 238 239 240 // The part of thread-specific data that can be modified by other threads. 241 // Such modifications must be protected by AllLocalCaches::listLock. 242 struct TLSRemote { 243 TLSRemote *next, 244 *prev; 245 }; 246 247 // The list of all thread-local data; supporting cleanup of thread caches 248 class AllLocalCaches { 249 TLSRemote *head; 250 MallocMutex listLock; // protects operations in the list 251 public: 252 void registerThread(TLSRemote *tls); 253 void unregisterThread(TLSRemote *tls); 254 bool cleanup(bool cleanOnlyUnused); 255 void markUnused(); 256 void reset() { head = NULL; } 257 }; 258 259 class LifoList { 260 public: 261 inline LifoList(); 262 inline void push(Block *block); 263 inline Block *pop(); 264 inline Block *grab(); 265 266 private: 267 Block *top; 268 MallocMutex lock; 269 }; 270 271 /* 272 * When a block that is not completely free is returned for reuse by other threads 273 * this is where the block goes. 274 * 275 * LifoList assumes zero initialization; so below its constructors are omitted, 276 * to avoid linking with C++ libraries on Linux. 277 */ 278 279 class OrphanedBlocks { 280 LifoList bins[numBlockBinLimit]; 281 public: 282 Block *get(TLSData *tls, unsigned int size); 283 void put(intptr_t binTag, Block *block); 284 void reset(); 285 bool cleanup(Backend* backend); 286 }; 287 288 /* Large objects entities */ 289 #include "large_objects.h" 290 291 // select index size for BackRefMaster based on word size: default is uint32_t, 292 // uint16_t for 32-bit platforms 293 template<bool> 294 struct MasterIndexSelect { 295 typedef uint32_t master_type; 296 }; 297 298 template<> 299 struct MasterIndexSelect<false> { 300 typedef uint16_t master_type; 301 }; 302 303 class BackRefIdx { // composite index to backreference array 304 public: 305 typedef MasterIndexSelect<4 < sizeof(uintptr_t)>::master_type master_t; 306 private: 307 static const master_t invalid = ~master_t(0); 308 master_t master; // index in BackRefMaster 309 uint16_t largeObj:1; // is this object "large"? 310 uint16_t offset :15; // offset from beginning of BackRefBlock 311 public: 312 BackRefIdx() : master(invalid), largeObj(0), offset(0) {} 313 bool isInvalid() const { return master == invalid; } 314 bool isLargeObject() const { return largeObj; } 315 master_t getMaster() const { return master; } 316 uint16_t getOffset() const { return offset; } 317 318 // only newBackRef can modify BackRefIdx 319 static BackRefIdx newBackRef(bool largeObj); 320 }; 321 322 // Block header is used during block coalescing 323 // and must be preserved in used blocks. 324 class BlockI { 325 intptr_t blockState[2]; 326 }; 327 328 struct LargeMemoryBlock : public BlockI { 329 MemoryPool *pool; // owner pool 330 LargeMemoryBlock *next, // ptrs in list of cached blocks 331 *prev, 332 // 2-linked list of pool's large objects 333 // Used to destroy backrefs on pool destroy (backrefs are global) 334 // and for object releasing during pool reset. 335 *gPrev, 336 *gNext; 337 uintptr_t age; // age of block while in cache 338 size_t objectSize; // the size requested by a client 339 size_t unalignedSize; // the size requested from backend 340 BackRefIdx backRefIdx; // cached here, used copy is in LargeObjectHdr 341 }; 342 343 // Classes and methods for backend.cpp 344 #include "backend.h" 345 346 // An TBB allocator mode that can be controlled by user 347 // via API/environment variable. Must be placed in zero-initialized memory. 348 // External synchronization assumed. 349 // TODO: TBB_VERSION support 350 class AllocControlledMode { 351 intptr_t val; 352 bool setDone; 353 354 public: 355 intptr_t get() const { 356 MALLOC_ASSERT(setDone, ASSERT_TEXT); 357 return val; 358 } 359 360 // Note: set() can be called before init() 361 void set(intptr_t newVal) { 362 val = newVal; 363 setDone = true; 364 } 365 366 bool ready() const { 367 return setDone; 368 } 369 370 // envName - environment variable to get controlled mode 371 void initReadEnv(const char *envName, intptr_t defaultVal) { 372 if (!setDone) { 373 // unreferenced formal parameter warning 374 tbb::detail::suppress_unused_warning(envName); 375 #if !__TBB_WIN8UI_SUPPORT 376 // TODO: use strtol to get the actual value of the envirable 377 const char *envVal = getenv(envName); 378 if (envVal && !strcmp(envVal, "1")) 379 val = 1; 380 else 381 #endif 382 val = defaultVal; 383 setDone = true; 384 } 385 } 386 }; 387 388 // Page type to be used inside MapMemory. 389 // Regular (4KB aligned), Huge and Transparent Huge Pages (2MB aligned). 390 enum PageType { 391 REGULAR = 0, 392 PREALLOCATED_HUGE_PAGE, 393 TRANSPARENT_HUGE_PAGE 394 }; 395 396 // init() and printStatus() is called only under global initialization lock. 397 // Race is possible between registerAllocation() and registerReleasing(), 398 // harm is that up to single huge page releasing is missed (because failure 399 // to get huge page is registered only 1st time), that is negligible. 400 // setMode is also can be called concurrently. 401 // Object must reside in zero-initialized memory 402 // TODO: can we check for huge page presence during every 10th mmap() call 403 // in case huge page is released by another process? 404 class HugePagesStatus { 405 private: 406 AllocControlledMode requestedMode; // changed only by user 407 // to keep enabled and requestedMode consistent 408 MallocMutex setModeLock; 409 size_t pageSize; 410 std::atomic<intptr_t> needActualStatusPrint; 411 412 static void doPrintStatus(bool state, const char *stateName) { 413 // Under macOS* fprintf/snprintf acquires an internal lock, so when 414 // 1st allocation is done under the lock, we got a deadlock. 415 // Do not use fprintf etc during initialization. 416 fputs("TBBmalloc: huge pages\t", stderr); 417 if (!state) 418 fputs("not ", stderr); 419 fputs(stateName, stderr); 420 fputs("\n", stderr); 421 } 422 423 void parseSystemMemInfo() { 424 bool hpAvailable = false; 425 bool thpAvailable = false; 426 unsigned long long hugePageSize = 0; 427 428 #if __linux__ 429 // Check huge pages existence 430 unsigned long long meminfoHugePagesTotal = 0; 431 432 parseFileItem meminfoItems[] = { 433 // Parse system huge page size 434 { "Hugepagesize: %llu kB", hugePageSize }, 435 // Check if there are preallocated huge pages on the system 436 // https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt 437 { "HugePages_Total: %llu", meminfoHugePagesTotal } }; 438 439 parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", meminfoItems); 440 441 // Double check another system information regarding preallocated 442 // huge pages if there are no information in /proc/meminfo 443 unsigned long long vmHugePagesTotal = 0; 444 445 parseFileItem vmItem[] = { { "%llu", vmHugePagesTotal } }; 446 447 // We parse a counter number, it can't be huge 448 parseFile</*BUFF_SIZE=*/100>("/proc/sys/vm/nr_hugepages", vmItem); 449 450 if (meminfoHugePagesTotal > 0 || vmHugePagesTotal > 0) { 451 MALLOC_ASSERT(hugePageSize != 0, "Huge Page size can't be zero if we found preallocated."); 452 453 // Any non zero value clearly states that there are preallocated 454 // huge pages on the system 455 hpAvailable = true; 456 } 457 458 // Check if there is transparent huge pages support on the system 459 unsigned long long thpPresent = 'n'; 460 parseFileItem thpItem[] = { { "[alwa%cs] madvise never\n", thpPresent } }; 461 parseFile</*BUFF_SIZE=*/100>("/sys/kernel/mm/transparent_hugepage/enabled", thpItem); 462 463 if (thpPresent == 'y') { 464 MALLOC_ASSERT(hugePageSize != 0, "Huge Page size can't be zero if we found thp existence."); 465 thpAvailable = true; 466 } 467 #endif 468 MALLOC_ASSERT(!pageSize, "Huge page size can't be set twice. Double initialization."); 469 470 // Initialize object variables 471 pageSize = hugePageSize * 1024; // was read in KB from meminfo 472 isHPAvailable = hpAvailable; 473 isTHPAvailable = thpAvailable; 474 } 475 476 public: 477 478 // System information 479 bool isHPAvailable; 480 bool isTHPAvailable; 481 482 // User defined value 483 bool isEnabled; 484 485 void init() { 486 parseSystemMemInfo(); 487 MallocMutex::scoped_lock lock(setModeLock); 488 requestedMode.initReadEnv("TBB_MALLOC_USE_HUGE_PAGES", 0); 489 isEnabled = (isHPAvailable || isTHPAvailable) && requestedMode.get(); 490 } 491 492 // Could be set from user code at any place. 493 // If we didn't call init() at this place, isEnabled will be false 494 void setMode(intptr_t newVal) { 495 MallocMutex::scoped_lock lock(setModeLock); 496 requestedMode.set(newVal); 497 isEnabled = (isHPAvailable || isTHPAvailable) && newVal; 498 } 499 500 bool isRequested() const { 501 return requestedMode.ready() ? requestedMode.get() : false; 502 } 503 504 void reset() { 505 needActualStatusPrint.store(0, std::memory_order_relaxed); 506 pageSize = 0; 507 isEnabled = isHPAvailable = isTHPAvailable = false; 508 } 509 510 // If memory mapping size is a multiple of huge page size, some OS kernels 511 // can use huge pages transparently. Use this when huge pages are requested. 512 size_t getGranularity() const { 513 if (requestedMode.ready()) 514 return requestedMode.get() ? pageSize : 0; 515 else 516 return HUGE_PAGE_SIZE; // the mode is not yet known; assume typical 2MB huge pages 517 } 518 519 void printStatus() { 520 doPrintStatus(requestedMode.get(), "requested"); 521 if (requestedMode.get()) { // report actual status iff requested 522 if (pageSize) 523 needActualStatusPrint.store(1, std::memory_order_release); 524 else 525 doPrintStatus(/*state=*/false, "available"); 526 } 527 } 528 }; 529 530 class AllLargeBlocksList { 531 MallocMutex largeObjLock; 532 LargeMemoryBlock *loHead; 533 public: 534 void add(LargeMemoryBlock *lmb); 535 void remove(LargeMemoryBlock *lmb); 536 template<bool poolDestroy> void releaseAll(Backend *backend); 537 }; 538 539 struct ExtMemoryPool { 540 Backend backend; 541 LargeObjectCache loc; 542 AllLocalCaches allLocalCaches; 543 OrphanedBlocks orphanedBlocks; 544 545 intptr_t poolId; 546 // To find all large objects. Used during user pool destruction, 547 // to release all backreferences in large blocks (slab blocks do not have them). 548 AllLargeBlocksList lmbList; 549 // Callbacks to be used instead of MapMemory/UnmapMemory. 550 rawAllocType rawAlloc; 551 rawFreeType rawFree; 552 size_t granularity; 553 bool keepAllMemory, 554 delayRegsReleasing, 555 // TODO: implements fixedPool with calling rawFree on destruction 556 fixedPool; 557 TLSKey tlsPointerKey; // per-pool TLS key 558 559 bool init(intptr_t poolId, rawAllocType rawAlloc, rawFreeType rawFree, 560 size_t granularity, bool keepAllMemory, bool fixedPool); 561 bool initTLS(); 562 563 // i.e., not system default pool for scalable_malloc/scalable_free 564 bool userPool() const { return rawAlloc; } 565 566 // true if something has been released 567 bool softCachesCleanup(); 568 bool releaseAllLocalCaches(); 569 bool hardCachesCleanup(); 570 void *remap(void *ptr, size_t oldSize, size_t newSize, size_t alignment); 571 bool reset() { 572 loc.reset(); 573 allLocalCaches.reset(); 574 orphanedBlocks.reset(); 575 bool ret = tlsPointerKey.destroy(); 576 backend.reset(); 577 return ret; 578 } 579 bool destroy() { 580 MALLOC_ASSERT(isPoolValid(), 581 "Possible double pool_destroy or heap corruption"); 582 if (!userPool()) { 583 loc.reset(); 584 allLocalCaches.reset(); 585 } 586 // pthread_key_dtors must be disabled before memory unmapping 587 // TODO: race-free solution 588 bool ret = tlsPointerKey.destroy(); 589 if (rawFree || !userPool()) 590 ret &= backend.destroy(); 591 // pool is not valid after this point 592 granularity = 0; 593 return ret; 594 } 595 void delayRegionsReleasing(bool mode) { delayRegsReleasing = mode; } 596 inline bool regionsAreReleaseable() const; 597 598 LargeMemoryBlock *mallocLargeObject(MemoryPool *pool, size_t allocationSize); 599 void freeLargeObject(LargeMemoryBlock *lmb); 600 void freeLargeObjectList(LargeMemoryBlock *head); 601 // use granulatity as marker for pool validity 602 bool isPoolValid() const { return granularity; } 603 }; 604 605 inline bool Backend::inUserPool() const { return extMemPool->userPool(); } 606 607 struct LargeObjectHdr { 608 LargeMemoryBlock *memoryBlock; 609 /* Backreference points to LargeObjectHdr. 610 Duplicated in LargeMemoryBlock to reuse in subsequent allocations. */ 611 BackRefIdx backRefIdx; 612 }; 613 614 struct FreeObject { 615 FreeObject *next; 616 }; 617 618 619 /******* A helper class to support overriding malloc with scalable_malloc *******/ 620 #if MALLOC_CHECK_RECURSION 621 622 class RecursiveMallocCallProtector { 623 // pointer to an automatic data of holding thread 624 static void *autoObjPtr; 625 static MallocMutex rmc_mutex; 626 static pthread_t owner_thread; 627 /* Under FreeBSD 8.0 1st call to any pthread function including pthread_self 628 leads to pthread initialization, that causes malloc calls. As 1st usage of 629 RecursiveMallocCallProtector can be before pthread initialized, pthread calls 630 can't be used in 1st instance of RecursiveMallocCallProtector. 631 RecursiveMallocCallProtector is used 1st time in checkInitialization(), 632 so there is a guarantee that on 2nd usage pthread is initialized. 633 No such situation observed with other supported OSes. 634 */ 635 #if __FreeBSD__ 636 static bool canUsePthread; 637 #else 638 static const bool canUsePthread = true; 639 #endif 640 /* 641 The variable modified in checkInitialization, 642 so can be read without memory barriers. 643 */ 644 static bool mallocRecursionDetected; 645 646 MallocMutex::scoped_lock* lock_acquired; 647 char scoped_lock_space[sizeof(MallocMutex::scoped_lock)+1]; 648 649 static uintptr_t absDiffPtr(void *x, void *y) { 650 uintptr_t xi = (uintptr_t)x, yi = (uintptr_t)y; 651 return xi > yi ? xi - yi : yi - xi; 652 } 653 public: 654 655 RecursiveMallocCallProtector() : lock_acquired(NULL) { 656 lock_acquired = new (scoped_lock_space) MallocMutex::scoped_lock( rmc_mutex ); 657 if (canUsePthread) 658 owner_thread = pthread_self(); 659 autoObjPtr = &scoped_lock_space; 660 } 661 ~RecursiveMallocCallProtector() { 662 if (lock_acquired) { 663 autoObjPtr = NULL; 664 lock_acquired->~scoped_lock(); 665 } 666 } 667 static bool sameThreadActive() { 668 if (!autoObjPtr) // fast path 669 return false; 670 // Some thread has an active recursive call protector; check if the current one. 671 // Exact pthread_self based test 672 if (canUsePthread) { 673 if (pthread_equal( owner_thread, pthread_self() )) { 674 mallocRecursionDetected = true; 675 return true; 676 } else 677 return false; 678 } 679 // inexact stack size based test 680 const uintptr_t threadStackSz = 2*1024*1024; 681 int dummy; 682 return absDiffPtr(autoObjPtr, &dummy)<threadStackSz; 683 } 684 static bool noRecursion(); 685 /* The function is called on 1st scalable_malloc call to check if malloc calls 686 scalable_malloc (nested call must set mallocRecursionDetected). */ 687 static void detectNaiveOverload() { 688 if (!malloc_proxy) { 689 #if __FreeBSD__ 690 /* If !canUsePthread, we can't call pthread_self() before, but now pthread 691 is already on, so can do it. */ 692 if (!canUsePthread) { 693 canUsePthread = true; 694 owner_thread = pthread_self(); 695 } 696 #endif 697 free(malloc(1)); 698 } 699 } 700 }; 701 702 #else 703 704 class RecursiveMallocCallProtector { 705 public: 706 RecursiveMallocCallProtector() {} 707 ~RecursiveMallocCallProtector() {} 708 }; 709 710 #endif /* MALLOC_CHECK_RECURSION */ 711 712 bool isMallocInitializedExt(); 713 714 unsigned int getThreadId(); 715 716 bool initBackRefMaster(Backend *backend); 717 void destroyBackRefMaster(Backend *backend); 718 void removeBackRef(BackRefIdx backRefIdx); 719 void setBackRef(BackRefIdx backRefIdx, void *newPtr); 720 void *getBackRef(BackRefIdx backRefIdx); 721 722 } // namespace internal 723 } // namespace rml 724 725 #endif // __TBB_tbbmalloc_internal_H 726