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