1 #ifndef JEMALLOC_INTERNAL_SEQ_H 2 #define JEMALLOC_INTERNAL_SEQ_H 3 4 #include "jemalloc/internal/atomic.h" 5 6 /* 7 * A simple seqlock implementation. 8 */ 9 10 #define seq_define(type, short_type) \ 11 typedef struct { \ 12 atomic_zu_t seq; \ 13 atomic_zu_t data[ \ 14 (sizeof(type) + sizeof(size_t) - 1) / sizeof(size_t)]; \ 15 } seq_##short_type##_t; \ 16 \ 17 /* \ 18 * No internal synchronization -- the caller must ensure that there's \ 19 * only a single writer at a time. \ 20 */ \ 21 static inline void \ 22 seq_store_##short_type(seq_##short_type##_t *dst, type *src) { \ 23 size_t buf[sizeof(dst->data) / sizeof(size_t)]; \ 24 buf[sizeof(buf) / sizeof(size_t) - 1] = 0; \ 25 memcpy(buf, src, sizeof(type)); \ 26 size_t old_seq = atomic_load_zu(&dst->seq, ATOMIC_RELAXED); \ 27 atomic_store_zu(&dst->seq, old_seq + 1, ATOMIC_RELAXED); \ 28 atomic_fence(ATOMIC_RELEASE); \ 29 for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \ 30 atomic_store_zu(&dst->data[i], buf[i], ATOMIC_RELAXED); \ 31 } \ 32 atomic_store_zu(&dst->seq, old_seq + 2, ATOMIC_RELEASE); \ 33 } \ 34 \ 35 /* Returns whether or not the read was consistent. */ \ 36 static inline bool \ 37 seq_try_load_##short_type(type *dst, seq_##short_type##_t *src) { \ 38 size_t buf[sizeof(src->data) / sizeof(size_t)]; \ 39 size_t seq1 = atomic_load_zu(&src->seq, ATOMIC_ACQUIRE); \ 40 if (seq1 % 2 != 0) { \ 41 return false; \ 42 } \ 43 for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \ 44 buf[i] = atomic_load_zu(&src->data[i], ATOMIC_RELAXED); \ 45 } \ 46 atomic_fence(ATOMIC_ACQUIRE); \ 47 size_t seq2 = atomic_load_zu(&src->seq, ATOMIC_RELAXED); \ 48 if (seq1 != seq2) { \ 49 return false; \ 50 } \ 51 memcpy(dst, buf, sizeof(type)); \ 52 return true; \ 53 } 54 55 #endif /* JEMALLOC_INTERNAL_SEQ_H */ 56