diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-05-17 03:13:58 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-05-17 04:26:27 +0200 |
commit | 45fbe937d7ca8d0da9ea276d57bc70ebd41c285e (patch) | |
tree | 95b216605530430206c7d863bca4d1d610382d25 | |
parent | d5a2b9a6f455468a0f29483303657ab4fd7013d8 (diff) |
bus: add minimal locking around the memfd cache
We want to allow clients to process an sd_bus_message on a different
thread than it was received on. Since unreffing a bus message might
readd some of its memfds to the memfd cache add some minimal locking
around the cache.
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-internal.h | 8 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-kernel.c | 35 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 5 |
5 files changed, 45 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am index 526598277a..66f12e9037 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1749,6 +1749,10 @@ libsystemd_bus_la_LIBADD = \ libsystemd-shared.la \ libsystemd-daemon.la +libsystemd_bus_la_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + noinst_LTLIBRARIES += \ libsystemd-bus.la @@ -42,7 +42,6 @@ Features: - port systemd to new library - implement busname unit type in systemd - move to gvariant - - minimal locking around the memfd cache - keep the connection fds around as long as the bus is open - merge busctl into systemctl or so? - synthesize sd_bus_message objects from kernel messages diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index b6975c54a2..8f87bea781 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -24,6 +24,7 @@ #include <sys/socket.h> #include <sys/un.h> #include <netinet/in.h> +#include <pthread.h> #include "hashmap.h" #include "prioq.h" @@ -169,6 +170,13 @@ struct sd_bus { void *kdbus_buffer; + /* We do locking around the memfd cache, since we want to + * allow people to process a sd_bus_message in a different + * thread then it was generated on and free it there. Since + * adding something to the memfd cache might happen when a + * message is released, we hence need to protect this bit with + * a mutex. */ + pthread_mutex_t memfd_cache_mutex; struct memfd_cache memfd_cache[MEMFD_CACHE_MAX]; unsigned n_memfd_cache; diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index ede78d7bef..699d24185e 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -721,6 +721,7 @@ int bus_kernel_create(const char *name, char **s) { int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { struct memfd_cache *c; + int fd; assert(address); assert(size); @@ -728,8 +729,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { if (!bus || !bus->is_kernel) return -ENOTSUP; + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); + if (bus->n_memfd_cache <= 0) { - int fd, r; + int r; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd); if (r < 0) @@ -747,8 +752,18 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { *address = c->address; *size = c->size; + fd = c->fd; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - return c->fd; + return fd; +} + +static void close_and_munmap(int fd, void *address, size_t size) { + if (size > 0) + assert_se(munmap(address, PAGE_ALIGN(size)) == 0); + + close_nointr_nofail(fd); } void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { @@ -757,13 +772,17 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { assert(fd >= 0); assert(size == 0 || address); - if (!bus || !bus->is_kernel || - bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { + if (!bus || !bus->is_kernel) { + close_and_munmap(fd, address, size); + return; + } + + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); - if (size > 0) - assert_se(munmap(address, PAGE_ALIGN(size)) == 0); + if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - close_nointr_nofail(fd); + close_and_munmap(fd, address, size); return; } @@ -780,6 +799,8 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { c->size = MEMFD_CACHE_ITEM_SIZE_MAX; } else c->size = size; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); } void bus_kernel_flush_memfd(sd_bus *b) { diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index fd19ff32b0..5e66a31162 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -27,6 +27,7 @@ #include <sys/poll.h> #include <byteswap.h> #include <sys/mman.h> +#include <pthread.h> #include "util.h" #include "macro.h" @@ -106,6 +107,8 @@ static void bus_free(sd_bus *b) { bus_kernel_flush_memfd(b); + assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0); + free(b); } @@ -125,6 +128,8 @@ int sd_bus_new(sd_bus **ret) { r->negotiate_fds = true; r->original_pid = getpid(); + assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0); + /* We guarantee that wqueue always has space for at least one * entry */ r->wqueue = new(sd_bus_message*, 1); |