Home | History | Annotate | Line # | Download | only in internal
      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