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