Blame jemalloc/include/jemalloc/internal/seq.h

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