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