Blame jemalloc/include/jemalloc/internal/mutex.h

Packit Service 724aca
#ifndef JEMALLOC_INTERNAL_MUTEX_H
Packit Service 724aca
#define JEMALLOC_INTERNAL_MUTEX_H
Packit Service 724aca
Packit Service 724aca
#include "jemalloc/internal/atomic.h"
Packit Service 724aca
#include "jemalloc/internal/mutex_prof.h"
Packit Service 724aca
#include "jemalloc/internal/tsd.h"
Packit Service 724aca
#include "jemalloc/internal/witness.h"
Packit Service 724aca
Packit Service 724aca
typedef enum {
Packit Service 724aca
	/* Can only acquire one mutex of a given witness rank at a time. */
Packit Service 724aca
	malloc_mutex_rank_exclusive,
Packit Service 724aca
	/*
Packit Service 724aca
	 * Can acquire multiple mutexes of the same witness rank, but in
Packit Service 724aca
	 * address-ascending order only.
Packit Service 724aca
	 */
Packit Service 724aca
	malloc_mutex_address_ordered
Packit Service 724aca
} malloc_mutex_lock_order_t;
Packit Service 724aca
Packit Service 724aca
typedef struct malloc_mutex_s malloc_mutex_t;
Packit Service 724aca
struct malloc_mutex_s {
Packit Service 724aca
	union {
Packit Service 724aca
		struct {
Packit Service 724aca
			/*
Packit Service 724aca
			 * prof_data is defined first to reduce cacheline
Packit Service 724aca
			 * bouncing: the data is not touched by the mutex holder
Packit Service 724aca
			 * during unlocking, while might be modified by
Packit Service 724aca
			 * contenders.  Having it before the mutex itself could
Packit Service 724aca
			 * avoid prefetching a modified cacheline (for the
Packit Service 724aca
			 * unlocking thread).
Packit Service 724aca
			 */
Packit Service 724aca
			mutex_prof_data_t	prof_data;
Packit Service 724aca
#ifdef _WIN32
Packit Service 724aca
#  if _WIN32_WINNT >= 0x0600
Packit Service 724aca
			SRWLOCK         	lock;
Packit Service 724aca
#  else
Packit Service 724aca
			CRITICAL_SECTION	lock;
Packit Service 724aca
#  endif
Packit Service 724aca
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
Packit Service 724aca
			os_unfair_lock		lock;
Packit Service 724aca
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
Packit Service 724aca
			pthread_mutex_t		lock;
Packit Service 724aca
			malloc_mutex_t		*postponed_next;
Packit Service 724aca
#else
Packit Service 724aca
			pthread_mutex_t		lock;
Packit Service 724aca
#endif
Packit Service 724aca
			/*
Packit Service 724aca
			 * Hint flag to avoid exclusive cache line contention
Packit Service 724aca
			 * during spin waiting
Packit Service 724aca
			 */
Packit Service 724aca
			atomic_b_t		locked;
Packit Service 724aca
		};
Packit Service 724aca
		/*
Packit Service 724aca
		 * We only touch witness when configured w/ debug.  However we
Packit Service 724aca
		 * keep the field in a union when !debug so that we don't have
Packit Service 724aca
		 * to pollute the code base with #ifdefs, while avoid paying the
Packit Service 724aca
		 * memory cost.
Packit Service 724aca
		 */
Packit Service 724aca
#if !defined(JEMALLOC_DEBUG)
Packit Service 724aca
		witness_t			witness;
Packit Service 724aca
		malloc_mutex_lock_order_t	lock_order;
Packit Service 724aca
#endif
Packit Service 724aca
	};
Packit Service 724aca
Packit Service 724aca
#if defined(JEMALLOC_DEBUG)
Packit Service 724aca
	witness_t			witness;
Packit Service 724aca
	malloc_mutex_lock_order_t	lock_order;
Packit Service 724aca
#endif
Packit Service 724aca
};
Packit Service 724aca
Packit Service 724aca
/*
Packit Service 724aca
 * Based on benchmark results, a fixed spin with this amount of retries works
Packit Service 724aca
 * well for our critical sections.
Packit Service 724aca
 */
Packit Service 724aca
#define MALLOC_MUTEX_MAX_SPIN 250
Packit Service 724aca
Packit Service 724aca
#ifdef _WIN32
Packit Service 724aca
#  if _WIN32_WINNT >= 0x0600
Packit Service 724aca
#    define MALLOC_MUTEX_LOCK(m)    AcquireSRWLockExclusive(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_UNLOCK(m)  ReleaseSRWLockExclusive(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock))
Packit Service 724aca
#  else
Packit Service 724aca
#    define MALLOC_MUTEX_LOCK(m)    EnterCriticalSection(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_UNLOCK(m)  LeaveCriticalSection(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock))
Packit Service 724aca
#  endif
Packit Service 724aca
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
Packit Service 724aca
#    define MALLOC_MUTEX_LOCK(m)    os_unfair_lock_lock(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_UNLOCK(m)  os_unfair_lock_unlock(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock))
Packit Service 724aca
#else
Packit Service 724aca
#    define MALLOC_MUTEX_LOCK(m)    pthread_mutex_lock(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_UNLOCK(m)  pthread_mutex_unlock(&(m)->lock)
Packit Service 724aca
#    define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0)
Packit Service 724aca
#endif
Packit Service 724aca
Packit Service 724aca
#define LOCK_PROF_DATA_INITIALIZER					\
Packit Service 724aca
    {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0,		\
Packit Service 724aca
	    ATOMIC_INIT(0), 0, NULL, 0}
Packit Service 724aca
Packit Service 724aca
#ifdef _WIN32
Packit Service 724aca
#  define MALLOC_MUTEX_INITIALIZER
Packit Service 724aca
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
Packit Service 724aca
#  if defined(JEMALLOC_DEBUG)
Packit Service 724aca
#    define MALLOC_MUTEX_INITIALIZER					\
Packit Service 724aca
  {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT, ATOMIC_INIT(false)}}, \
Packit Service 724aca
         WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
Packit Service 724aca
#  else
Packit Service 724aca
#    define MALLOC_MUTEX_INITIALIZER                      \
Packit Service 724aca
  {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT, ATOMIC_INIT(false)}},  \
Packit Service 724aca
      WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
Packit Service 724aca
#  endif
Packit Service 724aca
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
Packit Service 724aca
#  if (defined(JEMALLOC_DEBUG))
Packit Service 724aca
#     define MALLOC_MUTEX_INITIALIZER					\
Packit Service 724aca
      {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL, ATOMIC_INIT(false)}},	\
Packit Service 724aca
           WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
Packit Service 724aca
#  else
Packit Service 724aca
#     define MALLOC_MUTEX_INITIALIZER					\
Packit Service 724aca
      {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL, ATOMIC_INIT(false)}},	\
Packit Service 724aca
           WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
Packit Service 724aca
#  endif
Packit Service 724aca
Packit Service 724aca
#else
Packit Service 724aca
#    define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
Packit Service 724aca
#  if defined(JEMALLOC_DEBUG)
Packit Service 724aca
#    define MALLOC_MUTEX_INITIALIZER					\
Packit Service 724aca
     {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, ATOMIC_INIT(false)}}, \
Packit Service 724aca
           WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
Packit Service 724aca
#  else
Packit Service 724aca
#    define MALLOC_MUTEX_INITIALIZER                          \
Packit Service 724aca
     {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, ATOMIC_INIT(false)}},	\
Packit Service 724aca
      WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
Packit Service 724aca
#  endif
Packit Service 724aca
#endif
Packit Service 724aca
Packit Service 724aca
#ifdef JEMALLOC_LAZY_LOCK
Packit Service 724aca
extern bool isthreaded;
Packit Service 724aca
#else
Packit Service 724aca
#  undef isthreaded /* Undo private_namespace.h definition. */
Packit Service 724aca
#  define isthreaded true
Packit Service 724aca
#endif
Packit Service 724aca
Packit Service 724aca
bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name,
Packit Service 724aca
    witness_rank_t rank, malloc_mutex_lock_order_t lock_order);
Packit Service 724aca
void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex);
Packit Service 724aca
void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex);
Packit Service 724aca
void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex);
Packit Service 724aca
bool malloc_mutex_boot(void);
Packit Service 724aca
void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex);
Packit Service 724aca
Packit Service 724aca
void malloc_mutex_lock_slow(malloc_mutex_t *mutex);
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_lock_final(malloc_mutex_t *mutex) {
Packit Service 724aca
	MALLOC_MUTEX_LOCK(mutex);
Packit Service 724aca
	atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline bool
Packit Service 724aca
malloc_mutex_trylock_final(malloc_mutex_t *mutex) {
Packit Service 724aca
	return MALLOC_MUTEX_TRYLOCK(mutex);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	if (config_stats) {
Packit Service 724aca
		mutex_prof_data_t *data = &mutex->prof_data;
Packit Service 724aca
		data->n_lock_ops++;
Packit Service 724aca
		if (data->prev_owner != tsdn) {
Packit Service 724aca
			data->prev_owner = tsdn;
Packit Service 724aca
			data->n_owner_switches++;
Packit Service 724aca
		}
Packit Service 724aca
	}
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
/* Trylock: return false if the lock is successfully acquired. */
Packit Service 724aca
static inline bool
Packit Service 724aca
malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
	if (isthreaded) {
Packit Service 724aca
		if (malloc_mutex_trylock_final(mutex)) {
Packit Service 724aca
			atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
Packit Service 724aca
			return true;
Packit Service 724aca
		}
Packit Service 724aca
		mutex_owner_stats_update(tsdn, mutex);
Packit Service 724aca
	}
Packit Service 724aca
	witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
Packit Service 724aca
	return false;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
/* Aggregate lock prof data. */
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) {
Packit Service 724aca
	nstime_add(&sum->tot_wait_time, &data->tot_wait_time);
Packit Service 724aca
	if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) {
Packit Service 724aca
		nstime_copy(&sum->max_wait_time, &data->max_wait_time);
Packit Service 724aca
	}
Packit Service 724aca
Packit Service 724aca
	sum->n_wait_times += data->n_wait_times;
Packit Service 724aca
	sum->n_spin_acquired += data->n_spin_acquired;
Packit Service 724aca
Packit Service 724aca
	if (sum->max_n_thds < data->max_n_thds) {
Packit Service 724aca
		sum->max_n_thds = data->max_n_thds;
Packit Service 724aca
	}
Packit Service 724aca
	uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds,
Packit Service 724aca
	    ATOMIC_RELAXED);
Packit Service 724aca
	uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32(
Packit Service 724aca
	    &data->n_waiting_thds, ATOMIC_RELAXED);
Packit Service 724aca
	atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds,
Packit Service 724aca
	    ATOMIC_RELAXED);
Packit Service 724aca
	sum->n_owner_switches += data->n_owner_switches;
Packit Service 724aca
	sum->n_lock_ops += data->n_lock_ops;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
	if (isthreaded) {
Packit Service 724aca
		if (malloc_mutex_trylock_final(mutex)) {
Packit Service 724aca
			malloc_mutex_lock_slow(mutex);
Packit Service 724aca
			atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
Packit Service 724aca
		}
Packit Service 724aca
		mutex_owner_stats_update(tsdn, mutex);
Packit Service 724aca
	}
Packit Service 724aca
	witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	atomic_store_b(&mutex->locked, false, ATOMIC_RELAXED);
Packit Service 724aca
	witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
	if (isthreaded) {
Packit Service 724aca
		MALLOC_MUTEX_UNLOCK(mutex);
Packit Service 724aca
	}
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	witness_assert_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) {
Packit Service 724aca
	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
/* Copy the prof data from mutex for processing. */
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data,
Packit Service 724aca
    malloc_mutex_t *mutex) {
Packit Service 724aca
	mutex_prof_data_t *source = &mutex->prof_data;
Packit Service 724aca
	/* Can only read holding the mutex. */
Packit Service 724aca
	malloc_mutex_assert_owner(tsdn, mutex);
Packit Service 724aca
Packit Service 724aca
	/*
Packit Service 724aca
	 * Not *really* allowed (we shouldn't be doing non-atomic loads of
Packit Service 724aca
	 * atomic data), but the mutex protection makes this safe, and writing
Packit Service 724aca
	 * a member-for-member copy is tedious for this situation.
Packit Service 724aca
	 */
Packit Service 724aca
	*data = *source;
Packit Service 724aca
	/* n_wait_thds is not reported (modified w/o locking). */
Packit Service 724aca
	atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void
Packit Service 724aca
malloc_mutex_prof_accum(tsdn_t *tsdn, mutex_prof_data_t *data,
Packit Service 724aca
    malloc_mutex_t *mutex) {
Packit Service 724aca
	mutex_prof_data_t *source = &mutex->prof_data;
Packit Service 724aca
	/* Can only read holding the mutex. */
Packit Service 724aca
	malloc_mutex_assert_owner(tsdn, mutex);
Packit Service 724aca
Packit Service 724aca
	nstime_add(&data->tot_wait_time, &source->tot_wait_time);
Packit Service 724aca
	if (nstime_compare(&source->max_wait_time, &data->max_wait_time) > 0) {
Packit Service 724aca
		nstime_copy(&data->max_wait_time, &source->max_wait_time);
Packit Service 724aca
	}
Packit Service 724aca
	data->n_wait_times += source->n_wait_times;
Packit Service 724aca
	data->n_spin_acquired += source->n_spin_acquired;
Packit Service 724aca
	if (data->max_n_thds < source->max_n_thds) {
Packit Service 724aca
		data->max_n_thds = source->max_n_thds;
Packit Service 724aca
	}
Packit Service 724aca
	/* n_wait_thds is not reported. */
Packit Service 724aca
	atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
Packit Service 724aca
	data->n_owner_switches += source->n_owner_switches;
Packit Service 724aca
	data->n_lock_ops += source->n_lock_ops;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
#endif /* JEMALLOC_INTERNAL_MUTEX_H */