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) \
11typedef 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 */ \
21static inline void \
22seq_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. */ \
36static inline bool \
37seq_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