[systemd-devel] [RFC 6/8] HACK2: blocking ioctl(CMD_MSG_RECV)

AKASHI Takahiro takahiro.akashi at linaro.org
Wed Jun 25 02:13:35 PDT 2014


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.akashi at 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



More information about the systemd-devel mailing list