diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-02-10 17:56:48 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-02-17 10:09:30 +0100 |
commit | a38cf9fb965552c932a18c6b1b7950aed521cbe5 (patch) | |
tree | fb000b9ccd751c0d6f289df978e599e4dc97eff9 /src/libsystemd/sd-event/sd-event.c | |
parent | macro: add macro for determining size of struct with trailing union (diff) | |
download | systemd-a38cf9fb965552c932a18c6b1b7950aed521cbe5.tar.xz systemd-a38cf9fb965552c932a18c6b1b7950aed521cbe5.zip |
sd-event: allocate event source objects with the actually needed size
Currently we allocate fixed-size memory for event sources: the largest
any of the event source type needs. Discrepancy in the sizes needed for
the various event sources is quite major however: it's 144 bytes on
x86_64, i.e. more than two cache lines.
hence, let's be a tiny bit more careful, and allocate exactly as much as
we need, but not more.
Diffstat (limited to '')
-rw-r--r-- | src/libsystemd/sd-event/sd-event.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index cefe2a36b4..307fdde311 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -1075,22 +1075,46 @@ static int source_set_pending(sd_event_source *s, bool b) { } static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) { + + /* Let's allocate exactly what we need. Note that the difference of the smallest event source + * structure to the largest is 144 bytes on x86-64 at the time of writing, i.e. more than two cache + * lines. */ + static const size_t size_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { + [SOURCE_IO] = endoffsetof_field(sd_event_source, io), + [SOURCE_TIME_REALTIME] = endoffsetof_field(sd_event_source, time), + [SOURCE_TIME_BOOTTIME] = endoffsetof_field(sd_event_source, time), + [SOURCE_TIME_MONOTONIC] = endoffsetof_field(sd_event_source, time), + [SOURCE_TIME_REALTIME_ALARM] = endoffsetof_field(sd_event_source, time), + [SOURCE_TIME_BOOTTIME_ALARM] = endoffsetof_field(sd_event_source, time), + [SOURCE_SIGNAL] = endoffsetof_field(sd_event_source, signal), + [SOURCE_CHILD] = endoffsetof_field(sd_event_source, child), + [SOURCE_DEFER] = endoffsetof_field(sd_event_source, defer), + [SOURCE_POST] = endoffsetof_field(sd_event_source, post), + [SOURCE_EXIT] = endoffsetof_field(sd_event_source, exit), + [SOURCE_INOTIFY] = endoffsetof_field(sd_event_source, inotify), + }; + sd_event_source *s; assert(e); + assert(type >= 0); + assert(type < _SOURCE_EVENT_SOURCE_TYPE_MAX); + assert(size_table[type] > 0); - s = new(sd_event_source, 1); + /* We use expand_to_usable() here to tell gcc that it should consider this an object of the full + * size, even if we only allocate the initial part we need. */ + s = expand_to_usable(malloc0(size_table[type]), sizeof(sd_event_source)); if (!s) return NULL; - *s = (struct sd_event_source) { - .n_ref = 1, - .event = e, - .floating = floating, - .type = type, - .pending_index = PRIOQ_IDX_NULL, - .prepare_index = PRIOQ_IDX_NULL, - }; + /* Note: we cannot use compound initialization here, because sizeof(sd_event_source) is likely larger + * than what we allocated here. */ + s->n_ref = 1; + s->event = e; + s->floating = floating; + s->type = type; + s->pending_index = PRIOQ_IDX_NULL; + s->prepare_index = PRIOQ_IDX_NULL; if (!floating) sd_event_ref(e); |