github.com/moontrade/nogc@v0.1.7/alloc/rpmalloc/src/malloc.c (about)

     1  /* malloc.c  -  Memory allocator  -  Public Domain  -  2016 Mattias Jansson
     2   *
     3   * This library provides a cross-platform lock free thread caching malloc implementation in C11.
     4   * The latest source code is always available at
     5   *
     6   * https://github.com/mjansson/rpmalloc
     7   *
     8   * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
     9   *
    10   */
    11  
    12  //
    13  // This file provides overrides for the standard library malloc entry points for C and new/delete operators for C++
    14  // It also provides automatic initialization/finalization of process and threads
    15  //
    16  
    17  #ifndef ARCH_64BIT
    18  #  if defined(__LLP64__) || defined(__LP64__) || defined(_WIN64)
    19  #    define ARCH_64BIT 1
    20  _Static_assert(sizeof(size_t) == 8, "Data type size mismatch");
    21  _Static_assert(sizeof(void*) == 8, "Data type size mismatch");
    22  #  else
    23  #    define ARCH_64BIT 0
    24  _Static_assert(sizeof(size_t) == 4, "Data type size mismatch");
    25  _Static_assert(sizeof(void*) == 4, "Data type size mismatch");
    26  #  endif
    27  #endif
    28  
    29  #if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__)
    30  #pragma GCC visibility push(default)
    31  #endif
    32  
    33  #define USE_IMPLEMENT 1
    34  #define USE_INTERPOSE 0
    35  #define USE_ALIAS 0
    36  
    37  #if defined(__APPLE__) && ENABLE_PRELOAD
    38  #undef USE_INTERPOSE
    39  #define USE_INTERPOSE 1
    40  
    41  typedef struct interpose_t {
    42  	void* new_func;
    43  	void* orig_func;
    44  } interpose_t;
    45  
    46  #define MAC_INTERPOSE_PAIR(newf, oldf) 	{ (void*)newf, (void*)oldf }
    47  #define MAC_INTERPOSE_SINGLE(newf, oldf) \
    48  __attribute__((used)) static const interpose_t macinterpose##newf##oldf \
    49  __attribute__ ((section("__DATA, __interpose"))) = MAC_INTERPOSE_PAIR(newf, oldf)
    50  
    51  #endif
    52  
    53  #if !defined(_WIN32) && !USE_INTERPOSE
    54  #undef USE_IMPLEMENT
    55  #undef USE_ALIAS
    56  #define USE_IMPLEMENT 0
    57  #define USE_ALIAS 1
    58  #endif
    59  
    60  #ifdef _MSC_VER
    61  #pragma warning (disable : 4100)
    62  #undef malloc
    63  #undef free
    64  #undef calloc
    65  #define RPMALLOC_RESTRICT __declspec(restrict)
    66  #else
    67  #define RPMALLOC_RESTRICT
    68  #endif
    69  
    70  #if ENABLE_OVERRIDE
    71  
    72  typedef struct rp_nothrow_t { int __dummy; } rp_nothrow_t;
    73  
    74  #if USE_IMPLEMENT
    75  
    76  extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL malloc(size_t size) { return rpmalloc(size); }
    77  extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL calloc(size_t count, size_t size) { return rpcalloc(count, size); }
    78  extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL realloc(void* ptr, size_t size) { return rprealloc(ptr, size); }
    79  extern inline void* RPMALLOC_CDECL reallocf(void* ptr, size_t size) { return rprealloc(ptr, size); }
    80  extern inline void* RPMALLOC_CDECL aligned_alloc(size_t alignment, size_t size) { return rpaligned_alloc(alignment, size); }
    81  extern inline void* RPMALLOC_CDECL memalign(size_t alignment, size_t size) { return rpmemalign(alignment, size); }
    82  extern inline int RPMALLOC_CDECL posix_memalign(void** memptr, size_t alignment, size_t size) { return rpposix_memalign(memptr, alignment, size); }
    83  extern inline void RPMALLOC_CDECL free(void* ptr) { rpfree(ptr); }
    84  extern inline void RPMALLOC_CDECL cfree(void* ptr) { rpfree(ptr); }
    85  extern inline size_t RPMALLOC_CDECL malloc_usable_size(void* ptr) { return rpmalloc_usable_size(ptr); }
    86  extern inline size_t RPMALLOC_CDECL malloc_size(void* ptr) { return rpmalloc_usable_size(ptr); }
    87  
    88  #ifdef _WIN32
    89  // For Windows, #include <rpnew.h> in one source file to get the C++ operator overrides implemented in your module
    90  #else
    91  // Overload the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
    92  // operators delete and delete[]
    93  extern void _ZdlPv(void* p); void _ZdlPv(void* p) { rpfree(p); }
    94  extern void _ZdaPv(void* p); void _ZdaPv(void* p) { rpfree(p); }
    95  #if ARCH_64BIT
    96  // 64-bit operators new and new[], normal and aligned
    97  extern void* _Znwm(uint64_t size); void* _Znwm(uint64_t size) { return rpmalloc(size); }
    98  extern void* _Znam(uint64_t size); void* _Znam(uint64_t size) { return rpmalloc(size); }
    99  extern void* _Znwmm(uint64_t size, uint64_t align); void* _Znwmm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   100  extern void* _Znamm(uint64_t size, uint64_t align); void* _Znamm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   101  extern void* _ZnwmSt11align_val_t(uint64_t size, uint64_t align); void* _ZnwmSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   102  extern void* _ZnamSt11align_val_t(uint64_t size, uint64_t align); void* _ZnamSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   103  extern void* _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   104  extern void* _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   105  extern void* _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   106  extern void* _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   107  // 64-bit operators sized delete and delete[], normal and aligned
   108  extern void _ZdlPvm(void* p, uint64_t size); void _ZdlPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
   109  extern void _ZdaPvm(void* p, uint64_t size); void _ZdaPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
   110  extern void _ZdlPvSt11align_val_t(void* p, uint64_t align); void _ZdlPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
   111  extern void _ZdaPvSt11align_val_t(void* p, uint64_t align); void _ZdaPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
   112  extern void _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
   113  extern void _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
   114  #else
   115  // 32-bit operators new and new[], normal and aligned
   116  extern void* _Znwj(uint32_t size); void* _Znwj(uint32_t size) { return rpmalloc(size); }
   117  extern void* _Znaj(uint32_t size); void* _Znaj(uint32_t size) { return rpmalloc(size); }
   118  extern void* _Znwjj(uint32_t size, uint32_t align); void* _Znwjj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
   119  extern void* _Znajj(uint32_t size, uint32_t align); void* _Znajj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
   120  extern void* _ZnwjSt11align_val_t(size_t size, size_t align); void* _ZnwjSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   121  extern void* _ZnajSt11align_val_t(size_t size, size_t align); void* _ZnajSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   122  extern void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   123  extern void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   124  extern void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   125  extern void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   126  // 32-bit operators sized delete and delete[], normal and aligned
   127  extern void _ZdlPvj(void* p, uint64_t size); void _ZdlPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
   128  extern void _ZdaPvj(void* p, uint64_t size); void _ZdaPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
   129  extern void _ZdlPvSt11align_val_t(void* p, uint32_t align); void _ZdlPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
   130  extern void _ZdaPvSt11align_val_t(void* p, uint32_t align); void _ZdaPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
   131  extern void _ZdlPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void _ZdlPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
   132  extern void _ZdaPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void _ZdaPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
   133  #endif
   134  #endif
   135  
   136  #endif
   137  
   138  #if USE_INTERPOSE
   139  
   140  __attribute__((used)) static const interpose_t macinterpose_malloc[]
   141  __attribute__ ((section("__DATA, __interpose"))) = {
   142  	//new and new[]
   143  	MAC_INTERPOSE_PAIR(rpmalloc, _Znwm),
   144  	MAC_INTERPOSE_PAIR(rpmalloc, _Znam),
   145  	//delete and delete[]
   146  	MAC_INTERPOSE_PAIR(rpfree, _ZdlPv),
   147  	MAC_INTERPOSE_PAIR(rpfree, _ZdaPv),
   148  	MAC_INTERPOSE_PAIR(rpmalloc, malloc),
   149  	MAC_INTERPOSE_PAIR(rpmalloc, calloc),
   150  	MAC_INTERPOSE_PAIR(rprealloc, realloc),
   151  	MAC_INTERPOSE_PAIR(rprealloc, reallocf),
   152  #if defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15
   153  	MAC_INTERPOSE_PAIR(rpaligned_alloc, aligned_alloc),
   154  #endif
   155  	MAC_INTERPOSE_PAIR(rpmemalign, memalign),
   156  	MAC_INTERPOSE_PAIR(rpposix_memalign, posix_memalign),
   157  	MAC_INTERPOSE_PAIR(rpfree, free),
   158  	MAC_INTERPOSE_PAIR(rpfree, cfree),
   159  	MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_usable_size),
   160  	MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_size)
   161  };
   162  
   163  #endif
   164  
   165  #if USE_ALIAS
   166  
   167  #define RPALIAS(fn) __attribute__((alias(#fn), used, visibility("default")));
   168  
   169  // Alias the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
   170  
   171  // operators delete and delete[]
   172  void _ZdlPv(void* p) RPALIAS(rpfree)
   173  void _ZdaPv(void* p) RPALIAS(rpfree)
   174  extern inline void _ZdlPvm(void* p, size_t n) { rpfree(p); (void)sizeof(n); }
   175  extern inline void _ZdaPvm(void* p, size_t n) { rpfree(p); (void)sizeof(n); }
   176  extern inline void _ZdlPvSt11align_val_t(void* p, size_t a) { rpfree(p); (void)sizeof(a); }
   177  extern inline void _ZdaPvSt11align_val_t(void* p, size_t a) { rpfree(p); (void)sizeof(a); }
   178  extern inline void _ZdlPvmSt11align_val_t(void* p, size_t n, size_t a) { rpfree(p); (void)sizeof(n); (void)sizeof(a); }
   179  extern inline void _ZdaPvmSt11align_val_t(void* p, size_t n, size_t a) { rpfree(p); (void)sizeof(n); (void)sizeof(a); }
   180  
   181  #if ARCH_64BIT
   182  // 64-bit operators new and new[], normal and aligned
   183  void* _Znwm(uint64_t size) RPALIAS(rpmalloc)
   184  void* _Znam(uint64_t size) RPALIAS(rpmalloc)
   185  extern inline void* _Znwmm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   186  extern inline void* _Znamm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
   187  extern inline void* _ZnwmSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   188  extern inline void* _ZnamSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   189  extern inline void* _ZnwmRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   190  extern inline void* _ZnamRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   191  extern inline void* _ZnwmSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   192  extern inline void* _ZnamSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   193  #else
   194  // 32-bit operators new and new[], normal and aligned
   195  void* _Znwj(uint32_t size) RPALIAS(rpmalloc)
   196  void* _Znaj(uint32_t size) RPALIAS(rpmalloc)
   197  extern inline void* _Znwjj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
   198  extern inline void* _Znajj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
   199  extern inline void* _ZnwjSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   200  extern inline void* _ZnajSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
   201  extern inline void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   202  extern inline void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
   203  extern inline void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   204  extern inline void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
   205  #endif
   206  
   207  void* malloc(size_t size) RPALIAS(rpmalloc)
   208  void* calloc(size_t count, size_t size) RPALIAS(rpcalloc)
   209  void* realloc(void* ptr, size_t size) RPALIAS(rprealloc)
   210  void* reallocf(void* ptr, size_t size) RPALIAS(rprealloc)
   211  void* aligned_alloc(size_t alignment, size_t size) RPALIAS(rpaligned_alloc)
   212  void* memalign(size_t alignment, size_t size) RPALIAS(rpmemalign)
   213  int posix_memalign(void** memptr, size_t alignment, size_t size) RPALIAS(rpposix_memalign)
   214  void free(void* ptr) RPALIAS(rpfree)
   215  void cfree(void* ptr) RPALIAS(rpfree)
   216  #if defined(__ANDROID__)
   217  size_t malloc_usable_size(const void* ptr) RPALIAS(rpmalloc_usable_size)
   218  #else
   219  size_t malloc_usable_size(void* ptr) RPALIAS(rpmalloc_usable_size)
   220  #endif
   221  size_t malloc_size(void* ptr) RPALIAS(rpmalloc_usable_size)
   222  
   223  #endif
   224  
   225  static inline size_t
   226  _rpmalloc_page_size(void) {
   227  	return _memory_page_size;
   228  }
   229  
   230  extern inline void* RPMALLOC_CDECL
   231  reallocarray(void* ptr, size_t count, size_t size) {
   232  	size_t total;
   233  #if ENABLE_VALIDATE_ARGS
   234  #ifdef _MSC_VER
   235  	int err = SizeTMult(count, size, &total);
   236  	if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
   237  		errno = EINVAL;
   238  		return 0;
   239  	}
   240  #else
   241  	int err = __builtin_umull_overflow(count, size, &total);
   242  	if (err || (total >= MAX_ALLOC_SIZE)) {
   243  		errno = EINVAL;
   244  		return 0;
   245  	}
   246  #endif
   247  #else
   248  	total = count * size;
   249  #endif
   250  	return realloc(ptr, total);
   251  }
   252  
   253  extern inline void* RPMALLOC_CDECL
   254  valloc(size_t size) {
   255  	get_thread_heap();
   256  	return rpaligned_alloc(_rpmalloc_page_size(), size);
   257  }
   258  
   259  extern inline void* RPMALLOC_CDECL
   260  pvalloc(size_t size) {
   261  	get_thread_heap();
   262  	const size_t page_size = _rpmalloc_page_size();
   263  	const size_t aligned_size = ((size + page_size - 1) / page_size) * page_size;
   264  #if ENABLE_VALIDATE_ARGS
   265  	if (aligned_size < size) {
   266  		errno = EINVAL;
   267  		return 0;
   268  	}
   269  #endif
   270  	return rpaligned_alloc(_rpmalloc_page_size(), aligned_size);
   271  }
   272  
   273  #endif // ENABLE_OVERRIDE
   274  
   275  #if ENABLE_PRELOAD
   276  
   277  #ifdef _WIN32
   278  
   279  #if defined(BUILD_DYNAMIC_LINK) && BUILD_DYNAMIC_LINK
   280  
   281  extern __declspec(dllexport) BOOL WINAPI
   282  DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved);
   283  
   284  extern __declspec(dllexport) BOOL WINAPI
   285  DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
   286  	(void)sizeof(reserved);
   287  	(void)sizeof(instance);
   288  	if (reason == DLL_PROCESS_ATTACH)
   289  		rpmalloc_initialize();
   290  	else if (reason == DLL_PROCESS_DETACH)
   291  		rpmalloc_finalize();
   292  	else if (reason == DLL_THREAD_ATTACH)
   293  		rpmalloc_thread_initialize();
   294  	else if (reason == DLL_THREAD_DETACH)
   295  		rpmalloc_thread_finalize(1);
   296  	return TRUE;
   297  }
   298  
   299  //end BUILD_DYNAMIC_LINK
   300  #else
   301  
   302  extern void
   303  _global_rpmalloc_init(void) {
   304  	rpmalloc_set_main_thread();
   305  	rpmalloc_initialize();
   306  }
   307  
   308  #if defined(__clang__) || defined(__GNUC__)
   309  
   310  static void __attribute__((constructor))
   311  initializer(void) {
   312  	_global_rpmalloc_init();
   313  }
   314  
   315  #elif defined(_MSC_VER)
   316  
   317  #pragma section(".CRT$XIB",read)
   318  __declspec(allocate(".CRT$XIB")) void (*_rpmalloc_module_init)(void) = _global_rpmalloc_init;
   319  #pragma comment(linker, "/include:_rpmalloc_module_init")
   320  
   321  #endif
   322  
   323  //end !BUILD_DYNAMIC_LINK
   324  #endif
   325  
   326  #else
   327  
   328  #include <pthread.h>
   329  #include <stdlib.h>
   330  #include <stdint.h>
   331  #include <unistd.h>
   332  
   333  extern void
   334  rpmalloc_set_main_thread(void);
   335  
   336  static pthread_key_t destructor_key;
   337  
   338  static void
   339  thread_destructor(void*);
   340  
   341  static void __attribute__((constructor))
   342  initializer(void) {
   343  	rpmalloc_set_main_thread();
   344  	rpmalloc_initialize();
   345  	pthread_key_create(&destructor_key, thread_destructor);
   346  }
   347  
   348  static void __attribute__((destructor))
   349  finalizer(void) {
   350  	rpmalloc_finalize();
   351  }
   352  
   353  typedef struct {
   354  	void* (*real_start)(void*);
   355  	void* real_arg;
   356  } thread_starter_arg;
   357  
   358  static void*
   359  thread_starter(void* argptr) {
   360  	thread_starter_arg* arg = argptr;
   361  	void* (*real_start)(void*) = arg->real_start;
   362  	void* real_arg = arg->real_arg;
   363  	rpmalloc_thread_initialize();
   364  	rpfree(argptr);
   365  	pthread_setspecific(destructor_key, (void*)1);
   366  	return (*real_start)(real_arg);
   367  }
   368  
   369  static void
   370  thread_destructor(void* value) {
   371  	(void)sizeof(value);
   372  	rpmalloc_thread_finalize(1);
   373  }
   374  
   375  #ifdef __APPLE__
   376  
   377  static int
   378  pthread_create_proxy(pthread_t* thread,
   379                       const pthread_attr_t* attr,
   380                       void* (*start_routine)(void*),
   381                       void* arg) {
   382  	rpmalloc_initialize();
   383  //	fprintf(stderr, "pthread_create_proxy\n");
   384  	thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
   385  	starter_arg->real_start = start_routine;
   386  	starter_arg->real_arg = arg;
   387  	return pthread_create(thread, attr, thread_starter, starter_arg);
   388  }
   389  
   390  MAC_INTERPOSE_SINGLE(pthread_create_proxy, pthread_create);
   391  
   392  #else
   393  
   394  #include <dlfcn.h>
   395  
   396  int
   397  pthread_create(pthread_t* thread,
   398                 const pthread_attr_t* attr,
   399                 void* (*start_routine)(void*),
   400                 void* arg) {
   401  #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
   402      defined(__APPLE__) || defined(__HAIKU__)
   403  	char fname[] = "pthread_create";
   404  #else
   405  	char fname[] = "_pthread_create";
   406  #endif
   407  	void* real_pthread_create = dlsym(RTLD_NEXT, fname);
   408  	rpmalloc_thread_initialize();
   409  	thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
   410  	starter_arg->real_start = start_routine;
   411  	starter_arg->real_arg = arg;
   412  	return (*(int (*)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*))real_pthread_create)(thread, attr, thread_starter, starter_arg);
   413  }
   414  
   415  #endif
   416  
   417  #endif
   418  
   419  #endif
   420  
   421  #if ENABLE_OVERRIDE
   422  
   423  #if defined(__GLIBC__) && defined(__linux__)
   424  
   425  void* __libc_malloc(size_t size) RPALIAS(rpmalloc)
   426  void* __libc_calloc(size_t count, size_t size) RPALIAS(rpcalloc)
   427  void* __libc_realloc(void* p, size_t size) RPALIAS(rprealloc)
   428  void __libc_free(void* p) RPALIAS(rpfree)
   429  void __libc_cfree(void* p) RPALIAS(rpfree)
   430  void* __libc_memalign(size_t align, size_t size) RPALIAS(rpmemalign)
   431  int __posix_memalign(void** p, size_t align, size_t size) RPALIAS(rpposix_memalign)
   432  
   433  extern void* __libc_valloc(size_t size);
   434  extern void* __libc_pvalloc(size_t size);
   435  
   436  void*
   437  __libc_valloc(size_t size) {
   438  	return valloc(size);
   439  }
   440  
   441  void*
   442  __libc_pvalloc(size_t size) {
   443  	return pvalloc(size);
   444  }
   445  
   446  #endif
   447  
   448  #endif
   449  
   450  #if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__)
   451  #pragma GCC visibility pop
   452  #endif