From e4ee6e5cc3e8e23e1ecc0d9fa756d9cc2534d218 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 May 2013 21:52:35 +0200 Subject: [PATCH] bus: make bus ref counting atomic This is preparation to allow sd_bus_message obejcts to be processed in a different thread from their originating sd_bus object. --- Makefile.am | 3 ++- TODO | 2 +- src/libsystemd-bus/bus-internal.h | 12 ++++++++++- src/libsystemd-bus/sd-bus.c | 10 +++------ src/shared/refcnt.h | 34 +++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/shared/refcnt.h diff --git a/Makefile.am b/Makefile.am index 4c5e6fcdf..526598277 100644 --- a/Makefile.am +++ b/Makefile.am @@ -695,7 +695,8 @@ libsystemd_shared_la_SOURCES = \ src/shared/fileio.h \ src/shared/output-mode.h \ src/shared/MurmurHash3.c \ - src/shared/MurmurHash3.h + src/shared/MurmurHash3.h \ + src/shared/refcnt.h #------------------------------------------------------------------------------- noinst_LTLIBRARIES += \ diff --git a/TODO b/TODO index 14ed4b43c..19e53fe65 100644 --- a/TODO +++ b/TODO @@ -42,8 +42,8 @@ Features: - move to gvariant - minimal locking around the memfd cache - keep the connection fds around as long as the bus is open - - make ref counting atomic - merge busctl into systemctl or so? + - synthesize sd_bus_message objects from kernel messages * in the final killing spree, detect processes from the root directory, and complain loudly if they have argv[0][0] == '@' set. diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index 504dac7f0..0edb09764 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -29,6 +29,7 @@ #include "prioq.h" #include "list.h" #include "util.h" +#include "refcnt.h" #include "sd-bus.h" #include "bus-error.h" @@ -77,7 +78,16 @@ enum bus_auth { }; struct sd_bus { - unsigned n_ref; + /* We use atomic ref counting here since sd_bus_message + objects retain references to their originating sd_bus but + we want to allow them to be processed in a different + thread. We won't provide full thread safety, but only the + bare minimum that makes it possible to use sd_bus and + sd_bus_message objects independently and on different + threads as long as each object is used only once at the + same time. */ + RefCount n_ref; + enum bus_state state; int input_fd, output_fd; int message_version; diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 7b937d999..4a081778a 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -103,7 +103,7 @@ int sd_bus_new(sd_bus **ret) { if (!r) return -ENOMEM; - r->n_ref = 1; + r->n_ref = REFCNT_INIT; r->input_fd = r->output_fd = -1; r->message_version = 1; r->negotiate_fds = true; @@ -934,9 +934,8 @@ sd_bus *sd_bus_ref(sd_bus *bus) { if (!bus) return NULL; - assert(bus->n_ref > 0); + assert_se(REFCNT_INC(bus->n_ref) >= 2); - bus->n_ref++; return bus; } @@ -944,10 +943,7 @@ sd_bus *sd_bus_unref(sd_bus *bus) { if (!bus) return NULL; - assert(bus->n_ref > 0); - bus->n_ref--; - - if (bus->n_ref <= 0) + if (REFCNT_DEC(bus->n_ref) <= 0) bus_free(bus); return NULL; diff --git a/src/shared/refcnt.h b/src/shared/refcnt.h new file mode 100644 index 000000000..0502c20a2 --- /dev/null +++ b/src/shared/refcnt.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* A type-safe atomic refcounter */ + +typedef struct { + volatile unsigned _value; +} RefCount; + +#define REFCNT_GET(r) ((r)._value) +#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1)) +#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1)) + +#define REFCNT_INIT ((RefCount) { ._value = 1 }) -- 2.30.2