Add reply_callback slots to async kdbus name request/release
authorMaciej Slodczyk <m.slodczyk2@partner.samsung.com>
Tue, 25 Feb 2020 13:49:14 +0000 (14:49 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Wed, 4 Mar 2020 09:40:38 +0000 (10:40 +0100)
Signed-off-by: Maciej Slodczyk <m.slodczyk2@partner.samsung.com>
src/libsystemd/sd-bus/bus-control-kernel.c

index 8dffb56..aeb8356 100644 (file)
@@ -73,6 +73,22 @@ int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
         return 1;
 }
 
+static usec_t calc_elapse(sd_bus *bus, uint64_t usec) {
+        assert(bus);
+
+        if (usec == (uint64_t) -1)
+                return 0;
+
+        /* We start all timeouts the instant we enter BUS_HELLO/BUS_RUNNING state, so that the don't run in parallel
+         * with any connection setup states. Hence, if a method callback is started earlier than that we just store the
+         * relative timestamp, and afterwards the absolute one. */
+
+        if (IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING))
+                return usec;
+        else
+                return now(CLOCK_MONOTONIC) + usec;
+}
+
 int bus_request_name_kernel_async(sd_bus *bus,
         sd_bus_slot **ret_slot,
         const char *name,
@@ -81,12 +97,13 @@ int bus_request_name_kernel_async(sd_bus *bus,
         void *userdata) {
     int ret;
     sd_bus_message *m;
+    uint64_t cookie;
+    _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *s = NULL;
 
-    if (NULL != ret_slot) {
-        *ret_slot = bus_slot_allocate(bus, false, BUS_KDBUS_CALLBACK, 0, NULL);
-        if (!(*ret_slot))
-            return -ENOMEM;
-    }
+    /* we want room for the return message */
+    ret = bus_rqueue_make_room(bus);
+    if (ret < 0)
+        return ret;
 
     ret = bus_request_name_kernel(bus, name, flags);
 
@@ -108,8 +125,36 @@ int bus_request_name_kernel_async(sd_bus *bus,
     if (ret < 0)
         return ret;
 
+    if (ret_slot || callback) {
+        s = bus_slot_allocate(bus, !ret_slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
+        if (!s)
+            return -ENOMEM;
+
+        s->reply_callback.callback = callback;
+
+        s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
+        ret = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
+        if (ret < 0) {
+            s->reply_callback.cookie = 0;
+            return ret;
+        }
+
+        s->reply_callback.timeout_usec = calc_elapse(bus, m->timeout);
+        if (s->reply_callback.timeout_usec != 0) {
+            ret = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
+            if (ret < 0) {
+                s->reply_callback.timeout_usec = 0;
+                return ret;
+            }
+        }
+    }
+
     bus->rqueue[bus->rqueue_size++] = m;
 
+    if (ret_slot)
+        *ret_slot = s;
+    s = NULL;
+
     return ret;
 }
 
@@ -148,15 +193,18 @@ int bus_release_name_kernel_async(
                 void *userdata) {
     int ret;
     sd_bus_message *m;
+    uint64_t cookie;
+    _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *s = NULL;
 
-    if (NULL != ret_slot) {
-        *ret_slot = bus_slot_allocate(bus, false, BUS_KDBUS_CALLBACK, 0, NULL);
-        if (!(*ret_slot))
-            return -ENOMEM;
-    }
+    /* we want room for the return message */
+    ret = bus_rqueue_make_room(bus);
+    if (ret < 0)
+        return ret;
 
     ret = bus_release_name_kernel(bus, name);
 
+    cookie = ++bus->cookie;
+
     if (ret < 0) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
@@ -175,7 +223,34 @@ int bus_release_name_kernel_async(
     if (ret < 0)
         return ret;
 
+    if (ret_slot || callback) {
+        s = bus_slot_allocate(bus, !ret_slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
+        if (!s)
+            return -ENOMEM;
+
+        s->reply_callback.callback = callback;
+
+        s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
+        ret = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
+        if (ret < 0) {
+            s->reply_callback.cookie = 0;
+            return ret;
+        }
+
+        s->reply_callback.timeout_usec = calc_elapse(bus, m->timeout);
+        if (s->reply_callback.timeout_usec != 0) {
+            ret = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
+            if (ret < 0) {
+                s->reply_callback.timeout_usec = 0;
+                return ret;
+            }
+        }
+    }
+
     bus->rqueue[bus->rqueue_size++] = m;
+    if (ret_slot)
+        *ret_slot = s;
+    s = NULL;
 
     return ret;
 }
@@ -1118,6 +1193,11 @@ int bus_add_match_internal_kernel_async(
     int ret;
     sd_bus_message *m;
 
+    /* we want room for the return message */
+    ret = bus_rqueue_make_room(bus);
+    if (ret < 0)
+        return ret;
+
     if (NULL != ret_slot) {
         *ret_slot = bus_slot_allocate(bus, false, BUS_KDBUS_CALLBACK, 0, NULL);
         if (!(*ret_slot))