Home | History | Annotate | Download | only in src
      1 #define	JEMALLOC_MUTEX_C_
      2 #include "jemalloc/internal/jemalloc_internal.h"
      3 
      4 #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32)
      5 #include <dlfcn.h>
      6 #endif
      7 
      8 #ifndef _CRT_SPINCOUNT
      9 #define	_CRT_SPINCOUNT 4000
     10 #endif
     11 
     12 /******************************************************************************/
     13 /* Data. */
     14 
     15 #ifdef JEMALLOC_LAZY_LOCK
     16 bool isthreaded = false;
     17 #endif
     18 #ifdef JEMALLOC_MUTEX_INIT_CB
     19 static bool		postpone_init = true;
     20 static malloc_mutex_t	*postponed_mutexes = NULL;
     21 #endif
     22 
     23 #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32)
     24 static void	pthread_create_once(void);
     25 #endif
     26 
     27 /******************************************************************************/
     28 /*
     29  * We intercept pthread_create() calls in order to toggle isthreaded if the
     30  * process goes multi-threaded.
     31  */
     32 
     33 #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32)
     34 static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *,
     35     void *(*)(void *), void *__restrict);
     36 
     37 static void
     38 pthread_create_once(void)
     39 {
     40 
     41 	pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
     42 	if (pthread_create_fptr == NULL) {
     43 		malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
     44 		    "\"pthread_create\")\n");
     45 		abort();
     46 	}
     47 
     48 	isthreaded = true;
     49 }
     50 
     51 JEMALLOC_EXPORT int
     52 pthread_create(pthread_t *__restrict thread,
     53     const pthread_attr_t *__restrict attr, void *(*start_routine)(void *),
     54     void *__restrict arg)
     55 {
     56 	static pthread_once_t once_control = PTHREAD_ONCE_INIT;
     57 
     58 	pthread_once(&once_control, pthread_create_once);
     59 
     60 	return (pthread_create_fptr(thread, attr, start_routine, arg));
     61 }
     62 #endif
     63 
     64 /******************************************************************************/
     65 
     66 #ifdef JEMALLOC_MUTEX_INIT_CB
     67 JEMALLOC_EXPORT int	_pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex,
     68     void *(calloc_cb)(size_t, size_t));
     69 #endif
     70 
     71 bool
     72 malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank)
     73 {
     74 
     75 #ifdef _WIN32
     76 #  if _WIN32_WINNT >= 0x0600
     77 	InitializeSRWLock(&mutex->lock);
     78 #  else
     79 	if (!InitializeCriticalSectionAndSpinCount(&mutex->lock,
     80 	    _CRT_SPINCOUNT))
     81 		return (true);
     82 #  endif
     83 #elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
     84 	mutex->lock = OS_UNFAIR_LOCK_INIT;
     85 #elif (defined(JEMALLOC_OSSPIN))
     86 	mutex->lock = 0;
     87 #elif (defined(JEMALLOC_MUTEX_INIT_CB))
     88 	if (postpone_init) {
     89 		mutex->postponed_next = postponed_mutexes;
     90 		postponed_mutexes = mutex;
     91 	} else {
     92 		if (_pthread_mutex_init_calloc_cb(&mutex->lock,
     93 		    bootstrap_calloc) != 0)
     94 			return (true);
     95 	}
     96 #else
     97 	pthread_mutexattr_t attr;
     98 
     99 	if (pthread_mutexattr_init(&attr) != 0)
    100 		return (true);
    101 	pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE);
    102 	if (pthread_mutex_init(&mutex->lock, &attr) != 0) {
    103 		pthread_mutexattr_destroy(&attr);
    104 		return (true);
    105 	}
    106 	pthread_mutexattr_destroy(&attr);
    107 #endif
    108 	if (config_debug)
    109 		witness_init(&mutex->witness, name, rank, NULL);
    110 	return (false);
    111 }
    112 
    113 void
    114 malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex)
    115 {
    116 
    117 	malloc_mutex_lock(tsdn, mutex);
    118 }
    119 
    120 void
    121 malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex)
    122 {
    123 
    124 	malloc_mutex_unlock(tsdn, mutex);
    125 }
    126 
    127 void
    128 malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex)
    129 {
    130 
    131 #ifdef JEMALLOC_MUTEX_INIT_CB
    132 	malloc_mutex_unlock(tsdn, mutex);
    133 #else
    134 	if (malloc_mutex_init(mutex, mutex->witness.name,
    135 	    mutex->witness.rank)) {
    136 		malloc_printf("<jemalloc>: Error re-initializing mutex in "
    137 		    "child\n");
    138 		if (opt_abort)
    139 			abort();
    140 	}
    141 #endif
    142 }
    143 
    144 bool
    145 malloc_mutex_boot(void)
    146 {
    147 
    148 #ifdef JEMALLOC_MUTEX_INIT_CB
    149 	postpone_init = false;
    150 	while (postponed_mutexes != NULL) {
    151 		if (_pthread_mutex_init_calloc_cb(&postponed_mutexes->lock,
    152 		    bootstrap_calloc) != 0)
    153 			return (true);
    154 		postponed_mutexes = postponed_mutexes->postponed_next;
    155 	}
    156 #endif
    157 	return (false);
    158 }
    159