32# define SERENE_DEBUG 0
39# include <emmintrin.h>
45#define UNUSED(x) (void)(x)
53#define PANIC(msg) srn_panic(msg, __FILE__, __LINE__, __func__)
54#define TODO(msg) PANIC(msg)
55#define PANIC_WITH_CTX(ctx, msg) \
56 srn_context_release(ctx); \
59#define PANIC_IF(cond, msg) \
66#define PANIC_IF_NULL(ptr) PANIC_IF((ptr) == nullptr, "Null pointer")
67#define RETURN_IF_NULL(ptr) \
68 if ((ptr) == nullptr) { \
72#define SNPRINTF(buf, s, f, ...) \
74 int i = snprintf(buf, (s) + 1, f, __VA_ARGS__); \
76 PANIC("[snprintf] A negative return value"); \
78 if (i >= (int)(s)) { \
79 PANIC("[snprintf] Written bytes are more than expected"); \
83#define SHOULD_NOT_HAPPEN PANIC("This should not happen")
84#define PANIC_ON_ERR(interr) \
105#if defined(__clang__) || defined(__GNUC__)
106# define SRN_ATTR_COLD [[gnu::cold]]
107# define SRN_ATTR_FMT(a, b) [[gnu::format(__printf__, a, b)]]
109# define SRN_ATTR_COLD
110# define SRN_ATTR_FMT(a, b)
117# define SRN_DBG_OUT stdout
120srn_dbg_prefix(FILE *out,
const char *prefix,
const char *
file,
int line,
const char *func) {
122 int res = fprintf(out,
"[%s]%s:%d:(%s): ", prefix ==
nullptr ?
"SRN" : prefix,
file,
line, func);
129 FILE *out,
const char *prefix,
const char *
file,
int line,
const char *func,
const char *
fmt,
133 srn_dbg_prefix(out, prefix,
file,
line, func);
139 FILE *out, const
char *prefix, const
char *
file,
int line, const
char *func, const
char *
fmt, ...
144 srn_dbg_vlog(out, prefix,
file,
line, func,
fmt, ap);
149 FILE *out,
const char *
file,
int line,
const char *func,
const void *data,
size_t len
151 const unsigned char *p = (
const unsigned char *)data;
152 srn_dbg_prefix(out,
"Hexdump",
file,
line, func);
153 UNUSED(fprintf(out,
"hexdump %zu bytes\n", len));
154 for (
size_t i = 0; i < len; i += 16) {
155 UNUSED(fprintf(out,
" %08zx ", i));
156 for (
size_t j = 0; j < 16; ++j) {
158 UNUSED(fprintf(out,
"%02x ", p[i + j]));
165 for (
size_t j = 0; j < 16 && i + j < len; ++j) {
166 unsigned char c = p[i + j];
167 UNUSED(fputc((c >= 32 && c < 127) ? c :
'.', out));
173# define DBG(PREFIX, FMT, ...) \
174 srn_dbg_log(SRN_DBG_OUT, PREFIX, __FILE__, __LINE__, __func__, FMT __VA_OPT__(, ) __VA_ARGS__)
175# define DBG_HEX(PTR, LEN) \
176 srn_dbg_hexdump_here(SRN_DBG_OUT, __FILE__, __LINE__, __func__, (PTR), (LEN))
182# define DBG_HEX(...) \
185# define DBG_ASSERT(x) \
195#if defined(__clang__) || defined(__GNUC__)
196 return (uint32_t)__builtin_popcount(x);
198 x = x - ((x >> 1) & 0x55555555u);
199 x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
200 return (((x + (x >> 4)) & 0x0F0F0F0Fu) * 0x01010101u) >> 24;
205#if defined(__GNUC__) || defined(__clang__)
206 return (uint64_t)__builtin_popcountll(x);
224#if defined(_M_IX86) || defined(__I86__) || defined(i686) || defined(__i686) || \
225 defined(__i686__) || defined(i586) || defined(__i586) || defined(__i586__) || defined(i486) || \
226 defined(__i486) || defined(__i486__) || defined(i386) || defined(__i386) || defined(__i386__) || \
227 defined(_X86_) || defined(__X86__) || defined(__THW_INTEL__)
228# if defined(__SSE2__)
230# elif defined(_MSC_VER)
233 __asm__ __volatile__(
"pause");
235#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
236 defined(_M_X64) || defined(_M_AMD64)
237# if defined(__SSE2__)
240#elif defined(__aarch64__) || defined(_M_ARM64)
241# if defined(_MSC_VER)
242 __isb(_ARM64_BARRIER_SY);
244 __asm__ __volatile__(
"isb\n");
246#elif defined(__ARM_ARCH) || defined(_M_ARM) || defined(__arm__) || defined(__thumb__) || \
247 defined(__TARGET_ARCH_ARM) || defined(_ARM)
248# if defined(_MSC_VER)
251 __asm__ __volatile__(
"yield");
253#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || defined(__ppc__) || \
254 defined(__PPC__) || defined(_ARCH_PPC) || defined(__ppc)
255 __asm__ __volatile__(
"or 27,27,27" :::
"memory");
256#elif defined(__riscv) || defined(__riscv__)
257# if defined(__riscv_pause)
258 __builtin_riscv_pause();
260 __asm__ __volatile__(
"nop");
262#elif defined(__loongarch32) || defined(__loongarch64)
263 __asm__ __volatile__(
"nop");
264#elif defined(__wasm__)
265 __asm__ __volatile__(
"nop");
277 atomic_flag_clear_explicit(&lock->
flag, memory_order_release);
281 lock->
flag = (atomic_flag)ATOMIC_FLAG_INIT;
286 while (atomic_flag_test_and_set_explicit(&lock->
flag, memory_order_acquire)) {
299[[gnu::nonnull(1, 2)]]
306#define SRN_NS_PER_SEC 1000000000ULL
308#define SRN_NS_PER_MS 1000000ULL
319#define TYPE_BITS(T) (sizeof(T) * CHAR_BIT)
320#define MAX_POW2_EXP_FOR_UNSIGNED(T) (TYPE_BITS(T) - 1)
static int const char * fmt
Main memory manager structure that will own all the allocated blocks and data.
static void srn_spinlock_lock(srn_spinlock_t *lock)
uint64_t srn_now_ns(void)
The current time on the monotonic clock, in nanoseconds.
#define SRN_ATTR_FMT(a, b)
#define SHOULD_NOT_HAPPEN
static void srn_spinlock_unlock(srn_spinlock_t *lock)
char * srn_copy_bytes(const srn_context_t *ctx, const char *src, size_t len, size_t alignment)
static uint32_t srn_popcnt32(uint32_t x)
static void srn_spinlock_init(srn_spinlock_t *lock)
static uint64_t srn_popcnt64(uint64_t x)
static void cpu_relax(void)
A portable way to use pasue instructions.
char * srn_dup_str(srn_mm_t *mm, const char *s)
Copy a null terminated C string into a fresh allocation made through mm.
void srn_panic(const char *msg, const char *file, size_t line, const char *fn)
TODO(lxsameer): unwind the stack.
#define PANIC_ON_ERR(interr)