[PATCH] POLLRDHUP/EPOLLRDHUP handling for half-closed devices notifications

Implement the half-closed devices notifiation, by adding a new POLLRDHUP
(and its alias EPOLLRDHUP) bit to the existing poll/select sets.  Since the
existing POLLHUP handling, that does not report correctly half-closed
devices, was feared to be changed, this implementation leaves the current
POLLHUP reporting unchanged and simply add a new bit that is set in the few
places where it makes sense.  The same thing was discussed and conceptually
agreed quite some time ago:

http://lkml.org/lkml/2003/7/12/116

Since this new event bit is added to the existing Linux poll infrastruture,
even the existing poll/select system calls will be able to use it.  As far
as the existing POLLHUP handling, the patch leaves it as is.  The
pollrdhup-2.6.16.rc5-0.10.diff defines the POLLRDHUP for all the existing
archs and sets the bit in the six relevant files.  The other attached diff
is the simple change required to sys/epoll.h to add the EPOLLRDHUP
definition.

There is "a stupid program" to test POLLRDHUP delivery here:

 http://www.xmailserver.org/pollrdhup-test.c

It tests poll(2), but since the delivery is same epoll(2) will work equally.

Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Davide Libenzi 2006-03-25 03:07:39 -08:00 committed by Linus Torvalds
parent 501f2499b8
commit f348d70a32
28 changed files with 35 additions and 4 deletions

View file

@ -599,7 +599,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
switch (op) { switch (op) {
case EPOLL_CTL_ADD: case EPOLL_CTL_ADD:
if (!epi) { if (!epi) {
epds.events |= POLLERR | POLLHUP; epds.events |= POLLERR | POLLHUP | POLLRDHUP;
error = ep_insert(ep, &epds, tfile, fd); error = ep_insert(ep, &epds, tfile, fd);
} else } else
@ -613,7 +613,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
break; break;
case EPOLL_CTL_MOD: case EPOLL_CTL_MOD:
if (epi) { if (epi) {
epds.events |= POLLERR | POLLHUP; epds.events |= POLLERR | POLLHUP | POLLRDHUP;
error = ep_modify(ep, epi, &epds); error = ep_modify(ep, epi, &epds);
} else } else
error = -ENOENT; error = -ENOENT;

View file

@ -13,6 +13,8 @@
#define POLLWRBAND (1 << 9) #define POLLWRBAND (1 << 9)
#define POLLMSG (1 << 10) #define POLLMSG (1 << 10)
#define POLLREMOVE (1 << 11) #define POLLREMOVE (1 << 11)
#define POLLRDHUP (1 << 12)
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -15,6 +15,7 @@
#define POLLWRNORM 0x0100 #define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -15,6 +15,7 @@
#define POLLWRBAND 512 #define POLLWRBAND 512
#define POLLMSG 1024 #define POLLMSG 1024
#define POLLREMOVE 4096 #define POLLREMOVE 4096
#define POLLRDHUP 8192
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -12,6 +12,7 @@
#define POLLRDBAND 128 #define POLLRDBAND 128
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -12,6 +12,7 @@
#define POLLRDBAND 128 #define POLLRDBAND 128
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -21,6 +21,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -21,6 +21,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -17,6 +17,7 @@
/* These seem to be more or less nonstandard ... */ /* These seem to be more or less nonstandard ... */
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -13,6 +13,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -24,6 +24,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -26,6 +26,7 @@
#define POLLWRNORM 0x0100 #define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 512 #define POLLMSG 512
#define POLLREMOVE 1024 #define POLLREMOVE 1024
#define POLLRDHUP 2048
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 512 #define POLLMSG 512
#define POLLREMOVE 1024 #define POLLREMOVE 1024
#define POLLRDHUP 2048
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -13,6 +13,7 @@
#define POLLWRBAND 0x0100 #define POLLWRBAND 0x0100
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -27,6 +27,7 @@
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x0800 #define POLLREMOVE 0x0800
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;

View file

@ -238,6 +238,9 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;

View file

@ -500,6 +500,8 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
/* exceptional events? */ /* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;

View file

@ -350,7 +350,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED) if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */ /* Connected? */
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) { if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {

View file

@ -365,7 +365,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */ /* Connected? */
if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {

View file

@ -4894,6 +4894,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
/* Is there any exceptional events? */ /* Is there any exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;

View file

@ -1878,6 +1878,8 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
/* readable? */ /* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue) || if (!skb_queue_empty(&sk->sk_receive_queue) ||