sd-bus: optionally, exit process or event loop on disconnect

Old libdbus has a feature that the process is terminated whenever the the bus
connection receives a disconnect. This is pretty useful on desktop apps (where
a disconnect indicates session termination), as well as on command line apps
(where we really shouldn't stay hanging in most cases if dbus daemon goes
down).

Add a similar feature to sd-bus, but make it opt-in rather than opt-out, like
it is on libdbus. Also, if the bus is attached to an event loop just exit the
event loop rather than the the whole process.
This commit is contained in:
Lennart Poettering 2016-08-22 17:19:12 +02:00
parent 2c5f295823
commit fbb4603d48
4 changed files with 54 additions and 0 deletions

View File

@ -507,4 +507,6 @@ global:
sd_bus_track_get_recursive;
sd_bus_track_count_name;
sd_bus_track_count_sender;
sd_bus_set_exit_on_disconnect;
sd_bus_get_exit_on_disconnect;
} LIBSYSTEMD_231;

View File

@ -209,6 +209,9 @@ struct sd_bus {
bool is_system:1;
bool is_user:1;
bool allow_interactive_authorization:1;
bool exit_on_disconnect:1;
bool exited:1;
bool exit_triggered:1;
int use_memfd;

View File

@ -2641,6 +2641,31 @@ null_message:
return r;
}
static int bus_exit_now(sd_bus *bus) {
assert(bus);
/* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes
* sd_event_exit(), otherwise invokes libc exit(). */
if (bus->exited) /* did we already exit? */
return 0;
if (!bus->exit_triggered) /* was the exit condition triggered? */
return 0;
if (!bus->exit_on_disconnect) /* Shall we actually exit on disconnection? */
return 0;
bus->exited = true; /* never exit more than once */
log_debug("Bus connection disconnected, exiting.");
if (bus->event)
return sd_event_exit(bus->event, EXIT_FAILURE);
else
exit(EXIT_FAILURE);
assert_not_reached("exit() didn't exit?");
}
static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) {
_cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
@ -2742,6 +2767,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
if (r != 0)
goto finish;
/* Nothing else to do, exit now, if the condition holds */
bus->exit_triggered = true;
(void) bus_exit_now(bus);
if (ret) {
*ret = m;
m = NULL;
@ -3804,3 +3833,21 @@ _public_ void sd_bus_default_flush_close(void) {
flush_close(default_user_bus);
flush_close(default_system_bus);
}
_public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
/* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already
* disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never
* from the client side. */
bus->exit_on_disconnect = b;
/* If the exit condition was triggered already, exit immediately. */
return bus_exit_now(bus);
}
_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
assert_return(bus, -EINVAL);
return bus->exit_on_disconnect;
}

View File

@ -147,6 +147,8 @@ int sd_bus_can_send(sd_bus *bus, char type);
int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *creds_mask);
int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b);
int sd_bus_get_allow_interactive_authorization(sd_bus *bus);
int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b);
int sd_bus_get_exit_on_disconnect(sd_bus *bus);
int sd_bus_start(sd_bus *ret);