mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-27 01:55:32 +03:00
core: dbus: track bus names per unit
Currently, PID1 installs an unfiltered NameOwnerChanged signal match, and dispatches the signals itself. This does not scale, as right now, PID1 wakes up every time a bus client connects. To fix this, install individual matches once they are requested by unit_watch_bus_name(), and remove the watches again through their slot in unit_unwatch_bus_name(). If the bus is not available during unit_watch_bus_name(), just store name in the 'watch_bus' hashmap, and let bus_setup_api() do the installing later.
This commit is contained in:
parent
d5972272d2
commit
bbc2908635
@ -140,28 +140,6 @@ static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_e
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
const char *name, *old_owner, *new_owner;
|
||||
Manager *m = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
|
||||
if (r < 0) {
|
||||
bus_log_parse_error(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
manager_dispatch_bus_name_owner_changed(
|
||||
m, name,
|
||||
isempty(old_owner) ? NULL : old_owner,
|
||||
isempty(new_owner) ? NULL : new_owner);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
|
||||
@ -762,13 +740,21 @@ static int bus_list_names(Manager *m, sd_bus *bus) {
|
||||
/* This is a bit hacky, we say the owner of the name is the
|
||||
* name itself, because we don't want the extra traffic to
|
||||
* figure out the real owner. */
|
||||
STRV_FOREACH(i, names)
|
||||
manager_dispatch_bus_name_owner_changed(m, *i, NULL, *i);
|
||||
STRV_FOREACH(i, names) {
|
||||
Unit *u;
|
||||
|
||||
u = hashmap_get(m->watch_bus, *i);
|
||||
if (u)
|
||||
UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_setup_api(Manager *m, sd_bus *bus) {
|
||||
Iterator i;
|
||||
char *name;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -786,17 +772,11 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_add_match(
|
||||
bus,
|
||||
NULL,
|
||||
"type='signal',"
|
||||
"sender='org.freedesktop.DBus',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged'",
|
||||
signal_name_owner_changed, m);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
|
||||
HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
|
||||
r = unit_install_bus_match(bus, u, name);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
|
||||
}
|
||||
|
||||
r = sd_bus_add_match(
|
||||
bus,
|
||||
|
@ -2187,24 +2187,6 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
|
||||
log_error_errno(errno, "Failed to write Plymouth message: %m");
|
||||
}
|
||||
|
||||
void manager_dispatch_bus_name_owner_changed(
|
||||
Manager *m,
|
||||
const char *name,
|
||||
const char* old_owner,
|
||||
const char *new_owner) {
|
||||
|
||||
Unit *u;
|
||||
|
||||
assert(m);
|
||||
assert(name);
|
||||
|
||||
u = hashmap_get(m->watch_bus, name);
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
|
||||
}
|
||||
|
||||
int manager_open_serialization(Manager *m, FILE **_f) {
|
||||
const char *path;
|
||||
int fd = -1;
|
||||
|
@ -329,8 +329,6 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
|
||||
|
||||
int manager_loop(Manager *m);
|
||||
|
||||
void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
|
||||
|
||||
int manager_open_serialization(Manager *m, FILE **_f);
|
||||
|
||||
int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root);
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "dropin.h"
|
||||
#include "formats-util.h"
|
||||
#include "process-util.h"
|
||||
#include "bus-util.h"
|
||||
|
||||
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
|
||||
[UNIT_SERVICE] = &service_vtable,
|
||||
@ -477,6 +478,7 @@ void unit_free(Unit *u) {
|
||||
if (u->manager->n_reloading <= 0)
|
||||
unit_remove_transient(u);
|
||||
|
||||
sd_bus_slot_unref(u->match_bus_slot);
|
||||
bus_unit_send_removed_signal(u);
|
||||
|
||||
unit_done(u);
|
||||
@ -2500,14 +2502,74 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
const char *name, *old_owner, *new_owner;
|
||||
Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(u);
|
||||
|
||||
r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
|
||||
if (r < 0) {
|
||||
bus_log_parse_error(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (UNIT_VTABLE(u)->bus_name_owner_change)
|
||||
UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
|
||||
_cleanup_free_ char *match = NULL;
|
||||
Manager *m = u->manager;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (u->match_bus_slot)
|
||||
return -EBUSY;
|
||||
|
||||
match = strjoin("type='signal',"
|
||||
"sender='org.freedesktop.DBus',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged',"
|
||||
"arg0='",
|
||||
name,
|
||||
"'",
|
||||
NULL);
|
||||
if (!match)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
|
||||
}
|
||||
|
||||
int unit_watch_bus_name(Unit *u, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(name);
|
||||
|
||||
/* Watch a specific name on the bus. We only support one unit
|
||||
* watching each name for now. */
|
||||
|
||||
return hashmap_put(u->manager->watch_bus, name, u);
|
||||
if (u->manager->api_bus) {
|
||||
/* If the bus is already available, install the match directly.
|
||||
* Otherwise, just put the name in the list. bus_setup_api() will take care later. */
|
||||
r = unit_install_bus_match(u->manager->api_bus, u, name);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
|
||||
}
|
||||
|
||||
r = hashmap_put(u->manager->watch_bus, name, u);
|
||||
if (r < 0) {
|
||||
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
|
||||
return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unit_unwatch_bus_name(Unit *u, const char *name) {
|
||||
@ -2515,6 +2577,7 @@ void unit_unwatch_bus_name(Unit *u, const char *name) {
|
||||
assert(name);
|
||||
|
||||
hashmap_remove_value(u->manager->watch_bus, name, u);
|
||||
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
|
||||
}
|
||||
|
||||
bool unit_can_serialize(Unit *u) {
|
||||
|
@ -115,6 +115,9 @@ struct Unit {
|
||||
/* JOB_NOP jobs are special and can be installed without disturbing the real job. */
|
||||
Job *nop_job;
|
||||
|
||||
/* The slot used for watching NameOwnerChanged signals */
|
||||
sd_bus_slot *match_bus_slot;
|
||||
|
||||
/* Job timeout and action to take */
|
||||
usec_t job_timeout;
|
||||
FailureAction job_timeout_action;
|
||||
@ -522,6 +525,7 @@ void unit_unwatch_all_pids(Unit *u);
|
||||
|
||||
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
|
||||
|
||||
int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name);
|
||||
int unit_watch_bus_name(Unit *u, const char *name);
|
||||
void unit_unwatch_bus_name(Unit *u, const char *name);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user