Message ID | 1295620788-6002-7-git-send-email-alban.crequy@collabora.co.uk |
---|---|
State | Changes Requested, archived |
Delegated to: | David Miller |
Headers | show |
Le Fri, 21 Jan 2011 14:39:47 +0000, Alban Crequy <alban.crequy@collabora.co.uk> a écrit : > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c > index 4147d64..138d9a2 100644 > --- a/net/unix/af_unix.c > +++ b/net/unix/af_unix.c ... > sock_poll_wait(file, sk_sleep(sk), wait); ^^^^^^^^^^^^ > +#ifdef CONFIG_UNIX_MULTICAST > + /* > + * On multicast sockets, we need to check if the receiving queue is > + * full on all peers who don't have UNIX_MREQ_DROP_WHEN_FULL. > + */ > + if (!other || !unix_sk(other)->mcast_group) > + goto skip_multicast; > + others = unix_find_multicast_recipients(sk, > + unix_sk(other)->mcast_group, &err); > + if (!others) > + goto skip_multicast; > + for (i = others->offset ; i < others->cnt ; i++) { > + if (others->items[i].flags & UNIX_MREQ_DROP_WHEN_FULL) > + continue; > + if (unix_peer(others->items[i].s) != sk) { > + sock_poll_wait(file, > + &unix_sk(others->items[i].s)->peer_wait, wait); ^^^^^^^^^ This code does not work correctly: a poller cannot sleep on two wait queues at the same time. When the poller is added in ->peer_wait, it will not be in sk_sleep(sk) so it will miss POLLIN events. I think I need another wait queue at the group level for waiters of POLLIN|POLLOUT events. Waiters on that global wait queue would be woken up when a message is delivered to any peer (in unix_dgram_sendmsg along sk_data_ready) and when a member of the group receives a message (in unix_dgram_recvmsg along wake_up_interruptible_sync_poll). -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4147d64..138d9a2 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2940,6 +2940,11 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, { struct sock *sk = sock->sk, *other; unsigned int mask, writable; +#ifdef CONFIG_UNIX_MULTICAST + struct sock_set *others; + int err = 0; + int i; +#endif sock_poll_wait(file, sk_sleep(sk), wait); mask = 0; @@ -2980,6 +2985,34 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, sock_put(other); } +#ifdef CONFIG_UNIX_MULTICAST + /* + * On multicast sockets, we need to check if the receiving queue is + * full on all peers who don't have UNIX_MREQ_DROP_WHEN_FULL. + */ + if (!other || !unix_sk(other)->mcast_group) + goto skip_multicast; + others = unix_find_multicast_recipients(sk, + unix_sk(other)->mcast_group, &err); + if (!others) + goto skip_multicast; + for (i = others->offset ; i < others->cnt ; i++) { + if (others->items[i].flags & UNIX_MREQ_DROP_WHEN_FULL) + continue; + if (unix_peer(others->items[i].s) != sk) { + sock_poll_wait(file, + &unix_sk(others->items[i].s)->peer_wait, wait); + if (unix_recvq_full(others->items[i].s)) { + writable = 0; + break; + } + } + } + up_sock_set(others); + +skip_multicast: +#endif + if (writable) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else