In the current implementation, ioctl(CMD_MSG_RECV) returns immediately if
no message has been queued, and so a service process has to wait by
explicitly calling poll() system call. If such a process needs to wait only
on a single connection, we can eliminate poll() system call by adding a
synchronous attribute in receiving a message.

This patch allows us to specify a flag, KDBUS_HELLO_BLOCK, in HELLO command
and enable the feature. Please note that this is a quick hack, ignoring how
this feature and poll() could co-exist.

Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org>
---
 connection.c |   39 +++++++++++++++++++++++++++++++++++++++
 connection.h |    1 +
 kdbus.h      |    1 +
 3 files changed, 41 insertions(+)

diff --git a/connection.c b/connection.c
index d122be8..5969ead 100644
--- a/connection.c
+++ b/connection.c
@@ -41,6 +41,7 @@
 
 /*
  * KDBUS_HACK1: optimize copy operations in kdbus_conn_queue_alloc()
+ * KDBUS_HACK2: add a blocking attribute to ioctl(CMD_MSG_RECV)
  */
 
 struct kdbus_conn_reply;
@@ -795,6 +796,11 @@ static int kdbus_conn_queue_insert(struct kdbus_conn *conn,
 
        /* wake up poll() */
        wake_up_interruptible(&conn->wait);
+#if KDBUS_HACK2
+       if (conn->flags | KDBUS_HELLO_BLOCK)
+               wake_up_interruptible(&conn->wait_recv);
+#endif
+
        return 0;
 
 exit_queue_free:
@@ -1024,9 +1030,31 @@ int kdbus_cmd_msg_recv(struct kdbus_conn *conn,
        int ret = 0;
 
        mutex_lock(&conn->lock);
+recv_again:
        if (conn->msg_count == 0) {
+#if KDBUS_HACK2
+               if (conn->flags | KDBUS_HELLO_BLOCK) {
+                       mutex_unlock(&conn->lock);
+                       /* FIXME: there is a small window here. */
+                       wait_event_interruptible(conn->wait_recv,
+                                                conn->msg_count);
+                       mutex_lock(&conn->lock);
+                       if (signal_pending(current)) {
+                               ret = -EINTR;
+                               goto exit_unlock;
+                       } else if (conn->disconnected) {
+                               ret = -ESHUTDOWN;
+                               goto exit_unlock;
+                       }
+                       goto recv_again;
+               } else {
+                       ret = -EAGAIN;
+                       goto exit_unlock;
+               }
+#else
                ret = -EAGAIN;
                goto exit_unlock;
+#endif
        }
 
        if (recv->offset > 0) {
@@ -1606,6 +1634,10 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool 
ensure_queue_empty)
 
        /* wake up the queue so that users can get a POLLERR */
        wake_up_interruptible(&conn->wait);
+#if KDBUS_HACK2
+       if (conn->flags | KDBUS_HELLO_BLOCK)
+               wake_up_interruptible(&conn->wait_recv);
+#endif
 
        kdbus_notify_id_change(conn->bus, KDBUS_ITEM_ID_REMOVE, conn->id,
                               conn->flags);
@@ -1748,6 +1780,10 @@ int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
 
        /* wake up poll() */
        wake_up_interruptible(&conn_dst->wait);
+#if KDBUS_HACK2
+       if (conn_dst->flags | KDBUS_HELLO_BLOCK)
+               wake_up_interruptible(&conn_dst->wait_recv);
+#endif
 
        return ret;
 }
@@ -2058,6 +2094,9 @@ int kdbus_conn_new(struct kdbus_ep *ep,
        INIT_DELAYED_WORK(&conn->work, kdbus_conn_work);
        conn->cred = current_cred();
        init_waitqueue_head(&conn->wait);
+#if KDBUS_HACK2
+       init_waitqueue_head(&conn->wait_recv);
+#endif
 
        /* init entry, so we can unconditionally remove it */
        INIT_LIST_HEAD(&conn->monitor_entry);
diff --git a/connection.h b/connection.h
index 46f7b6e..17a05b8 100644
--- a/connection.h
+++ b/connection.h
@@ -92,6 +92,7 @@ struct kdbus_conn {
        size_t msg_count;
        atomic_t reply_count;
        wait_queue_head_t wait;
+       wait_queue_head_t wait_recv;
 };
 
 struct kdbus_kmsg;
diff --git a/kdbus.h b/kdbus.h
index 0b189cb..8f91f49 100644
--- a/kdbus.h
+++ b/kdbus.h
@@ -492,6 +492,7 @@ enum kdbus_hello_flags {
        KDBUS_HELLO_ACTIVATOR           =  1 <<  1,
        KDBUS_HELLO_POLICY_HOLDER       =  1 <<  2,
        KDBUS_HELLO_MONITOR             =  1 <<  3,
+       KDBUS_HELLO_BLOCK               =  1 <<  4,
 };
 
 /**
-- 
1.7.9.5

_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to