From: Lennart Poettering Date: Fri, 10 Feb 2023 16:56:48 +0000 (+0100) Subject: sd-event: allocate event source objects with the actually needed size X-Git-Tag: v254-rc1~1249^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a38cf9fb965552c932a18c6b1b7950aed521cbe5;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index cefe2a36b4f..307fdde311d 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);