[PATCH 06/11] KBUS add ability to receive messages only once

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sometimes a recipient has bound to a message name more than once,
but only wants to receive one copy of each message matching those
bindings.

Signed-off-by: Tony Ibbs <tibs@xxxxxxxxxxxxxx>
---
 include/linux/kbus_defns.h |   18 +++++++---
 ipc/kbus_internal.h        |   30 ++++++++++++++++
 ipc/kbus_main.c            |   82 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/include/linux/kbus_defns.h b/include/linux/kbus_defns.h
index d43c498..9da72e4 100644
--- a/include/linux/kbus_defns.h
+++ b/include/linux/kbus_defns.h
@@ -581,13 +581,21 @@ struct kbus_replier_bind_event_data {
  * retval: 0 for success, negative for failure
  */
 #define KBUS_IOC_UNREPLIEDTO _IOR(KBUS_IOC_MAGIC, 13, char *)
-
 /*
- * IOCTL 14 is not used, because it is introduced in the next revision,
- * (obviously, in real history this was done in a different order) and
- * I don't want to alter the number for VERBOSE.
+ * MSGONLYONCE - should we receive a message only once?
+ *
+ * This IOCTL tells a Ksock whether it should only receive a particular message
+ * once, even if it is both a Replier and Listener for the message (in which
+ * case it will always get the message as Replier, if appropriate), or if it is
+ * registered as multiple Listeners for the message.
+ *
+ * arg(in): __u32, 1 to change to "only once", 0 to change to the default,
+ * 0xFFFFFFFF to just return the current/previous state.
+ * arg(out): __u32, the previous state.
+ * retval: 0 for success, negative for failure (-EINVAL if arg in was not one
+ * of the specified values)
  */
-
+#define KBUS_IOC_MSGONLYONCE  _IOWR(KBUS_IOC_MAGIC, 14, char *)
 /*
  * VERBOSE - should KBUS output verbose "printk" messages (for this device)?
  *
diff --git a/ipc/kbus_internal.h b/ipc/kbus_internal.h
index 2d9e737..28c153c 100644
--- a/ipc/kbus_internal.h
+++ b/ipc/kbus_internal.h
@@ -534,6 +534,36 @@ struct kbus_private_data {
 	 * In fact, the 'outstanding_requests' list is used, simply because
 	 * it was implemented first.
 	 */
+
+	/*
+	 * By default, if a Ksock binds to a message name as both Replier and
+	 * Listener (typically by binding to a specific message name as Replier
+	 * and to a wildcard including it as Listener), and a Reqest of that
+	 * name is sent to that Ksock, it will get the message once as Replier
+	 * (marked "WANT_YOU_TO_REPLY"), and once as listener.
+	 *
+	 * This is technically sensible, but can be irritating to the end user
+	 * who really often only wants to receive the message once.
+	 *
+	 * If "messages_only_once" is set, then when a message is about to be
+	 * put onto a Ksocks message queue, it will only be added if it (i.e.,
+	 * a message with the same id) has not already just been added. This
+	 * is safe because Requests to the specific Replier are always dealt
+	 * with first.
+	 *
+	 * As a side-effect, which I think also makes sense, this will also
+	 * mean that if a Listener has bound to the same message name multiple
+	 * times (as a Listener), then they will only get the message once.
+	 */
+	int messages_only_once;
+	/*
+	 * Messages can be added to either end of our message queue (i.e.,
+	 * depending on whether they're urgent or not). This means that the
+	 * "only once" mechanism needs to check both ends of the queue (which
+	 * is a pain). Or we can just remember the message id of the last
+	 * message pushed onto the queue. Which is much simpler.
+	 */
+	struct kbus_msg_id msg_id_just_pushed;
 };
 
 /* What is a sensible number for the default maximum number of messages? */
diff --git a/ipc/kbus_main.c b/ipc/kbus_main.c
index 944b60c..a75d2e1 100644
--- a/ipc/kbus_main.c
+++ b/ipc/kbus_main.c
@@ -851,6 +851,46 @@ static int kbus_push_message(struct kbus_private_data *priv,
 		       "  %u Pushing message onto queue (%s)\n",
 		       priv->id, for_replier ? "replier" : "listener");
 
+	/*
+	 * 1. Check to see if this Ksock has the "only one copy
+	 *    of a message" flag set.
+	 * 2. If it does, check if our message (id) is already on
+	 *    the queue, and if it is, just skip adding it.
+	 *
+	 * (this means if the Ksock was destined to get the message
+	 * several times, either as Replier and Listener, or as
+	 * multiple Listeners to the same message name, it will only
+	 * get it once, for this "push")
+	 *
+	 * If "for_replier" is set we necessarily push the message - see below.
+	 */
+	if (priv->messages_only_once && !for_replier) {
+		/*
+		 * 1. We've been asked to only send one copy of a message
+		 *    to each Ksock that should receive it.
+		 * 2. This is not a Reply (to our Ksock) or a Request (to
+		 *    our Ksock as Replier)
+		 *
+		 * So, given that, has a message with that id already been
+		 * added to the message queue?
+		 *
+		 * (Note that if a message would be included because of
+		 * multiple message name bindings, we do not say anything
+		 * about which binding we will actually add the message
+		 * for - so unbinding later on may or may not cause a
+		 * message to go away, in this case.)
+		 */
+		if (kbus_same_message_id(&priv->msg_id_just_pushed,
+					 msg->id.network_id,
+					 msg->id.serial_num)) {
+			kbus_maybe_dbg(priv->dev,
+				       "  %u Ignoring message "
+				       "under 'once only' rule\n",
+				       priv->id);
+			return 0;
+		}
+	}
+
 	new_msg = kbus_copy_message(priv->dev, msg);
 	if (!new_msg)
 		return -EFAULT;
@@ -898,6 +938,7 @@ static int kbus_push_message(struct kbus_private_data *priv,
 	}
 
 	priv->message_count++;
+	priv->msg_id_just_pushed = msg->id;
 
 	if (!kbus_same_message_id(&msg->in_reply_to, 0, 0)) {
 		/*
@@ -3243,6 +3284,36 @@ static int kbus_nummsgs(struct kbus_private_data *priv,
 	return __put_user(count, (u32 __user *) arg);
 }
 
+static int kbus_onlyonce(struct kbus_private_data *priv,
+			 unsigned long arg)
+{
+	int retval = 0;
+	u32 only_once;
+	int old_value = priv->messages_only_once;
+
+	retval = __get_user(only_once, (u32 __user *) arg);
+	if (retval)
+		return retval;
+
+	kbus_maybe_dbg(priv->dev, "%u ONLYONCE requests %u (was %d)\n",
+		       priv->id, only_once, old_value);
+
+	switch (only_once) {
+	case 0:
+		priv->messages_only_once = false;
+		break;
+	case 1:
+		priv->messages_only_once = true;
+		break;
+	case 0xFFFFFFFF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return __put_user(old_value, (u32 __user *) arg);
+}
+
 static int kbus_set_verbosity(struct kbus_private_data *priv,
 			      unsigned long arg)
 {
@@ -3439,6 +3510,17 @@ static long kbus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 				(u32 __user *) arg);
 		break;
 
+	case KBUS_IOC_MSGONLYONCE:
+		/*
+		 * Should we receive a given message only once?
+		 *
+		 * arg in: 0 (for no), 1 (for yes), 0xFFFFFFFF (for query)
+		 * arg out: the previous value, before we were called
+		 * return: 0 means OK, otherwise not OK
+		 */
+		retval = kbus_onlyonce(priv, arg);
+		break;
+
 	case KBUS_IOC_VERBOSE:
 		/*
 		 * Should we output verbose/debug messages?
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Gstreamer Embedded]     [Linux MMC Devel]     [U-Boot V2]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux ARM Kernel]     [Linux OMAP]     [Linux SCSI]

  Powered by Linux