41e0b857be
Header files are now self-contained, which makes the relationships between the files clearer, and crucially allows LSP tools like `clangd` to function correctly in all of our header files. I have verified that the headers are self-contained (aside from the various Windows shims) by compiling them as if they were C files – in a follow-up commit I plan to add this to CI to ensure we don't regress on this front.
210 lines
5.7 KiB
C
210 lines
5.7 KiB
C
#ifndef JEMALLOC_INTERNAL_LOCKEDINT_H
|
|
#define JEMALLOC_INTERNAL_LOCKEDINT_H
|
|
|
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
|
#include "jemalloc/internal/atomic.h"
|
|
#include "jemalloc/internal/mutex.h"
|
|
#include "jemalloc/internal/tsd_types.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(mu, name, rank, rank_mode) \
|
|
malloc_mutex_init(&(mu), 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))
|
|
# define LOCKEDINT_MTX_PREFORK(tsdn, mu) malloc_mutex_prefork(tsdn, &(mu))
|
|
# define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu) \
|
|
malloc_mutex_postfork_parent(tsdn, &(mu))
|
|
# define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu) \
|
|
malloc_mutex_postfork_child(tsdn, &(mu))
|
|
#else
|
|
# define LOCKEDINT_MTX_DECLARE(name)
|
|
# define LOCKEDINT_MTX(mtx) NULL
|
|
# define LOCKEDINT_MTX_INIT(mu, name, rank, rank_mode) false
|
|
# define LOCKEDINT_MTX_LOCK(tsdn, mu)
|
|
# define LOCKEDINT_MTX_UNLOCK(tsdn, mu)
|
|
# define LOCKEDINT_MTX_PREFORK(tsdn, mu)
|
|
# define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu)
|
|
# define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu)
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
# define LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx) assert((mtx) == NULL)
|
|
#else
|
|
# define LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx) \
|
|
malloc_mutex_assert_owner(tsdn, (mtx))
|
|
#endif
|
|
|
|
static inline uint64_t
|
|
locked_read_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
return atomic_load_u64(&p->val, ATOMIC_RELAXED);
|
|
#else
|
|
return p->val;
|
|
#endif
|
|
}
|
|
|
|
static inline void
|
|
locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
|
uint64_t x) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
atomic_fetch_add_u64(&p->val, x, ATOMIC_RELAXED);
|
|
#else
|
|
p->val += x;
|
|
#endif
|
|
}
|
|
|
|
static inline void
|
|
locked_dec_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
|
uint64_t x) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
uint64_t r = atomic_fetch_sub_u64(&p->val, x, ATOMIC_RELAXED);
|
|
assert(r - x <= r);
|
|
#else
|
|
p->val -= x;
|
|
assert(p->val + x >= p->val);
|
|
#endif
|
|
}
|
|
|
|
/* Increment and take modulus. Returns whether the modulo made any change. */
|
|
static inline bool
|
|
locked_inc_mod_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
|
const uint64_t x, const uint64_t modulus) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
uint64_t before, after;
|
|
bool overflow;
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
before = atomic_load_u64(&p->val, ATOMIC_RELAXED);
|
|
do {
|
|
after = before + x;
|
|
assert(after >= before);
|
|
overflow = (after >= modulus);
|
|
if (overflow) {
|
|
after %= modulus;
|
|
}
|
|
} while (!atomic_compare_exchange_weak_u64(&p->val, &before, after,
|
|
ATOMIC_RELAXED, ATOMIC_RELAXED));
|
|
#else
|
|
before = p->val;
|
|
after = before + x;
|
|
overflow = (after >= modulus);
|
|
if (overflow) {
|
|
after %= modulus;
|
|
}
|
|
p->val = after;
|
|
#endif
|
|
return overflow;
|
|
}
|
|
|
|
/*
|
|
* 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 void
|
|
locked_init_u64_unsynchronized(locked_u64_t *p, uint64_t x) {
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
atomic_store_u64(&p->val, x, ATOMIC_RELAXED);
|
|
#else
|
|
p->val = x;
|
|
#endif
|
|
}
|
|
|
|
static inline size_t
|
|
locked_read_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
return atomic_load_zu(&p->val, ATOMIC_RELAXED);
|
|
#else
|
|
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) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
atomic_fetch_add_zu(&p->val, x, ATOMIC_RELAXED);
|
|
#else
|
|
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) {
|
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
size_t r = atomic_fetch_sub_zu(&p->val, x, ATOMIC_RELAXED);
|
|
assert(r - x <= r);
|
|
#else
|
|
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 */
|