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 <t...@tonyibbs.co.uk>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to