X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Fsd-rtnl.c;h=2ab9d90aa790d4f76360d6adc45111d2b6a6fe1b;hb=689703f618f99661ca75db7c74984ec0fed27e08;hp=551e95b592d87eb48a3e34a21cb3ed80f13e29d4;hpb=3dd215e056ee9ff23175eca66686ff9b7a566dbf;p=elogind.git diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c index 551e95b59..2ab9d90aa 100644 --- a/src/libsystemd/sd-rtnl/sd-rtnl.c +++ b/src/libsystemd/sd-rtnl/sd-rtnl.c @@ -31,7 +31,7 @@ #include "rtnl-util.h" static int sd_rtnl_new(sd_rtnl **ret) { - sd_rtnl *rtnl; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; assert_return(ret, -EINVAL); @@ -52,12 +52,12 @@ static int sd_rtnl_new(sd_rtnl **ret) { /* We guarantee that wqueue always has space for at least * one entry */ rtnl->wqueue = new(sd_rtnl_message*, 1); - if (!rtnl->wqueue) { - free(rtnl); + if (!rtnl->wqueue) return -ENOMEM; - } *ret = rtnl; + rtnl = NULL; + return 0; } @@ -104,6 +104,9 @@ int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) { } sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) { + assert_return(rtnl, NULL); + assert_return(!rtnl_pid_changed(rtnl), NULL); + if (rtnl) assert_se(REFCNT_INC(rtnl->n_ref) >= 2); @@ -111,81 +114,39 @@ sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) { } sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) { - unsigned long refs; - if (!rtnl) return NULL; - /* - * If our ref-cnt is exactly the number of internally queued messages - * plus the ref-cnt to be dropped, then we know there's no external - * reference to us. Hence, we look through all queued messages and if - * they also have no external references, we're about to drop the last - * ref. Flush the queues so the REFCNT_DEC() below will drop to 0. - * We must be careful not to introduce inter-message references or this - * logic will fall apart.. - */ - - refs = rtnl->rqueue_size + rtnl->wqueue_size + 1; + assert_return(!rtnl_pid_changed(rtnl), NULL); - if (REFCNT_GET(rtnl->n_ref) <= refs) { + if (REFCNT_DEC(rtnl->n_ref) <= 0) { struct match_callback *f; - bool q = true; unsigned i; - for (i = 0; i < rtnl->rqueue_size; i++) { - if (REFCNT_GET(rtnl->rqueue[i]->n_ref) > 1) { - q = false; - break; - } else if (rtnl->rqueue[i]->rtnl != rtnl) - --refs; - } - - if (q) { - for (i = 0; i < rtnl->wqueue_size; i++) { - if (REFCNT_GET(rtnl->wqueue[i]->n_ref) > 1) { - q = false; - break; - } else if (rtnl->wqueue[i]->rtnl != rtnl) - --refs; - } - } - - if (q && REFCNT_GET(rtnl->n_ref) == refs) { - /* Drop our own ref early to avoid recursion from: - * sd_rtnl_message_unref() - * sd_rtnl_unref() - * These must enter sd_rtnl_unref() with a ref-cnt - * smaller than us. */ - REFCNT_DEC(rtnl->n_ref); - - for (i = 0; i < rtnl->rqueue_size; i++) - sd_rtnl_message_unref(rtnl->rqueue[i]); - free(rtnl->rqueue); - - for (i = 0; i < rtnl->wqueue_size; i++) - sd_rtnl_message_unref(rtnl->wqueue[i]); - free(rtnl->wqueue); + for (i = 0; i < rtnl->rqueue_size; i++) + sd_rtnl_message_unref(rtnl->rqueue[i]); + free(rtnl->rqueue); - assert_se(REFCNT_GET(rtnl->n_ref) == 0); + for (i = 0; i < rtnl->wqueue_size; i++) + sd_rtnl_message_unref(rtnl->wqueue[i]); + free(rtnl->wqueue); - hashmap_free_free(rtnl->reply_callbacks); - prioq_free(rtnl->reply_callbacks_prioq); + hashmap_free_free(rtnl->reply_callbacks); + prioq_free(rtnl->reply_callbacks_prioq); - while ((f = rtnl->match_callbacks)) { - LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); - free(f); - } - - safe_close(rtnl->fd); - free(rtnl); + sd_event_source_unref(rtnl->io_event_source); + sd_event_source_unref(rtnl->time_event_source); + sd_event_source_unref(rtnl->exit_event_source); + sd_event_unref(rtnl->event); - return NULL; + while ((f = rtnl->match_callbacks)) { + LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); + free(f); } - } - assert_se(REFCNT_GET(rtnl->n_ref) > 0); - REFCNT_DEC(rtnl->n_ref); + safe_close(rtnl->fd); + free(rtnl); + } return NULL; }