chiark / gitweb /
bus: make bus ref counting atomic
authorLennart Poettering <lennart@poettering.net>
Thu, 16 May 2013 19:52:35 +0000 (21:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 16 May 2013 19:58:34 +0000 (21:58 +0200)
This is preparation to allow sd_bus_message obejcts to be processed in a
different thread from their originating sd_bus object.

Makefile.am
TODO
src/libsystemd-bus/bus-internal.h
src/libsystemd-bus/sd-bus.c
src/shared/refcnt.h [new file with mode: 0644]

index 4c5e6fc..5265982 100644 (file)
@@ -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 14ed4b4..19e53fe 100644 (file)
--- 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.
index 504dac7..0edb097 100644 (file)
@@ -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;
index 7b937d9..4a08177 100644 (file)
@@ -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 (file)
index 0000000..0502c20
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+***/
+
+/* 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 })