We replace the implicit single callback and wait-future indirection with the usual slot design so independent fibers and future groups can track the same future. We also opt to always have callbacks dispatch asynchronously, including when they are registered after the future has already resolved. We now require futures to be resolved before their final unref rather than cancelling them implicitly. The idea is to catch bugs rather than leak futures. A future should always be cancelled and awaited before it is cleaned up, otherwise resources might leak if the stack is not unwound properly. We make exceptions for futures that haven't started executing yet as there's no risk of leaking resources there since there's no stack to unwind. One issue with awaiting futures is that sd_fiber_await() returned both errors and the future's result via the function's return value, meaning it was impossible to distinguish future failures from interrupted waits (or waits that failed for whatever other reason). This is generally not an issue except in the cleanup functions, where we have to retry on interrupted waits (the best example is a parent fiber waiting for a future being cancelled itself, which should cancel the future it's waiting for and retry the wait). So we introduce fiber_wait() which distinguishes between both values via return value and output argument so the two can be distinguished from each other. Cleanup always consumes the caller's reference, including on invalid self or cross-loop waits. The existing assertion still forbids dropping the last reference to an unresolved future. The installed header documents this rule. We introduce a new RUNNING fiber state to distinguish executing fibers from non-executing fibers. We replace CANCELLED with queued resume results and preserve interruptions across ordinary wakeups. We add future groups with wait-all, wait-any and ignore-errors policies to wait for multiple futures at once and migrate various existing call sites over to them. Group size is a direct size_t query, treating NULL as an empty group. Document all four policy combinations, including that IGNORE_ERRORS suppresses fail-fast and parent cancellation without discarding the group's error result. We also add defer futures and migrate bus, varlink, QMP and fiber I/O callers to use them. Bus and QMP futures report -ENOPKG when no event loop is attached, rather than passing NULL to sd_future_new() and returning -EINVAL. Parent-await suppression is derived from the active wait's callback slot, so groups use sd_fiber_await() without a separate await API or additional state. Waits, group children and captured parents must use the same event loop. Groups created on another loop have no parent, and a group releases its parent reference when that fiber finishes. Resolve SD_EVENT_DEFAULT in sd_future_new() so futures retain the actual loop. Match group parents against that resolved loop as well; an unavailable default returns -ENOPKG without creating an event loop implicitly. Keep the public await entry point in fiber.c, sharing the slot-based wait with cancellation cleanup through future-internal.h. Keep event/future integration in event-future.c/h: priority inheritance uses the public fiber accessor, and sd_future_new_defer() lives alongside the other event-backed constructors. This avoids sd-event depending on sd-future private headers and removes the redundant private defer wrapper. Assert the non-failing slot-disabling and active-loop invariants instead of returning early without completing callback dispatch. Regression tests cover group error propagation and NULL-safe size queries, interrupted waits, partial add-many rollback, groups outliving their parent, and cancellation or timeout during nested event-loop waits, including event-loop and descriptor cleanup. They also cover cross-loop parent isolation, reference release on invalid cleanup calls, mixed WAIT_ANY outcomes, failed child cancellation and policy changes on resolved groups. Additional tests verify failed group-priority updates, slot priority during dispatch and exit, and cancellation, timeout and spurious wakeups during bus and QMP calls. Late replies must leave subsequent calls unaffected. Default-event tests cover missing-loop errors, reference lifetime and parent capture by constructors. Unattached bus and QMP clients are covered by missing-event-loop regressions. Constructor tests verify inherited and default priorities for I/O, defer and timer futures, plus defer argument validation and missing-default errors. Signed-off-by: Daan De Meyer <daan@amutable.com>
System and Service Manager
Details
Most documentation is available on systemd's website.
Assorted, older, general information about systemd can be found in the systemd Wiki.
Information about build requirements is provided in the README file.
Consult our NEWS file for information about what's new in the most recent systemd versions.
Please see the Code Map for information about this repository's layout and content.
Please see the Hacking guide for information on how to hack on systemd and test your modifications.
Please see our Contribution Guidelines for more information about filing GitHub Issues and posting GitHub Pull Requests.
When preparing patches for systemd, please follow our Coding Style Guidelines.
If you are looking for support, please contact our mailing list, join our IRC channel #systemd on libera.chat or Matrix channel
Stable branches with backported patches are available in the stable repo.
We have a security bug bounty program sponsored by the Sovereign Tech Fund hosted on YesWeHack
Repositories with distribution packages built from git main are available on OBS, and also repositories with packages built from the latest stable release
