summaryrefslogtreecommitdiffstats
path: root/src/libsystemd/sd-event/sd-event.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-02-10 17:56:48 +0100
committerLennart Poettering <lennart@poettering.net>2023-02-17 10:09:30 +0100
commita38cf9fb965552c932a18c6b1b7950aed521cbe5 (patch)
treefb000b9ccd751c0d6f289df978e599e4dc97eff9 /src/libsystemd/sd-event/sd-event.c
parentmacro: add macro for determining size of struct with trailing union (diff)
downloadsystemd-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.c42
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);