2018-04-14 06:56:59 +08:00
|
|
|
#ifndef JEMALLOC_INTERNAL_SEQ_H
|
|
|
|
#define JEMALLOC_INTERNAL_SEQ_H
|
|
|
|
|
2023-06-10 08:37:47 +08:00
|
|
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
2018-04-14 06:56:59 +08:00
|
|
|
#include "jemalloc/internal/atomic.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A simple seqlock implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define seq_define(type, short_type) \
|
|
|
|
typedef struct { \
|
|
|
|
atomic_zu_t seq; \
|
|
|
|
atomic_zu_t data[ \
|
|
|
|
(sizeof(type) + sizeof(size_t) - 1) / sizeof(size_t)]; \
|
|
|
|
} seq_##short_type##_t; \
|
|
|
|
\
|
|
|
|
/* \
|
|
|
|
* No internal synchronization -- the caller must ensure that there's \
|
|
|
|
* only a single writer at a time. \
|
|
|
|
*/ \
|
|
|
|
static inline void \
|
|
|
|
seq_store_##short_type(seq_##short_type##_t *dst, type *src) { \
|
|
|
|
size_t buf[sizeof(dst->data) / sizeof(size_t)]; \
|
|
|
|
buf[sizeof(buf) / sizeof(size_t) - 1] = 0; \
|
|
|
|
memcpy(buf, src, sizeof(type)); \
|
|
|
|
size_t old_seq = atomic_load_zu(&dst->seq, ATOMIC_RELAXED); \
|
|
|
|
atomic_store_zu(&dst->seq, old_seq + 1, ATOMIC_RELAXED); \
|
|
|
|
atomic_fence(ATOMIC_RELEASE); \
|
|
|
|
for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \
|
|
|
|
atomic_store_zu(&dst->data[i], buf[i], ATOMIC_RELAXED); \
|
|
|
|
} \
|
|
|
|
atomic_store_zu(&dst->seq, old_seq + 2, ATOMIC_RELEASE); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
/* Returns whether or not the read was consistent. */ \
|
|
|
|
static inline bool \
|
|
|
|
seq_try_load_##short_type(type *dst, seq_##short_type##_t *src) { \
|
|
|
|
size_t buf[sizeof(src->data) / sizeof(size_t)]; \
|
|
|
|
size_t seq1 = atomic_load_zu(&src->seq, ATOMIC_ACQUIRE); \
|
|
|
|
if (seq1 % 2 != 0) { \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \
|
|
|
|
buf[i] = atomic_load_zu(&src->data[i], ATOMIC_RELAXED); \
|
|
|
|
} \
|
|
|
|
atomic_fence(ATOMIC_ACQUIRE); \
|
|
|
|
size_t seq2 = atomic_load_zu(&src->seq, ATOMIC_RELAXED); \
|
|
|
|
if (seq1 != seq2) { \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
memcpy(dst, buf, sizeof(type)); \
|
|
|
|
return true; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* JEMALLOC_INTERNAL_SEQ_H */
|