Fix poll(2) and select(2) for named pipes to return "ready for read"
when all writers, observed by reader, exited. Use writer generation counter for fifo, and store the snapshot of the fifo generation in the f_seqcount field of struct file, that is otherwise unused for fifos. Set FreeBSD-undocumented POLLINIGNEOF flag only when file f_seqcount is equal to fifo' fi_wgen, and revert r89376. Fix POLLINIGNEOF for sockets and pipes, and return POLLHUP for them. Note that the patch does not fix not returning POLLHUP for fifos. PR: kern/94772 Submitted by: bde (original version) Reviewed by: rwatson, jilles Approved by: re (kensmith) MFC after: 6 weeks (might be)
This commit is contained in:
parent
55b57bd274
commit
7f5dff5064
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195423
@ -84,6 +84,7 @@ struct fifoinfo {
|
||||
struct socket *fi_writesock;
|
||||
long fi_readers;
|
||||
long fi_writers;
|
||||
int fi_wgen;
|
||||
};
|
||||
|
||||
static vop_print_t fifo_print;
|
||||
@ -232,6 +233,7 @@ fifo_open(ap)
|
||||
sowwakeup(fip->fi_writesock);
|
||||
}
|
||||
}
|
||||
fp->f_seqcount = fip->fi_wgen - fip->fi_writers;
|
||||
}
|
||||
if (ap->a_mode & FWRITE) {
|
||||
if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
|
||||
@ -279,6 +281,9 @@ fifo_open(ap)
|
||||
fip->fi_writers--;
|
||||
if (fip->fi_writers == 0) {
|
||||
socantrcvmore(fip->fi_readsock);
|
||||
mtx_lock(&fifo_mtx);
|
||||
fip->fi_wgen++;
|
||||
mtx_unlock(&fifo_mtx);
|
||||
fifo_cleanup(vp);
|
||||
}
|
||||
return (error);
|
||||
@ -395,8 +400,12 @@ fifo_close(ap)
|
||||
}
|
||||
if (ap->a_fflag & FWRITE) {
|
||||
fip->fi_writers--;
|
||||
if (fip->fi_writers == 0)
|
||||
if (fip->fi_writers == 0) {
|
||||
socantrcvmore(fip->fi_readsock);
|
||||
mtx_lock(&fifo_mtx);
|
||||
fip->fi_wgen++;
|
||||
mtx_unlock(&fifo_mtx);
|
||||
}
|
||||
}
|
||||
fifo_cleanup(vp);
|
||||
return (0);
|
||||
@ -634,28 +643,13 @@ fifo_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
|
||||
levents = events &
|
||||
(POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
|
||||
if ((fp->f_flag & FREAD) && levents) {
|
||||
/*
|
||||
* If POLLIN or POLLRDNORM is requested and POLLINIGNEOF is
|
||||
* not, then convert the first two to the last one. This
|
||||
* tells the socket poll function to ignore EOF so that we
|
||||
* block if there is no writer (and no data). Callers can
|
||||
* set POLLINIGNEOF to get non-blocking behavior.
|
||||
*/
|
||||
if (levents & (POLLIN | POLLRDNORM) &&
|
||||
!(levents & POLLINIGNEOF)) {
|
||||
levents &= ~(POLLIN | POLLRDNORM);
|
||||
levents |= POLLINIGNEOF;
|
||||
}
|
||||
|
||||
filetmp.f_data = fip->fi_readsock;
|
||||
filetmp.f_cred = cred;
|
||||
mtx_lock(&fifo_mtx);
|
||||
if (fp->f_seqcount == fip->fi_wgen)
|
||||
levents |= POLLINIGNEOF;
|
||||
mtx_unlock(&fifo_mtx);
|
||||
revents |= soo_poll(&filetmp, levents, cred, td);
|
||||
|
||||
/* Reverse the above conversion. */
|
||||
if ((revents & POLLINIGNEOF) && !(events & POLLINIGNEOF)) {
|
||||
revents |= (events & (POLLIN | POLLRDNORM));
|
||||
revents &= ~POLLINIGNEOF;
|
||||
}
|
||||
}
|
||||
levents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||
if ((fp->f_flag & FWRITE) && levents) {
|
||||
|
@ -1353,8 +1353,7 @@ pipe_poll(fp, events, active_cred, td)
|
||||
#endif
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
if ((rpipe->pipe_state & PIPE_DIRECTW) ||
|
||||
(rpipe->pipe_buffer.cnt > 0) ||
|
||||
(rpipe->pipe_state & PIPE_EOF))
|
||||
(rpipe->pipe_buffer.cnt > 0))
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
@ -1364,10 +1363,14 @@ pipe_poll(fp, events, active_cred, td)
|
||||
(wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF))
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
|
||||
if ((rpipe->pipe_state & PIPE_EOF) ||
|
||||
wpipe->pipe_present != PIPE_ACTIVE ||
|
||||
(wpipe->pipe_state & PIPE_EOF))
|
||||
revents |= POLLHUP;
|
||||
if ((events & POLLINIGNEOF) == 0) {
|
||||
if (rpipe->pipe_state & PIPE_EOF) {
|
||||
revents |= (events & (POLLIN | POLLRDNORM));
|
||||
if (wpipe->pipe_present != PIPE_ACTIVE ||
|
||||
(wpipe->pipe_state & PIPE_EOF))
|
||||
revents |= POLLHUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (revents == 0) {
|
||||
if (events & (POLLIN | POLLRDNORM)) {
|
||||
|
@ -2885,14 +2885,9 @@ sopoll_generic(struct socket *so, int events, struct ucred *active_cred,
|
||||
SOCKBUF_LOCK(&so->so_snd);
|
||||
SOCKBUF_LOCK(&so->so_rcv);
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
if (soreadable(so))
|
||||
if (soreadabledata(so))
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
|
||||
if (events & POLLINIGNEOF)
|
||||
if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat ||
|
||||
!TAILQ_EMPTY(&so->so_comp) || so->so_error)
|
||||
revents |= POLLINIGNEOF;
|
||||
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
if (sowriteable(so))
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
@ -2901,10 +2896,16 @@ sopoll_generic(struct socket *so, int events, struct ucred *active_cred,
|
||||
if (so->so_oobmark || (so->so_rcv.sb_state & SBS_RCVATMARK))
|
||||
revents |= events & (POLLPRI | POLLRDBAND);
|
||||
|
||||
if ((events & POLLINIGNEOF) == 0) {
|
||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
if (so->so_snd.sb_state & SBS_CANTSENDMORE)
|
||||
revents |= POLLHUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (revents == 0) {
|
||||
if (events &
|
||||
(POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM |
|
||||
POLLRDBAND)) {
|
||||
if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
|
||||
selrecord(td, &so->so_rcv.sb_sel);
|
||||
so->so_rcv.sb_flags |= SB_SEL;
|
||||
}
|
||||
|
@ -197,10 +197,11 @@ struct xsocket {
|
||||
((so)->so_proto->pr_flags & PR_ATOMIC)
|
||||
|
||||
/* can we read something from so? */
|
||||
#define soreadable(so) \
|
||||
#define soreadabledata(so) \
|
||||
((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \
|
||||
((so)->so_rcv.sb_state & SBS_CANTRCVMORE) || \
|
||||
!TAILQ_EMPTY(&(so)->so_comp) || (so)->so_error)
|
||||
#define soreadable(so) \
|
||||
(soreadabledata(so) || ((so)->so_rcv.sb_state & SBS_CANTRCVMORE))
|
||||
|
||||
/* can we write something to so? */
|
||||
#define sowriteable(so) \
|
||||
|
Loading…
Reference in New Issue
Block a user