Skip to content

Commit

Permalink
Support for static constructors with priorities
Browse files Browse the repository at this point in the history
Instead of relying on __attribute__((constructor)), use our own system
that should work everywhere -- regardless of the C standard library, or
the system supporting them.

As a bonus, each constructor now gets a pointer to a Lwan struct, making
it easier to install initialization hooks.
  • Loading branch information
lpereira committed Aug 29, 2024
1 parent 9f37366 commit cac0dd8
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 53 deletions.
50 changes: 18 additions & 32 deletions src/bin/tools/bin2hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@

#include "lwan-private.h"

static int constructor_attr_supported = 0;

LWAN_CONSTRUCTOR()
static void initialize_constructor_attr_supported(void)
{
constructor_attr_supported = 1;
}

static int bin2hex_mmap(const char *path, const char *identifier)
{
int fd = open(path, O_RDONLY | O_CLOEXEC);
Expand Down Expand Up @@ -104,15 +96,12 @@ static int bin2hex(const char *path, const char *identifier)

printf("\n/* Contents of %s available through %s_value */\n", path, identifier);

if (constructor_attr_supported) {
printf("#if defined(__GNUC__) || defined(__clang__)\n");
r |= bin2hex_incbin(path, identifier);
printf("#else\n");
r |= bin2hex_mmap(path, identifier);
printf("#endif\n\n");
} else {
r |= bin2hex_mmap(path, identifier);
}
printf("#if defined(__GNUC__) || defined(__clang__)\n");
r |= bin2hex_incbin(path, identifier);
printf("#else\n");
r |= bin2hex_mmap(path, identifier);
printf("#endif\n\n");

return r;
}

Expand All @@ -133,7 +122,7 @@ int main(int argc, char *argv[])

printf("/* Auto generated by %s, do not edit. */\n", argv[0]);
printf("#pragma once\n\n");
printf("#include \"lwan.h\"\n");
printf("#include \"lwan-private.h\"\n");

for (arg = 1; arg < argc; arg += 2) {
const char *path = argv[arg];
Expand All @@ -146,21 +135,18 @@ int main(int argc, char *argv[])
}
}

if (constructor_attr_supported) {
printf("#if defined(__GNUC__) || defined(__clang__)\n");
printf("__attribute__((constructor (101))) static void\n");
printf("initialize_bin2hex_%016lx(void)\n", (uintptr_t)argv);
printf("{\n");
for (arg = 1; arg < argc; arg += 2) {
const char *identifier = argv[arg + 1];

printf(" %s_value = (struct lwan_value) {.value = (char *)%s_start, "
".len = (size_t)(%s_end - %s_start)};\n",
identifier, identifier, identifier, identifier);
}
printf("}\n");
printf("#endif\n");
printf("#if defined(__GNUC__) || defined(__clang__)\n");
printf("LWAN_CONSTRUCTOR(bin2hex_%016lx, 0)\n", (uintptr_t)argv);
printf("{\n");
for (arg = 1; arg < argc; arg += 2) {
const char *identifier = argv[arg + 1];

printf(" %s_value = (struct lwan_value) {.value = (char *)%s_start, "
".len = (size_t)(%s_end - %s_start)};\n",
identifier, identifier, identifier, identifier);
}
printf("}\n");
printf("#endif\n");

return 0;
}
3 changes: 1 addition & 2 deletions src/lib/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ static inline unsigned int hash_int64_crc32(const void *keyptr)

#endif

LWAN_CONSTRUCTOR(65535)
static void initialize_fnv1a_seed(void)
LWAN_CONSTRUCTOR(fnv1a_seed, 65535)
{
uint8_t entropy[128];

Expand Down
4 changes: 1 addition & 3 deletions src/lib/lwan-lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,7 @@ static int luaopen_log(lua_State *L)
DEFINE_ARRAY_TYPE(lwan_lua_method_array, luaL_reg)
static struct lwan_lua_method_array lua_methods;

LWAN_CONSTRUCTOR()
__attribute__((no_sanitize_address))
static void register_lua_methods(void)
LWAN_CONSTRUCTOR(register_lua_methods, 0)
{
const struct lwan_lua_method_info *info;
luaL_reg *r;
Expand Down
20 changes: 15 additions & 5 deletions src/lib/lwan-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,21 @@
#define DEFAULT_BUFFER_SIZE 4096
#define DEFAULT_HEADERS_SIZE 2048

#if defined(__APPLE__)
# define LWAN_CONSTRUCTOR(prio_) __attribute__((constructor))
#else
# define LWAN_CONSTRUCTOR(prio_) __attribute__((constructor(prio_)))
#endif
struct lwan_constructor_callback_info {
void (*func)(struct lwan *);
int prio;
};

#define LWAN_CONSTRUCTOR(name_, prio_) \
__attribute__((no_sanitize_address)) static void lwan_constructor_##name_( \
struct lwan *l __attribute__((unused))); \
static const struct lwan_constructor_callback_info __attribute__(( \
used, section(LWAN_SECTION_NAME( \
lwan_constructor)))) lwan_constructor_info_##name_ = { \
.func = lwan_constructor_##name_, \
.prio = (prio_), \
}; \
static ALWAYS_INLINE void lwan_constructor_##name_(struct lwan *l)

struct lwan_request_parser_helper {
struct lwan_value *buffer; /* The whole request buffer */
Expand Down
3 changes: 1 addition & 2 deletions src/lib/lwan-readahead.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ static pthread_t readahead_self;
static long page_size = PAGE_SIZE;

#ifdef _SC_PAGESIZE
LWAN_CONSTRUCTOR()
static void get_page_size(void)
LWAN_CONSTRUCTOR(get_page_size, 0)
{
long ps = sysconf(_SC_PAGESIZE);

Expand Down
3 changes: 1 addition & 2 deletions src/lib/lwan-request.c
Original file line number Diff line number Diff line change
Expand Up @@ -1112,8 +1112,7 @@ get_temp_dir(void)
return NULL;
}

LWAN_CONSTRUCTOR()
static void initialize_temp_dir(void)
LWAN_CONSTRUCTOR(initialize_temp_dir, 0)
{
temp_dir = get_temp_dir();
}
Expand Down
3 changes: 1 addition & 2 deletions src/lib/lwan-status.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,7 @@ void lwan_syslog_status_out(
lwan_strbuf_free(&buf);
}

LWAN_CONSTRUCTOR()
static void register_lwan_to_syslog(void)
LWAN_CONSTRUCTOR(register_lwan_to_syslog, 0)
{
openlog("lwan", LOG_NDELAY | LOG_PID | LOG_CONS, LOG_USER);
}
Expand Down
38 changes: 36 additions & 2 deletions src/lib/lwan.c
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,39 @@ static char *dup_or_null(const char *s)
return s ? strdup(s) : NULL;
}

DEFINE_ARRAY_TYPE(constructor_array, struct lwan_constructor_callback_info)

static int constructor_sort(const void *a, const void *b)
{
const struct lwan_constructor_callback_info *ca = a;
const struct lwan_constructor_callback_info *cb = b;
return (ca->prio < cb->prio) - (ca->prio > cb->prio);
}

__attribute__((no_sanitize_address)) static void
call_constructors(struct lwan *l)
{
struct constructor_array constructors;
const struct lwan_constructor_callback_info *iter;

constructor_array_init(&constructors);
LWAN_SECTION_FOREACH(lwan_constructor, iter)
{
struct lwan_constructor_callback_info *info =
constructor_array_append(&constructors);
if (!info)
lwan_status_critical("Could not append to constructor array");
*info = *iter;
}
constructor_array_sort(&constructors, constructor_sort);

LWAN_ARRAY_FOREACH (&constructors, iter) {
iter->func(l);
}

constructor_array_reset(&constructors);
}

void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
{
/* Load defaults */
Expand All @@ -883,6 +916,8 @@ void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
* their initialization. */
lwan_status_init(l);

call_constructors(l);

/* These will only print debugging messages. Debug messages are always
* printed if we're on a debug build, so the quiet setting will be
* respected. */
Expand Down Expand Up @@ -975,8 +1010,7 @@ void lwan_main_loop(struct lwan *l)
}

#ifdef CLOCK_MONOTONIC_COARSE
LWAN_CONSTRUCTOR()
static void detect_fastest_monotonic_clock(void)
LWAN_CONSTRUCTOR(detect_fastest_monotonic_clock, 0)
{
struct timespec ts;

Expand Down
2 changes: 1 addition & 1 deletion src/samples/clock/blocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ static const struct fall *fall[] = {

static int block_sizes[10];

LWAN_CONSTRUCTOR() void calculate_block_sizes(void)
LWAN_CONSTRUCTOR(calculate_block_sizes, 0)
{
for (int i = 0; i < 10; i++) {
const struct fall *instr = fall[i];
Expand Down
2 changes: 1 addition & 1 deletion src/samples/clock/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ static const struct lwan_var_descriptor index_desc[] = {

static struct lwan_tpl *index_tpl;

LWAN_CONSTRUCTOR() static void initialize_template(void)
LWAN_CONSTRUCTOR(initialize_template, 0)
{
static const char index[] =
"<html>\n"
Expand Down
2 changes: 1 addition & 1 deletion src/samples/clock/xdaliclock.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ frame_from_pixmap(const unsigned char *bits, int width, int height)
return frame;
}

LWAN_CONSTRUCTOR() static void initialize_numbers(void)
LWAN_CONSTRUCTOR(initialize_numbers, 0)
{
const struct raw_number *raw = get_raw_numbers();

Expand Down

0 comments on commit cac0dd8

Please sign in to comment.