sslbd/common.hpp
#pragma once
#include "conf/config.inc"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#ifndef NDEBUG
#define DEBUG
#endif
#define strnchr(s, c, n) (char*)memchr(s, c, n)
#define cstrlen(cstr) (sizeof(cstr)-1)
#define strccpy(p, cstr) strcpy(p, cstr) + cstrlen(cstr)
extern time_t* BEFORE_NOW; // for obfuscating NOW acesses only
extern time_t NOW;
typedef uint64_t msec_t;
extern msec_t NOW_MSEC;
extern char NOW_STR[cstrlen("Sun Sep 16 01:03:52 1973")+1]; // some stray newline
void update_now();
#define msleep(ms) usleep((ms)*1000)
extern int RECONFIGURE;
extern int CLEANUP;
extern enum shutdown_e {SHUTDOWN_NONE=0, SHUTDOWN_GRACEFUL=1, SHUTDOWN_NOW=2} SHUTDOWN;
const char* src_basename(const char*);
int null_fd();
typedef enum tristate_e {TRI_FALSE=0, TRI_TRUE=1, TRI_NONE=-1} tristate_t;
#define bi2tri(bi) ((bi)? TRI_TRUE: TRI_FALSE)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define unless(x) if (unlikely(!(x)))
#define NOOP do{}while(0)
#define VAL(x) #x
#define STRINGIFY(x) VAL(x)
#define _PRAGMA(x) _Pragma(#x)
#define MESSAGE(x) _PRAGMA(message(#x))
#define ALWAYS_INLINE inline __attribute__((always_inline))
#ifdef NDEBUG
#define INLINE ALWAYS_INLINE
#else
#define INLINE // for better stacktraces and/or profiling
#endif
#define is_noop_errno(rv) ((rv) == -1 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
#define TERM_RED "\x1B[31m"
#define TERM_GREEN "\x1B[32m"
#define TERM_RESET "\033[0m"
typedef const char* loglevel_t;
extern struct loglevels_s {
loglevel_t io, debug, info, notice, error;
} loglevels;
extern loglevel_t* loglevel;
typedef struct {
const unsigned* no;
const int* cfd;
const int* sfd;
} logctx_t;
extern const logctx_t* logctx;
class LogCtx {
private:
const logctx_t* bup;
public:
INLINE LogCtx(const logctx_t* l): bup(logctx) { logctx = l; }
INLINE ~LogCtx() { logctx = bup; }
};
bool in_main_thread();
void log_bt(int fd=-1);
#define STDERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
//#define log_ts(...) log(__VA_ARGS__) // TODO: need threadsafe logging?
#define log(lvl, fmt, ...) log_(&(loglevels.lvl), fmt, ##__VA_ARGS__)
#define log_(lvl, fmt, ...) if (unlikely(lvl >= loglevel)) { if (logctx) log__(lvl, "[%u/%d/%d] " fmt, *(logctx->no), *(logctx->cfd), *(logctx->sfd), ##__VA_ARGS__); else log__(lvl, fmt, ##__VA_ARGS__); } else NOOP
#define log__(lvl, fmt, ...) STDERR("%s %d %s " fmt, NOW_STR, (int)getpid(), *(lvl), ##__VA_ARGS__)
#define die(fmt, ...) do{log(error, fmt " - DYING", ##__VA_ARGS__); exit(1);}while(0)
#define log_errno(lvl, fmt, ...) log(lvl, fmt " - %d: %s", ##__VA_ARGS__, errno, strerror(errno))
#define die_errno(fmt, ...) die(fmt " - %d: %s", ##__VA_ARGS__, errno, strerror(errno))
#define log_mark(lvl) log(lvl, "[%s:%d] %s", src_basename(__FILE__), __LINE__, __PRETTY_FUNCTION__)
#define log_access(fmt, ...) log(notice, fmt, ##__VA_ARGS__)
#define talloc(t) (t*)malloc(sizeof(t))
#define tcalloc(t) (t*)calloc(1, sizeof(t))
#define MIN(a, b) (((a)<(b))?(a):(b))
#define MAX(a, b) (((a)>(b))?(a):(b))
#define ABS(x) (((x)<0)?-(x):(x))
#define CONCAT_(a, b) a ## b
#define CONCAT(a, b) CONCAT_(a, b)
#ifndef NULL
#define NULL ((void*)0)
#endif
#define NOPE ((void*)-1)
#define safe_free(p) do { if (p) { free(p); p = NULL; } } while (0)
#define safe_delete(p) do { if (p) { delete p; p = NULL; } } while (0)
#define member_sizeof(t, m) sizeof(((t*)NULL)->m)
#define member_offset(t, m) ((&((t*)NULL)->m)) ///< offsetof
//#define member_offset(t, m) ((size_t)(&((t*)sizeof(t))->m) - sizeof(t)) ///< offsetof but w/o NULL ptr
#define EINTR_RETRY(func) while (unlikely(((func) == -1) && (errno == EINTR))) {}
typedef sig_atomic_t atomic_val_t;
typedef volatile atomic_val_t atomic_t;
#define mem_barrier() asm volatile("": : :"memory")
#ifdef __arm__
#define cpu_relax() do { usleep(100); asm volatile("": : :"memory"); } while (0) // TODO: could use ARM yield?
#else
#define cpu_relax() asm volatile("pause\n": : :"memory")
#endif
#define atomic_swp(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
#define atomic_add(p, v) __sync_add_and_fetch((p), (v))
#define atomic_get_and_reset(p) __sync_fetch_and_and((p), 0)
ALWAYS_INLINE void spin_lock(atomic_t* l) { while (unlikely(!atomic_swp(l, 0, 1))) { while (*l) cpu_relax(); } }
ALWAYS_INLINE void spin_unlock(atomic_t* l) { mem_barrier(); assert(*l); *l = 0; }
class SpinLock {
private:
atomic_t* lock;
public:
INLINE SpinLock(atomic_t* l): lock(l) { spin_lock(lock); }
INLINE ~SpinLock() { spin_unlock(lock); }
};
//#define CONSTRUCTOR __attribute__((constructor)) // a constructor with a priority runs before a constructor without a priority
//#define CONSTRUCTOR_EARLY __attribute__((constructor(101)))
//#define CONSTRUCTOR_LATE __attribute__((constructor(65535)))
//#define DESTRUCTOR __attribute__((destructor)) // a destructor with a priority runs before a destructor without a priority
//#define DESTRUCTOR_EARLY __attribute__((destructor(65535)))
//#define DESTRUCTOR_LATE __attribute__((destructor(101)))
#define UNUSED __attribute__((unused))
#define PACKED __attribute__((packed))
#define INIT_EARLY __attribute__((init_priority(101)))
#define INIT_LATE __attribute__((init_priority(65535)))
//#define THREAD_LOCAL __thread
/*#ifdef NDEBUG
#define BOOT_INFO(fmt, ...) UNUSED static bool CONCAT(BOOT_INFO_, __LINE__)()
#else
#define BOOT_INFO(fmt, ...) static void CONSTRUCTOR CONCAT(BOOT_INFO_, __LINE__)() { STDERR("INFO: " fmt, ##__VA_ARGS__); }
#endif*/