summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2017-06-23 12:54:34 +0100
committerSimon McVittie <smcv@collabora.com>2017-12-11 16:03:21 +0000
commitee56dde7ea9d2243a33d3c7d1871d6fa493fc8e3 (patch)
treef124f760360e720223d32143994a95d1b70593b5
parentec7f7f1755bcac6f33726d6a021cd08c3d441c72 (diff)
bus/containers: Emit InstanceRemoved signal
Signed-off-by: Simon McVittie <smcv@collabora.com> Reviewed-by: Philip Withnall <withnall@endlessm.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101354
-rw-r--r--bus/containers.c73
-rw-r--r--bus/driver.c5
2 files changed, 77 insertions, 1 deletions
diff --git a/bus/containers.c b/bus/containers.c
index eb2b89c6..aea9f78b 100644
--- a/bus/containers.c
+++ b/bus/containers.c
@@ -38,6 +38,7 @@
#include "dbus/dbus-sysdeps-unix.h"
#include "connection.h"
+#include "dispatch.h"
#include "driver.h"
#include "utils.h"
@@ -60,6 +61,7 @@ typedef struct
* removed from the bus */
DBusList *connections;
unsigned long uid;
+ unsigned announced:1;
} BusContainerInstance;
/* Data attached to a DBusConnection that has created container instances. */
@@ -209,6 +211,61 @@ bus_container_instance_ref (BusContainerInstance *self)
return self;
}
+static dbus_bool_t
+bus_container_instance_emit_removed (BusContainerInstance *self)
+{
+ BusTransaction *transaction = NULL;
+ DBusMessage *message = NULL;
+ DBusError error = DBUS_ERROR_INIT;
+
+ transaction = bus_transaction_new (self->context);
+
+ if (transaction == NULL)
+ goto oom;
+
+ message = dbus_message_new_signal (DBUS_PATH_DBUS,
+ DBUS_INTERFACE_CONTAINERS1,
+ "InstanceRemoved");
+
+ if (message == NULL ||
+ !dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
+ !dbus_message_append_args (message,
+ DBUS_TYPE_OBJECT_PATH, &self->path,
+ DBUS_TYPE_INVALID) ||
+ !bus_transaction_capture (transaction, NULL, NULL, message))
+ goto oom;
+
+ if (!bus_dispatch_matches (transaction, NULL, NULL, message, &error))
+ {
+ if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+ goto oom;
+
+ /* This can't actually happen, because all of the error cases in
+ * bus_dispatch_matches() are only if there is an addressed recipient
+ * (a unicast message), which there is not in this case. But if it
+ * somehow does happen, we don't want to stay in the OOM-retry loop,
+ * because waiting for more memory will not help; so continue to
+ * execute the transaction anyway. */
+ _dbus_warn ("Failed to send InstanceRemoved for a reason "
+ "other than OOM: %s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ }
+
+ bus_transaction_execute_and_free (transaction);
+ dbus_message_unref (message);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
+ return TRUE;
+
+oom:
+ dbus_error_free (&error);
+ dbus_clear_message (&message);
+
+ if (transaction != NULL)
+ bus_transaction_cancel_and_free (transaction);
+
+ return FALSE;
+}
+
static void
bus_container_instance_unref (BusContainerInstance *self)
{
@@ -218,6 +275,21 @@ bus_container_instance_unref (BusContainerInstance *self)
{
BusContainerCreatorData *creator_data;
+ /* If we announced the container instance in a reply from
+ * AddServer() (which is also the time at which it becomes
+ * available for the querying methods), then we have to emit
+ * InstanceRemoved for it.
+ *
+ * Similar to bus/connection.c dropping well-known name ownership,
+ * this isn't really a situation where we can "fail", because
+ * this last-unref is likely to be happening as a result of a
+ * connection disconnecting; so we use a retry loop on OOM. */
+ for (; self->announced; _dbus_wait_for_memory ())
+ {
+ if (bus_container_instance_emit_removed (self))
+ self->announced = FALSE;
+ }
+
/* As long as the server is listening, the BusContainerInstance can't
* be freed, because the DBusServer holds a reference to the
* BusContainerInstance */
@@ -754,6 +826,7 @@ bus_containers_handle_add_server (DBusConnection *connection,
if (! bus_transaction_send_from_driver (transaction, connection, reply))
goto oom;
+ instance->announced = TRUE;
dbus_message_unref (reply);
bus_container_instance_unref (instance);
dbus_address_entries_free (entries);
diff --git a/bus/driver.c b/bus/driver.c
index bcf38d05..feac80ad 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -2639,7 +2639,10 @@ static InterfaceHandler interface_handlers[] = {
INTERFACE_FLAG_NONE },
#endif
#ifdef DBUS_ENABLE_CONTAINERS
- { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers, NULL,
+ { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers,
+ " <signal name=\"InstanceRemoved\">\n"
+ " <arg type=\"o\" name=\"path\"/>\n"
+ " </signal>\n",
INTERFACE_FLAG_NONE, containers_property_handlers },
#endif
{ DBUS_INTERFACE_PEER, peer_message_handlers, NULL,