lkml.org 
[lkml]   [2004]   [Apr]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] Fix mq_notify with SIGEV_NONE notification
Hi!

mq_notify (q, NULL)
and
struct sigevent ev = { .sigev_notify = SIGEV_NONE };
mq_notify (q, &ev)
are not the same thing in POSIX, yet the kernel treats them the same.
Only the former makes the notification available to other processes
immediately, see
http://www.opengroup.org/onlinepubs/007904975/functions/mq_notify.html
Without the patch below,
http://sources.redhat.com/ml/libc-hacker/2004-04/msg00028.html
glibc test fails.
I looked at mq in Solaris and they behave the same in this regard
as Linux with this patch.
Kernel with this patch passes both Intel POSIX testsuite (with testsuite
fixes from Ulrich) and glibc mq testsuite.

--- linux-2.6.5-bk/ipc/mqueue.c.jj 2004-04-13 11:32:06.000000000 +0200
+++ linux-2.6.5-bk/ipc/mqueue.c 2004-04-13 14:27:57.000000000 +0200
@@ -65,8 +65,8 @@ struct mqueue_inode_info {
struct msg_msg **messages;
struct mq_attr attr;

- struct sigevent notify; /* notify.sigev_notify == SIGEV_NONE means */
- pid_t notify_owner; /* no notification registered */
+ struct sigevent notify;
+ pid_t notify_owner;
struct sock *notify_sock;
struct sk_buff *notify_cookie;

@@ -122,7 +122,7 @@ static struct inode *mqueue_get_inode(st
init_waitqueue_head(&info->wait_q);
INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list);
- info->notify.sigev_notify = SIGEV_NONE;
+ info->notify_owner = 0;
info->qsize = 0;
memset(&info->attr, 0, sizeof(info->attr));
info->attr.mq_maxmsg = DFLT_MSGMAX;
@@ -286,11 +286,11 @@ static ssize_t mqueue_read_file(struct f
snprintf(buffer, sizeof(buffer),
"QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
info->qsize,
- info->notify.sigev_notify,
- (info->notify.sigev_notify == SIGEV_SIGNAL ) ?
+ info->notify_owner ? info->notify.sigev_notify : 0,
+ (info->notify_owner &&
+ info->notify.sigev_notify == SIGEV_SIGNAL) ?
info->notify.sigev_signo : 0,
- (info->notify.sigev_notify != SIGEV_NONE) ?
- info->notify_owner : 0);
+ info->notify_owner);
spin_unlock(&info->lock);
buffer[sizeof(buffer)-1] = '\0';
slen = strlen(buffer)+1;
@@ -315,8 +315,7 @@ static int mqueue_flush_file(struct file
struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);

spin_lock(&info->lock);
- if (info->notify.sigev_notify != SIGEV_NONE &&
- current->tgid == info->notify_owner)
+ if (current->tgid == info->notify_owner)
remove_notification(info);

spin_unlock(&info->lock);
@@ -455,11 +454,14 @@ static void __do_notify(struct mqueue_in
* waiting synchronously for message AND state of queue changed from
* empty to not empty. Here we are sure that no one is waiting
* synchronously. */
- if (info->notify.sigev_notify != SIGEV_NONE &&
- info->attr.mq_curmsgs == 1) {
- /* sends signal */
- if (info->notify.sigev_notify == SIGEV_SIGNAL) {
- struct siginfo sig_i;
+ if (info->notify_owner &&
+ info->attr.mq_curmsgs == 1) {
+ struct siginfo sig_i;
+ switch (info->notify.sigev_notify) {
+ case SIGEV_NONE:
+ break;
+ case SIGEV_SIGNAL:
+ /* sends signal */

sig_i.si_signo = info->notify.sigev_signo;
sig_i.si_errno = 0;
@@ -470,13 +472,15 @@ static void __do_notify(struct mqueue_in

kill_proc_info(info->notify.sigev_signo,
&sig_i, info->notify_owner);
- } else if (info->notify.sigev_notify == SIGEV_THREAD) {
+ break;
+ case SIGEV_THREAD:
set_cookie(info->notify_cookie, NOTIFY_WOKENUP);
netlink_sendskb(info->notify_sock,
info->notify_cookie, 0);
+ break;
}
/* after notification unregisters process */
- info->notify.sigev_notify = SIGEV_NONE;
+ info->notify_owner = 0;
}
wake_up(&info->wait_q);
}
@@ -514,11 +518,12 @@ static long prepare_timeout(const struct

static void remove_notification(struct mqueue_inode_info *info)
{
- if (info->notify.sigev_notify == SIGEV_THREAD) {
+ if (info->notify_owner != 0 &&
+ info->notify.sigev_notify == SIGEV_THREAD) {
set_cookie(info->notify_cookie, NOTIFY_REMOVED);
netlink_sendskb(info->notify_sock, info->notify_cookie, 0);
}
- info->notify.sigev_notify = SIGEV_NONE;
+ info->notify_owner = 0;
}

/*
@@ -908,9 +913,9 @@ out:
}

/*
- * Notes: the case when user wants us to deregister (with NULL as pointer
- * or SIGEV_NONE) and he isn't currently owner of notification will be
- * silently discarded. It isn't explicitly defined in the POSIX.
+ * Notes: the case when user wants us to deregister (with NULL as pointer)
+ * and he isn't currently owner of notification, will be silently discarded.
+ * It isn't explicitly defined in the POSIX.
*/
asmlinkage long sys_mq_notify(mqd_t mqdes,
const struct sigevent __user *u_notification)
@@ -925,9 +930,7 @@ asmlinkage long sys_mq_notify(mqd_t mqde

nc = NULL;
sock = NULL;
- if (u_notification == NULL) {
- notification.sigev_notify = SIGEV_NONE;
- } else {
+ if (u_notification != NULL) {
if (copy_from_user(&notification, u_notification,
sizeof(struct sigevent)))
return -EFAULT;
@@ -993,35 +996,31 @@ retry:

ret = 0;
spin_lock(&info->lock);
- switch (notification.sigev_notify) {
- case SIGEV_NONE:
- if (info->notify.sigev_notify != SIGEV_NONE &&
- info->notify_owner == current->tgid) {
+ if (u_notification == NULL) {
+ if (info->notify_owner == current->tgid) {
remove_notification(info);
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
- break;
- case SIGEV_THREAD:
- if (info->notify.sigev_notify != SIGEV_NONE) {
- ret = -EBUSY;
+ } else if (info->notify_owner != 0) {
+ ret = -EBUSY;
+ } else {
+ switch (notification.sigev_notify) {
+ case SIGEV_NONE:
+ info->notify.sigev_notify = SIGEV_NONE;
break;
- }
- info->notify_sock = sock;
- info->notify_cookie = nc;
- sock = NULL;
- nc = NULL;
- info->notify.sigev_notify = SIGEV_THREAD;
- info->notify_owner = current->tgid;
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
- break;
- case SIGEV_SIGNAL:
- if (info->notify.sigev_notify != SIGEV_NONE) {
- ret = -EBUSY;
+ case SIGEV_THREAD:
+ info->notify_sock = sock;
+ info->notify_cookie = nc;
+ sock = NULL;
+ nc = NULL;
+ info->notify.sigev_notify = SIGEV_THREAD;
+ break;
+ case SIGEV_SIGNAL:
+ info->notify.sigev_signo = notification.sigev_signo;
+ info->notify.sigev_value = notification.sigev_value;
+ info->notify.sigev_notify = SIGEV_SIGNAL;
break;
}
- info->notify.sigev_signo = notification.sigev_signo;
- info->notify.sigev_value = notification.sigev_value;
- info->notify.sigev_notify = SIGEV_SIGNAL;
info->notify_owner = current->tgid;
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}

Jakub
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 14:02    [W:0.267 / U:0.024 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site