diff --git a/src/basic/list.h b/src/basic/list.h index e4e5dff3ea..497d116387 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -192,6 +192,18 @@ _p; \ }) +#define LIST_CLEAR(name, head, free_func) \ + _LIST_CLEAR(name, head, free_func, UNIQ_T(elem, UNIQ)) + +/* Clear the list, destroing each element with free_func */ +#define _LIST_CLEAR(name, head, free_func, elem) \ + ({ \ + typeof(head) elem; \ + while ((elem = LIST_POP(name, head))) \ + free_func(elem); \ + head; \ + }) + /* Now include "macro.h", because we want our definition of assert() which the macros above use. We include * it down here instead of up top, since macro.h pulls in log.h which in turn needs our own definitions. */ #include "macro.h" diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 2ccfcbad72..91ef33b12c 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -247,11 +247,7 @@ void cgroup_context_remove_bpf_foreign_program(CGroupContext *c, CGroupBPFForeig void cgroup_context_remove_socket_bind(CGroupSocketBindItem **head) { assert(head); - while (*head) { - CGroupSocketBindItem *h = *head; - LIST_REMOVE(socket_bind_items, *head, h); - free(h); - } + LIST_CLEAR(socket_bind_items, *head, free); } void cgroup_context_done(CGroupContext *c) { diff --git a/src/core/execute.c b/src/core/execute.c index 95349a4fb6..f9761b7239 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -6326,8 +6326,7 @@ void exec_command_done_array(ExecCommand *c, size_t n) { ExecCommand* exec_command_free_list(ExecCommand *c) { ExecCommand *i; - while ((i = c)) { - LIST_REMOVE(command, c, i); + while ((i = LIST_POP(command, c))) { exec_command_done(i); free(i); } diff --git a/src/core/manager.c b/src/core/manager.c index 53a1b41b0e..304abf4697 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1257,10 +1257,8 @@ static unsigned manager_dispatch_release_resources_queue(Manager *m) { assert(m); - while ((u = m->release_resources_queue)) { + while ((u = LIST_POP(release_resources_queue, m->release_resources_queue))) { assert(u->in_release_resources_queue); - - LIST_REMOVE(release_resources_queue, m->release_resources_queue, u); u->in_release_resources_queue = false; n++; @@ -1364,12 +1362,11 @@ static unsigned manager_dispatch_gc_unit_queue(Manager *m) { gc_marker = m->gc_marker; - while ((u = m->gc_unit_queue)) { + while ((u = LIST_POP(gc_queue, m->gc_unit_queue))) { assert(u->in_gc_queue); unit_gc_sweep(u, gc_marker); - LIST_REMOVE(gc_queue, m->gc_unit_queue, u); u->in_gc_queue = false; n++; @@ -1392,10 +1389,8 @@ static unsigned manager_dispatch_gc_job_queue(Manager *m) { assert(m); - while ((j = m->gc_job_queue)) { + while ((j = LIST_POP(gc_queue, m->gc_job_queue))) { assert(j->in_gc_queue); - - LIST_REMOVE(gc_queue, m->gc_job_queue, j); j->in_gc_queue = false; n++; @@ -1459,11 +1454,10 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) { assert(m); - while ((u = m->stop_when_unneeded_queue)) { + while ((u = LIST_POP(stop_when_unneeded_queue, m->stop_when_unneeded_queue))) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; assert(u->in_stop_when_unneeded_queue); - LIST_REMOVE(stop_when_unneeded_queue, m->stop_when_unneeded_queue, u); u->in_stop_when_unneeded_queue = false; n++; @@ -1500,12 +1494,11 @@ static unsigned manager_dispatch_start_when_upheld_queue(Manager *m) { assert(m); - while ((u = m->start_when_upheld_queue)) { + while ((u = LIST_POP(start_when_upheld_queue, m->start_when_upheld_queue))) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Unit *culprit = NULL; assert(u->in_start_when_upheld_queue); - LIST_REMOVE(start_when_upheld_queue, m->start_when_upheld_queue, u); u->in_start_when_upheld_queue = false; n++; @@ -1542,12 +1535,11 @@ static unsigned manager_dispatch_stop_when_bound_queue(Manager *m) { assert(m); - while ((u = m->stop_when_bound_queue)) { + while ((u = LIST_POP(stop_when_bound_queue, m->stop_when_bound_queue))) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Unit *culprit = NULL; assert(u->in_stop_when_bound_queue); - LIST_REMOVE(stop_when_bound_queue, m->stop_when_bound_queue, u); u->in_stop_when_bound_queue = false; n++; @@ -2177,13 +2169,12 @@ static int manager_dispatch_target_deps_queue(Manager *m) { assert(m); - while ((u = m->target_deps_queue)) { + while ((u = LIST_POP(target_deps_queue, m->target_deps_queue))) { _cleanup_free_ Unit **targets = NULL; int n_targets; assert(u->in_target_deps_queue); - LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u); u->in_target_deps_queue = false; /* Take an "atomic" snapshot of dependencies here, as the call below will likely modify the diff --git a/src/core/path.c b/src/core/path.c index b06b97d712..d5651cd9d8 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -288,9 +288,8 @@ void path_free_specs(Path *p) { assert(p); - while ((s = p->specs)) { + while ((s = LIST_POP(spec, p->specs))) { path_spec_unwatch(s); - LIST_REMOVE(spec, p->specs, s); path_spec_done(s); free(s); } diff --git a/src/core/socket.c b/src/core/socket.c index 023c0ba388..74d7769281 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -134,14 +134,9 @@ SocketPort *socket_port_free(SocketPort *p) { } void socket_free_ports(Socket *s) { - SocketPort *p; - assert(s); - while ((p = s->ports)) { - LIST_REMOVE(port, s->ports, p); - socket_port_free(p); - } + LIST_CLEAR(port, s->ports, socket_port_free); } static void socket_done(Unit *u) { diff --git a/src/core/timer.c b/src/core/timer.c index 17faa5cbfb..5a68f07e9d 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -51,8 +51,7 @@ void timer_free_values(Timer *t) { assert(t); - while ((v = t->values)) { - LIST_REMOVE(value, t->values, v); + while ((v = LIST_POP(value, t->values))) { calendar_spec_free(v->calendar_spec); free(v); } diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 5e8869a3b7..791314e9cc 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -345,13 +345,11 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s } static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { + struct sd_dhcp_raw_option *option; + assert(lease); - while (lease->private_options) { - struct sd_dhcp_raw_option *option = lease->private_options; - - LIST_REMOVE(options, lease->private_options, option); - + while ((option = LIST_POP(options, lease->private_options))) { free(option->data); free(option); } diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 890c146295..839c9a9ee6 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -99,19 +99,8 @@ static sd_radv *radv_free(sd_radv *ra) { if (!ra) return NULL; - while (ra->prefixes) { - sd_radv_prefix *p = ra->prefixes; - - LIST_REMOVE(prefix, ra->prefixes, p); - sd_radv_prefix_unref(p); - } - - while (ra->route_prefixes) { - sd_radv_route_prefix *p = ra->route_prefixes; - - LIST_REMOVE(prefix, ra->route_prefixes, p); - sd_radv_route_prefix_unref(p); - } + LIST_CLEAR(prefix, ra->prefixes, sd_radv_prefix_unref); + LIST_CLEAR(prefix, ra->route_prefixes, sd_radv_route_prefix_unref); free(ra->rdnss); free(ra->dnssl); diff --git a/src/login/logind.c b/src/login/logind.c index f30f7f9370..ba3a31b0a4 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -907,8 +907,7 @@ static void manager_gc(Manager *m, bool drop_not_started) { assert(m); - while ((seat = m->seat_gc_queue)) { - LIST_REMOVE(gc_queue, m->seat_gc_queue, seat); + while ((seat = LIST_POP(gc_queue, m->seat_gc_queue))) { seat->in_gc_queue = false; if (seat_may_gc(seat, drop_not_started)) { @@ -917,8 +916,7 @@ static void manager_gc(Manager *m, bool drop_not_started) { } } - while ((session = m->session_gc_queue)) { - LIST_REMOVE(gc_queue, m->session_gc_queue, session); + while ((session = LIST_POP(gc_queue, m->session_gc_queue))) { session->in_gc_queue = false; /* First, if we are not closing yet, initiate stopping. */ @@ -934,8 +932,7 @@ static void manager_gc(Manager *m, bool drop_not_started) { } } - while ((user = m->user_gc_queue)) { - LIST_REMOVE(gc_queue, m->user_gc_queue, user); + while ((user = LIST_POP(gc_queue, m->user_gc_queue))) { user->in_gc_queue = false; /* First step: queue stop jobs */ diff --git a/src/machine/machined.c b/src/machine/machined.c index 8152bda50d..926a8a7f2b 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -254,8 +254,7 @@ static void manager_gc(Manager *m, bool drop_not_started) { assert(m); - while ((machine = m->machine_gc_queue)) { - LIST_REMOVE(gc_queue, m->machine_gc_queue, machine); + while ((machine = LIST_POP(gc_queue, m->machine_gc_queue))) { machine->in_gc_queue = false; /* First, if we are not closing yet, initiate stopping */ diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index ffc6452bbf..0e992f9ad1 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -35,14 +35,9 @@ static void wireguard_resolve_endpoints(NetDev *netdev); static int peer_resolve_endpoint(WireguardPeer *peer); static void wireguard_peer_clear_ipmasks(WireguardPeer *peer) { - WireguardIPmask *mask; - assert(peer); - while ((mask = peer->ipmasks)) { - LIST_REMOVE(ipmasks, peer->ipmasks, mask); - free(mask); - } + LIST_CLEAR(ipmasks, peer->ipmasks, free); } static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) { diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c index b35f8b6a9b..5644068446 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -73,12 +73,7 @@ int expose_port_parse(ExposePort **l, const char *s) { } void expose_port_free_all(ExposePort *p) { - - while (p) { - ExposePort *q = p; - LIST_REMOVE(ports, p, q); - free(q); - } + LIST_CLEAR(ports, p, free); } int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_addr_union *exposed) { diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index c4e93737f5..be2a7f8d29 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -257,8 +257,7 @@ static void context_save_and_clear(Context *c) { assert(c); - while ((i = c->write_queue)) { - LIST_REMOVE(queue, c->write_queue, i); + while ((i = LIST_POP(queue, c->write_queue))) { (void) save_state_write_one(i); write_queue_item_free(i); } diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c index b9ea8aa7da..3ff2726d4a 100644 --- a/src/shared/bus-polkit.c +++ b/src/shared/bus-polkit.c @@ -204,8 +204,6 @@ typedef struct AsyncPolkitQuery { } AsyncPolkitQuery; static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) { - AsyncPolkitQueryAction *a; - if (!q) return NULL; @@ -220,8 +218,7 @@ static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) { sd_event_source_disable_unref(q->defer_event_source); - while ((a = LIST_POP(authorized, q->authorized_actions))) - async_polkit_query_action_free(a); + LIST_CLEAR(authorized, q->authorized_actions, async_polkit_query_action_free); async_polkit_query_action_free(q->denied_action); async_polkit_query_action_free(q->error_action); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 3b77706f8f..c361a7a461 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -3689,8 +3689,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi MountOptions* mount_options_free_all(MountOptions *options) { MountOptions *m; - while ((m = options)) { - LIST_REMOVE(mount_options, options, m); + while ((m = LIST_POP(mount_options, options))) { free(m->options); free(m); } diff --git a/src/shared/open-file.c b/src/shared/open-file.c index 3402518555..42772bdabe 100644 --- a/src/shared/open-file.c +++ b/src/shared/open-file.c @@ -132,12 +132,9 @@ OpenFile *open_file_free(OpenFile *of) { } void open_file_free_many(OpenFile **head) { - OpenFile *of; + assert(head); - while ((of = *head)) { - LIST_REMOVE(open_files, *head, of); - of = open_file_free(of); - } + LIST_CLEAR(open_files, *head, open_file_free); } static const char * const open_file_flags_table[_OPENFILE_MAX] = { diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 41c2daf02b..28068c686e 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -473,12 +473,7 @@ static void varlink_clear(Varlink *v) { v->pushed_fds = mfree(v->pushed_fds); v->n_pushed_fds = 0; - while (v->output_queue) { - VarlinkJsonQueueItem *q = v->output_queue; - - LIST_REMOVE(queue, v->output_queue, q); - varlink_json_queue_item_free(q); - } + LIST_CLEAR(queue, v->output_queue, varlink_json_queue_item_free); v->output_queue_tail = NULL; v->event = sd_event_unref(v->event); diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index 6422550af4..e113396331 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -278,25 +278,15 @@ typedef struct UnitStatusInfo { LIST_HEAD(ExecStatusInfo, exec_status_info_list); } UnitStatusInfo; -static void unit_status_info_free(UnitStatusInfo *info) { - ExecStatusInfo *p; - UnitCondition *c; - +static void unit_status_info_done(UnitStatusInfo *info) { strv_free(info->documentation); strv_free(info->dropin_paths); strv_free(info->triggered_by); strv_free(info->triggers); strv_free(info->listen); - while ((c = info->conditions)) { - LIST_REMOVE(conditions, info->conditions, c); - unit_condition_free(c); - } - - while ((p = info->exec_status_info_list)) { - LIST_REMOVE(exec_status_info_list, info->exec_status_info_list, p); - exec_status_info_free(p); - } + LIST_CLEAR(conditions, info->conditions, unit_condition_free); + LIST_CLEAR(exec_status_info_list, info->exec_status_info_list, exec_status_info_free); } static void format_active_state(const char *active_state, const char **active_on, const char **active_off) { @@ -2065,7 +2055,7 @@ static int show_one( _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_set_free_ Set *found_properties = NULL; - _cleanup_(unit_status_info_free) UnitStatusInfo info = { + _cleanup_(unit_status_info_done) UnitStatusInfo info = { .runtime_max_sec = USEC_INFINITY, .memory_current = UINT64_MAX, .memory_high = CGROUP_LIMIT_MAX, diff --git a/src/sysupdate/sysupdate-pattern.c b/src/sysupdate/sysupdate-pattern.c index c9e2067c58..6822d7eda2 100644 --- a/src/sysupdate/sysupdate-pattern.c +++ b/src/sysupdate/sysupdate-pattern.c @@ -36,10 +36,7 @@ struct PatternElement { }; static PatternElement *pattern_element_free_all(PatternElement *e) { - PatternElement *p; - - while ((p = LIST_POP(elements, e))) - free(p); + LIST_CLEAR(elements, e, free); return NULL; } diff --git a/src/test/test-list.c b/src/test/test-list.c index 307c1bf936..4b20a9f956 100644 --- a/src/test/test-list.c +++ b/src/test/test-list.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "alloc-util.h" #include "list.h" int main(int argc, const char *argv[]) { @@ -254,5 +255,29 @@ int main(int argc, const char *argv[]) { assert_se(LIST_POP(item_list, head) == items + 0); assert_se(LIST_POP(item_list, head) == NULL); + /* No-op on an empty list */ + + LIST_CLEAR(item_list, head, free); + + /* A non-empty list is cleared */ + + assert_se(LIST_PREPEND(item_list, head, new0(list_item, 1))); + assert_se(LIST_PREPEND(item_list, head, new0(list_item, 1))); + + LIST_CLEAR(item_list, head, free); + + assert_se(head == NULL); + + /* A list can be cleared partially */ + + assert_se(LIST_PREPEND(item_list, head, new0(list_item, 1))); + assert_se(LIST_PREPEND(item_list, head, new0(list_item, 1))); + assert_se(LIST_PREPEND(item_list, head, items + 0) == items + 0); + + LIST_CLEAR(item_list, head->item_list_next, free); + + assert_se(head == items + 0); + assert_se(head->item_list_next == NULL); + return 0; } diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index ad1d492d6b..5ac7c9f8b2 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -115,8 +115,6 @@ static UnitStatusInfo *unit_status_info_free(UnitStatusInfo *p) { DEFINE_TRIVIAL_CLEANUP_FUNC(UnitStatusInfo*, unit_status_info_free); static void context_clear(Context *c) { - UnitStatusInfo *p; - assert(c); free(c->zone); @@ -125,10 +123,7 @@ static void context_clear(Context *c) { sd_bus_slot_unref(c->slot_job_removed); - while ((p = c->units)) { - LIST_REMOVE(units, c->units, p); - unit_status_info_free(p); - } + LIST_CLEAR(units, c->units, unit_status_info_free); } static int context_add_ntp_service(Context *c, const char *s, const char *source) {