Introduce lockedint module.
This pulls out the various abstractions where some stats counter is sometimes an atomic, sometimes a plain variable, sometimes always protected by a lock, sometimes protected by reads but not writes, etc. With this change, these cases are treated consistently, and access patterns tagged. In the process, we fix a few missed-update bugs (where one caller assumes "protected-by-a-lock" semantics and another does not).
This commit is contained in:
committed by
David Goldblatt
parent
acd0bf6a26
commit
356aaa7dc6
@@ -148,14 +148,14 @@ arena_decay_extent(tsdn_t *tsdn,arena_t *arena, ehooks_t *ehooks,
|
||||
extent_dalloc_wrapper(tsdn, arena, ehooks, edata);
|
||||
if (config_stats) {
|
||||
/* Update stats accordingly. */
|
||||
arena_stats_lock(tsdn, &arena->stats);
|
||||
arena_stats_add_u64(tsdn, &arena->stats,
|
||||
LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
|
||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||
&arena->decay_dirty.stats->nmadvise, 1);
|
||||
arena_stats_add_u64(tsdn, &arena->stats,
|
||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||
&arena->decay_dirty.stats->purged, extent_size >> LG_PAGE);
|
||||
arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped,
|
||||
extent_size);
|
||||
arena_stats_unlock(tsdn, &arena->stats);
|
||||
locked_dec_zu(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||
&arena->stats.mapped, extent_size);
|
||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define JEMALLOC_INTERNAL_ARENA_STATS_H
|
||||
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/lockedint.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/mutex_prof.h"
|
||||
#include "jemalloc/internal/pa.h"
|
||||
@@ -9,40 +10,28 @@
|
||||
|
||||
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||
|
||||
/*
|
||||
* In those architectures that support 64-bit atomics, we use atomic updates for
|
||||
* our 64-bit values. Otherwise, we use a plain uint64_t and synchronize
|
||||
* externally.
|
||||
*/
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
typedef atomic_u64_t arena_stats_u64_t;
|
||||
#else
|
||||
/* Must hold the arena stats mutex while reading atomically. */
|
||||
typedef uint64_t arena_stats_u64_t;
|
||||
#endif
|
||||
|
||||
typedef struct arena_stats_large_s arena_stats_large_t;
|
||||
struct arena_stats_large_s {
|
||||
/*
|
||||
* Total number of allocation/deallocation requests served directly by
|
||||
* the arena.
|
||||
*/
|
||||
arena_stats_u64_t nmalloc;
|
||||
arena_stats_u64_t ndalloc;
|
||||
locked_u64_t nmalloc;
|
||||
locked_u64_t ndalloc;
|
||||
|
||||
/*
|
||||
* Number of allocation requests that correspond to this size class.
|
||||
* This includes requests served by tcache, though tcache only
|
||||
* periodically merges into this counter.
|
||||
*/
|
||||
arena_stats_u64_t nrequests; /* Partially derived. */
|
||||
locked_u64_t nrequests; /* Partially derived. */
|
||||
/*
|
||||
* Number of tcache fills / flushes for large (similarly, periodically
|
||||
* merged). Note that there is no large tcache batch-fill currently
|
||||
* (i.e. only fill 1 at a time); however flush may be batched.
|
||||
*/
|
||||
arena_stats_u64_t nfills; /* Partially derived. */
|
||||
arena_stats_u64_t nflushes; /* Partially derived. */
|
||||
locked_u64_t nfills; /* Partially derived. */
|
||||
locked_u64_t nflushes; /* Partially derived. */
|
||||
|
||||
/* Current number of allocations of this size class. */
|
||||
size_t curlextents; /* Derived. */
|
||||
@@ -51,11 +40,11 @@ struct arena_stats_large_s {
|
||||
typedef struct arena_stats_decay_s arena_stats_decay_t;
|
||||
struct arena_stats_decay_s {
|
||||
/* Total number of purge sweeps. */
|
||||
arena_stats_u64_t npurge;
|
||||
locked_u64_t npurge;
|
||||
/* Total number of madvise calls made. */
|
||||
arena_stats_u64_t nmadvise;
|
||||
locked_u64_t nmadvise;
|
||||
/* Total number of pages purged. */
|
||||
arena_stats_u64_t purged;
|
||||
locked_u64_t purged;
|
||||
};
|
||||
|
||||
typedef struct arena_stats_extents_s arena_stats_extents_t;
|
||||
@@ -81,19 +70,19 @@ struct arena_stats_extents_s {
|
||||
*/
|
||||
typedef struct arena_stats_s arena_stats_t;
|
||||
struct arena_stats_s {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_t mtx;
|
||||
#endif
|
||||
LOCKEDINT_MTX_DECLARE(mtx)
|
||||
|
||||
/* Number of bytes currently mapped, excluding retained memory. */
|
||||
atomic_zu_t mapped; /* Partially derived. */
|
||||
/*
|
||||
* Number of bytes currently mapped, excluding retained memory.
|
||||
*/
|
||||
locked_zu_t mapped; /* Partially derived. */
|
||||
|
||||
/*
|
||||
* Number of unused virtual memory bytes currently retained. Retained
|
||||
* bytes are technically mapped (though always decommitted or purged),
|
||||
* but they are excluded from the mapped statistic (above).
|
||||
*/
|
||||
atomic_zu_t retained; /* Derived. */
|
||||
locked_zu_t retained; /* Derived. */
|
||||
|
||||
/* Number of edata_t structs allocated by base, but not being used. */
|
||||
atomic_zu_t edata_avail;
|
||||
@@ -107,11 +96,11 @@ struct arena_stats_s {
|
||||
atomic_zu_t metadata_thp;
|
||||
|
||||
atomic_zu_t allocated_large; /* Derived. */
|
||||
arena_stats_u64_t nmalloc_large; /* Derived. */
|
||||
arena_stats_u64_t ndalloc_large; /* Derived. */
|
||||
arena_stats_u64_t nfills_large; /* Derived. */
|
||||
arena_stats_u64_t nflushes_large; /* Derived. */
|
||||
arena_stats_u64_t nrequests_large; /* Derived. */
|
||||
locked_u64_t nmalloc_large; /* Derived. */
|
||||
locked_u64_t ndalloc_large; /* Derived. */
|
||||
locked_u64_t nfills_large; /* Derived. */
|
||||
locked_u64_t nflushes_large; /* Derived. */
|
||||
locked_u64_t nrequests_large; /* Derived. */
|
||||
|
||||
/*
|
||||
* The stats logically owned by the pa_shard in the same arena. This
|
||||
@@ -139,138 +128,32 @@ arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
assert(((char *)arena_stats)[i] == 0);
|
||||
}
|
||||
}
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
if (malloc_mutex_init(&arena_stats->mtx, "arena_stats",
|
||||
if (LOCKEDINT_MTX_INIT(LOCKEDINT_MTX(arena_stats->mtx), "arena_stats",
|
||||
WITNESS_RANK_ARENA_STATS, malloc_mutex_rank_exclusive)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
/* Memory is zeroed, so there is no need to clear stats. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_lock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_lock(tsdn, &arena_stats->mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_unlock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_unlock(tsdn, &arena_stats->mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_u64(p, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
return *p;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p, uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_u64(p, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
*p += x;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p, uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
*p -= x;
|
||||
assert(*p + x >= *p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-atomically sets *dst += src. *dst needs external synchronization.
|
||||
* This lets us avoid the cost of a fetch_add when its unnecessary (note that
|
||||
* the types here are atomic).
|
||||
*/
|
||||
static inline void
|
||||
arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED);
|
||||
atomic_store_u64(dst, src + cur_dst, ATOMIC_RELAXED);
|
||||
#else
|
||||
*dst += src;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p, size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
atomic_store_zu(p, cur + x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p, size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
atomic_store_zu(p, cur - x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Like the _u64 variant, needs an externally synchronized *dst. */
|
||||
static inline void
|
||||
arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
|
||||
size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
|
||||
atomic_store_zu(dst, src + cur_dst, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_large_flush_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
szind_t szind, uint64_t nrequests) {
|
||||
arena_stats_lock(tsdn, arena_stats);
|
||||
LOCKEDINT_MTX_LOCK(tsdn, arena_stats->mtx);
|
||||
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
|
||||
arena_stats_add_u64(tsdn, arena_stats, &lstats->nrequests, nrequests);
|
||||
arena_stats_add_u64(tsdn, arena_stats, &lstats->nflushes, 1);
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
||||
&lstats->nrequests, nrequests);
|
||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
||||
&lstats->nflushes, 1);
|
||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena_stats->mtx);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
|
||||
arena_stats_lock(tsdn, arena_stats);
|
||||
arena_stats_add_zu(tsdn, arena_stats, &arena_stats->mapped, size);
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
LOCKEDINT_MTX_LOCK(tsdn, arena_stats->mtx);
|
||||
locked_inc_zu(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
||||
&arena_stats->mapped, size);
|
||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena_stats->mtx);
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
|
||||
|
@@ -51,6 +51,20 @@
|
||||
#define ATOMIC_ACQ_REL atomic_memory_order_acq_rel
|
||||
#define ATOMIC_SEQ_CST atomic_memory_order_seq_cst
|
||||
|
||||
/*
|
||||
* Another convenience -- simple atomic helper functions.
|
||||
*/
|
||||
#define JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(type, short_type, \
|
||||
lg_size) \
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
||||
ATOMIC_INLINE void \
|
||||
atomic_load_add_store_##short_type(atomic_##short_type##_t *a, \
|
||||
type inc) { \
|
||||
type oldval = atomic_load_##short_type(a, ATOMIC_RELAXED); \
|
||||
type newval = oldval + inc; \
|
||||
atomic_store_##short_type(a, newval, ATOMIC_RELAXED); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all platforms have 64-bit atomics. If we do, this #define exposes that
|
||||
* fact.
|
||||
@@ -67,18 +81,18 @@ JEMALLOC_GENERATE_ATOMICS(void *, p, LG_SIZEOF_PTR)
|
||||
*/
|
||||
JEMALLOC_GENERATE_ATOMICS(bool, b, 0)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(unsigned, u, LG_SIZEOF_INT)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(unsigned, u, LG_SIZEOF_INT)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint8_t, u8, 0)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(uint8_t, u8, 0)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(uint32_t, u32, 2)
|
||||
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3)
|
||||
JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(uint64_t, u64, 3)
|
||||
#endif
|
||||
|
||||
#undef ATOMIC_INLINE
|
||||
|
151
include/jemalloc/internal/lockedint.h
Normal file
151
include/jemalloc/internal/lockedint.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef JEMALLOC_INTERNAL_LOCKEDINT_H
|
||||
#define JEMALLOC_INTERNAL_LOCKEDINT_H
|
||||
|
||||
/*
|
||||
* In those architectures that support 64-bit atomics, we use atomic updates for
|
||||
* our 64-bit values. Otherwise, we use a plain uint64_t and synchronize
|
||||
* externally.
|
||||
*/
|
||||
|
||||
typedef struct locked_u64_s locked_u64_t;
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
struct locked_u64_s {
|
||||
atomic_u64_t val;
|
||||
};
|
||||
#else
|
||||
/* Must hold the associated mutex. */
|
||||
struct locked_u64_s {
|
||||
uint64_t val;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct locked_zu_s locked_zu_t;
|
||||
struct locked_zu_s {
|
||||
atomic_zu_t val;
|
||||
};
|
||||
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
# define LOCKEDINT_MTX_DECLARE(name) malloc_mutex_t name;
|
||||
# define LOCKEDINT_MTX_INIT(ptr, name, rank, rank_mode) \
|
||||
malloc_mutex_init(ptr, name, rank, rank_mode)
|
||||
# define LOCKEDINT_MTX(mtx) (&(mtx))
|
||||
# define LOCKEDINT_MTX_LOCK(tsdn, mu) malloc_mutex_lock(tsdn, &(mu))
|
||||
# define LOCKEDINT_MTX_UNLOCK(tsdn, mu) malloc_mutex_unlock(tsdn, &(mu))
|
||||
#else
|
||||
# define LOCKEDINT_MTX_DECLARE(name)
|
||||
# define LOCKEDINT_MTX(ptr) NULL
|
||||
# define LOCKEDINT_MTX_INIT(ptr, name, rank, rank_mode) false
|
||||
# define LOCKEDINT_MTX_LOCK(tsdn, mu) do {} while (0)
|
||||
# define LOCKEDINT_MTX_UNLOCK(tsdn, mu) do {} while (0)
|
||||
#endif
|
||||
|
||||
static inline uint64_t
|
||||
locked_read_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_u64(&p->val, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
return p->val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
||||
uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_u64(&p->val, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
p->val += x;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
locked_dec_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
||||
uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
uint64_t r = atomic_fetch_sub_u64(&p->val, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
p->val -= x;
|
||||
assert(p->val + x >= p->val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-atomically sets *dst += src. *dst needs external synchronization.
|
||||
* This lets us avoid the cost of a fetch_add when its unnecessary (note that
|
||||
* the types here are atomic).
|
||||
*/
|
||||
static inline void
|
||||
locked_inc_u64_unsynchronized(locked_u64_t *dst, uint64_t src) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
uint64_t cur_dst = atomic_load_u64(&dst->val, ATOMIC_RELAXED);
|
||||
atomic_store_u64(&dst->val, src + cur_dst, ATOMIC_RELAXED);
|
||||
#else
|
||||
dst->val += src;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
locked_read_u64_unsynchronized(locked_u64_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_u64(&p->val, ATOMIC_RELAXED);
|
||||
#else
|
||||
return p->val;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
locked_read_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
return atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
locked_inc_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p,
|
||||
size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_zu(&p->val, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
size_t cur = atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
||||
atomic_store_zu(&p->val, cur + x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
locked_dec_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p,
|
||||
size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
size_t r = atomic_fetch_sub_zu(&p->val, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, mtx);
|
||||
size_t cur = atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
||||
atomic_store_zu(&p->val, cur - x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Like the _u64 variant, needs an externally synchronized *dst. */
|
||||
static inline void
|
||||
locked_inc_zu_unsynchronized(locked_zu_t *dst, size_t src) {
|
||||
size_t cur_dst = atomic_load_zu(&dst->val, ATOMIC_RELAXED);
|
||||
atomic_store_zu(&dst->val, src + cur_dst, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike the _u64 variant, this is safe to call unconditionally.
|
||||
*/
|
||||
static inline size_t
|
||||
locked_read_atomic_zu(locked_zu_t *p) {
|
||||
return atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_LOCKEDINT_H */
|
Reference in New Issue
Block a user