Skip to content

Commit cac0dd8

Browse files
committed
Support for static constructors with priorities
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.
1 parent 9f37366 commit cac0dd8

11 files changed

+77
-53
lines changed

src/bin/tools/bin2hex.c

+18-32
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@
2828

2929
#include "lwan-private.h"
3030

31-
static int constructor_attr_supported = 0;
32-
33-
LWAN_CONSTRUCTOR()
34-
static void initialize_constructor_attr_supported(void)
35-
{
36-
constructor_attr_supported = 1;
37-
}
38-
3931
static int bin2hex_mmap(const char *path, const char *identifier)
4032
{
4133
int fd = open(path, O_RDONLY | O_CLOEXEC);
@@ -104,15 +96,12 @@ static int bin2hex(const char *path, const char *identifier)
10496

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

107-
if (constructor_attr_supported) {
108-
printf("#if defined(__GNUC__) || defined(__clang__)\n");
109-
r |= bin2hex_incbin(path, identifier);
110-
printf("#else\n");
111-
r |= bin2hex_mmap(path, identifier);
112-
printf("#endif\n\n");
113-
} else {
114-
r |= bin2hex_mmap(path, identifier);
115-
}
99+
printf("#if defined(__GNUC__) || defined(__clang__)\n");
100+
r |= bin2hex_incbin(path, identifier);
101+
printf("#else\n");
102+
r |= bin2hex_mmap(path, identifier);
103+
printf("#endif\n\n");
104+
116105
return r;
117106
}
118107

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

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

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

149-
if (constructor_attr_supported) {
150-
printf("#if defined(__GNUC__) || defined(__clang__)\n");
151-
printf("__attribute__((constructor (101))) static void\n");
152-
printf("initialize_bin2hex_%016lx(void)\n", (uintptr_t)argv);
153-
printf("{\n");
154-
for (arg = 1; arg < argc; arg += 2) {
155-
const char *identifier = argv[arg + 1];
156-
157-
printf(" %s_value = (struct lwan_value) {.value = (char *)%s_start, "
158-
".len = (size_t)(%s_end - %s_start)};\n",
159-
identifier, identifier, identifier, identifier);
160-
}
161-
printf("}\n");
162-
printf("#endif\n");
138+
printf("#if defined(__GNUC__) || defined(__clang__)\n");
139+
printf("LWAN_CONSTRUCTOR(bin2hex_%016lx, 0)\n", (uintptr_t)argv);
140+
printf("{\n");
141+
for (arg = 1; arg < argc; arg += 2) {
142+
const char *identifier = argv[arg + 1];
143+
144+
printf(" %s_value = (struct lwan_value) {.value = (char *)%s_start, "
145+
".len = (size_t)(%s_end - %s_start)};\n",
146+
identifier, identifier, identifier, identifier);
163147
}
148+
printf("}\n");
149+
printf("#endif\n");
164150

165151
return 0;
166152
}

src/lib/hash.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,7 @@ static inline unsigned int hash_int64_crc32(const void *keyptr)
208208

209209
#endif
210210

211-
LWAN_CONSTRUCTOR(65535)
212-
static void initialize_fnv1a_seed(void)
211+
LWAN_CONSTRUCTOR(fnv1a_seed, 65535)
213212
{
214213
uint8_t entropy[128];
215214

src/lib/lwan-lua.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,7 @@ static int luaopen_log(lua_State *L)
425425
DEFINE_ARRAY_TYPE(lwan_lua_method_array, luaL_reg)
426426
static struct lwan_lua_method_array lua_methods;
427427

428-
LWAN_CONSTRUCTOR()
429-
__attribute__((no_sanitize_address))
430-
static void register_lua_methods(void)
428+
LWAN_CONSTRUCTOR(register_lua_methods, 0)
431429
{
432430
const struct lwan_lua_method_info *info;
433431
luaL_reg *r;

src/lib/lwan-private.h

+15-5
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,21 @@
2828
#define DEFAULT_BUFFER_SIZE 4096
2929
#define DEFAULT_HEADERS_SIZE 2048
3030

31-
#if defined(__APPLE__)
32-
# define LWAN_CONSTRUCTOR(prio_) __attribute__((constructor))
33-
#else
34-
# define LWAN_CONSTRUCTOR(prio_) __attribute__((constructor(prio_)))
35-
#endif
31+
struct lwan_constructor_callback_info {
32+
void (*func)(struct lwan *);
33+
int prio;
34+
};
35+
36+
#define LWAN_CONSTRUCTOR(name_, prio_) \
37+
__attribute__((no_sanitize_address)) static void lwan_constructor_##name_( \
38+
struct lwan *l __attribute__((unused))); \
39+
static const struct lwan_constructor_callback_info __attribute__(( \
40+
used, section(LWAN_SECTION_NAME( \
41+
lwan_constructor)))) lwan_constructor_info_##name_ = { \
42+
.func = lwan_constructor_##name_, \
43+
.prio = (prio_), \
44+
}; \
45+
static ALWAYS_INLINE void lwan_constructor_##name_(struct lwan *l)
3646

3747
struct lwan_request_parser_helper {
3848
struct lwan_value *buffer; /* The whole request buffer */

src/lib/lwan-readahead.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ static pthread_t readahead_self;
6060
static long page_size = PAGE_SIZE;
6161

6262
#ifdef _SC_PAGESIZE
63-
LWAN_CONSTRUCTOR()
64-
static void get_page_size(void)
63+
LWAN_CONSTRUCTOR(get_page_size, 0)
6564
{
6665
long ps = sysconf(_SC_PAGESIZE);
6766

src/lib/lwan-request.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,7 @@ get_temp_dir(void)
11121112
return NULL;
11131113
}
11141114

1115-
LWAN_CONSTRUCTOR()
1116-
static void initialize_temp_dir(void)
1115+
LWAN_CONSTRUCTOR(initialize_temp_dir, 0)
11171116
{
11181117
temp_dir = get_temp_dir();
11191118
}

src/lib/lwan-status.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,7 @@ void lwan_syslog_status_out(
243243
lwan_strbuf_free(&buf);
244244
}
245245

246-
LWAN_CONSTRUCTOR()
247-
static void register_lwan_to_syslog(void)
246+
LWAN_CONSTRUCTOR(register_lwan_to_syslog, 0)
248247
{
249248
openlog("lwan", LOG_NDELAY | LOG_PID | LOG_CONS, LOG_USER);
250249
}

src/lib/lwan.c

+36-2
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,39 @@ static char *dup_or_null(const char *s)
869869
return s ? strdup(s) : NULL;
870870
}
871871

872+
DEFINE_ARRAY_TYPE(constructor_array, struct lwan_constructor_callback_info)
873+
874+
static int constructor_sort(const void *a, const void *b)
875+
{
876+
const struct lwan_constructor_callback_info *ca = a;
877+
const struct lwan_constructor_callback_info *cb = b;
878+
return (ca->prio < cb->prio) - (ca->prio > cb->prio);
879+
}
880+
881+
__attribute__((no_sanitize_address)) static void
882+
call_constructors(struct lwan *l)
883+
{
884+
struct constructor_array constructors;
885+
const struct lwan_constructor_callback_info *iter;
886+
887+
constructor_array_init(&constructors);
888+
LWAN_SECTION_FOREACH(lwan_constructor, iter)
889+
{
890+
struct lwan_constructor_callback_info *info =
891+
constructor_array_append(&constructors);
892+
if (!info)
893+
lwan_status_critical("Could not append to constructor array");
894+
*info = *iter;
895+
}
896+
constructor_array_sort(&constructors, constructor_sort);
897+
898+
LWAN_ARRAY_FOREACH (&constructors, iter) {
899+
iter->func(l);
900+
}
901+
902+
constructor_array_reset(&constructors);
903+
}
904+
872905
void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
873906
{
874907
/* Load defaults */
@@ -883,6 +916,8 @@ void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
883916
* their initialization. */
884917
lwan_status_init(l);
885918

919+
call_constructors(l);
920+
886921
/* These will only print debugging messages. Debug messages are always
887922
* printed if we're on a debug build, so the quiet setting will be
888923
* respected. */
@@ -975,8 +1010,7 @@ void lwan_main_loop(struct lwan *l)
9751010
}
9761011

9771012
#ifdef CLOCK_MONOTONIC_COARSE
978-
LWAN_CONSTRUCTOR()
979-
static void detect_fastest_monotonic_clock(void)
1013+
LWAN_CONSTRUCTOR(detect_fastest_monotonic_clock, 0)
9801014
{
9811015
struct timespec ts;
9821016

src/samples/clock/blocks.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ static const struct fall *fall[] = {
176176

177177
static int block_sizes[10];
178178

179-
LWAN_CONSTRUCTOR() void calculate_block_sizes(void)
179+
LWAN_CONSTRUCTOR(calculate_block_sizes, 0)
180180
{
181181
for (int i = 0; i < 10; i++) {
182182
const struct fall *instr = fall[i];

src/samples/clock/main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ static const struct lwan_var_descriptor index_desc[] = {
245245

246246
static struct lwan_tpl *index_tpl;
247247

248-
LWAN_CONSTRUCTOR() static void initialize_template(void)
248+
LWAN_CONSTRUCTOR(initialize_template, 0)
249249
{
250250
static const char index[] =
251251
"<html>\n"

src/samples/clock/xdaliclock.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ frame_from_pixmap(const unsigned char *bits, int width, int height)
155155
return frame;
156156
}
157157

158-
LWAN_CONSTRUCTOR() static void initialize_numbers(void)
158+
LWAN_CONSTRUCTOR(initialize_numbers, 0)
159159
{
160160
const struct raw_number *raw = get_raw_numbers();
161161

0 commit comments

Comments
 (0)