diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/sd-bus.c | 18 |
2 files changed, 21 insertions, 0 deletions
@@ -16,6 +16,9 @@ Bugfixes: * systemctl --root=container/ set-default ... is totally borked. +* sd_bus_unref() is broken regarding self-references and "pseudo thread-safety". + See the comment in sd_bus_unref() for more.. + External: * Fedora: when installing fedora with yum --installroot /var/run is a directory, not a symlink diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 984611fd4d..bbe61a6a8f 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1394,6 +1394,24 @@ _public_ sd_bus *sd_bus_unref(sd_bus *bus) { if (!bus) return NULL; + /* TODO/FIXME: It's naive to think REFCNT_GET() is thread-safe in any + * way but exclusive REFCNT_DEC(). The current logic _must_ lock around + * REFCNT_GET() until REFCNT_DEC() or two threads might end up in + * parallel in bus_reset_queues(). But locking would totally break the + * recursion we introduce by bus_reset_queues()... + * (Imagine one thread in sd_bus_message_unref() setting n_ref to 0 and + * thus calling into sd_bus_unref(). If at the same time the real + * thread calls sd_bus_unref(), both end up with "q == true" and will + * call into bus_reset_queues(). + * If we require the main bus to be alive until all dispatch threads + * are done, there is no need to do ref-counts at all. So in both ways, + * the REFCNT thing is humbug.) + * + * On a second note: messages are *not* required to have ->bus set nor + * does it have to be _this_ bus that they're assigned to. This whole + * ref-cnt checking breaks apart if a message is not assigned to us. + * (which is _very_ easy to trigger with the current API). */ + if (REFCNT_GET(bus->n_ref) == bus->rqueue_size + bus->wqueue_size + 1) { bool q = true; |