Improve kqueue() support in the LinuxKPI. Some applications using the
kqueue() does not set non-blocking I/O mode for event driven read of file descriptors. This means the LinuxKPI internal kqueue read and write event flags must be updated before the next read and/or write system call. Else the read and/or write system call may block. This can happen when there is no more data to read following a previous read event. Then the application also gets blocked from processing other events. This situation can also be solved by the applications setting and using non-blocking I/O mode. MFC after: 1 week Sponsored by: Mellanox Technologies
This commit is contained in:
parent
639af71ab1
commit
67e984c8f2
@ -438,7 +438,7 @@ linux_kq_lock_unowned(void *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dev_kqfilter_poll(struct linux_file *);
|
||||
linux_dev_kqfilter_poll(struct linux_file *, int);
|
||||
|
||||
struct linux_file *
|
||||
linux_file_alloc(void)
|
||||
@ -856,9 +856,11 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
current->bsd_ioctl_len = 0;
|
||||
}
|
||||
|
||||
if (error == EWOULDBLOCK)
|
||||
linux_dev_kqfilter_poll(filp);
|
||||
else if (error == ERESTARTSYS)
|
||||
if (error == EWOULDBLOCK) {
|
||||
/* update kqfilter status, if any */
|
||||
linux_dev_kqfilter_poll(filp,
|
||||
LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
|
||||
} else if (error == ERESTARTSYS)
|
||||
error = ERESTART;
|
||||
return (error);
|
||||
}
|
||||
@ -893,14 +895,15 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
uio->uio_resid -= bytes;
|
||||
} else {
|
||||
error = -bytes;
|
||||
if (error == EWOULDBLOCK)
|
||||
linux_dev_kqfilter_poll(filp);
|
||||
else if (error == ERESTARTSYS)
|
||||
if (error == ERESTARTSYS)
|
||||
error = ERESTART;
|
||||
}
|
||||
} else
|
||||
error = ENXIO;
|
||||
|
||||
/* update kqfilter status, if any */
|
||||
linux_dev_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_READ);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -934,14 +937,15 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
uio->uio_resid -= bytes;
|
||||
} else {
|
||||
error = -bytes;
|
||||
if (error == EWOULDBLOCK)
|
||||
linux_dev_kqfilter_poll(filp);
|
||||
else if (error == ERESTARTSYS)
|
||||
if (error == ERESTARTSYS)
|
||||
error = ERESTART;
|
||||
}
|
||||
} else
|
||||
error = ENXIO;
|
||||
|
||||
/* update kqfilter status, if any */
|
||||
linux_dev_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_WRITE);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1032,21 +1036,20 @@ static struct filterops linux_dev_kqfiltops_write = {
|
||||
};
|
||||
|
||||
static void
|
||||
linux_dev_kqfilter_poll(struct linux_file *filp)
|
||||
linux_dev_kqfilter_poll(struct linux_file *filp, int kqflags)
|
||||
{
|
||||
int temp;
|
||||
|
||||
spin_lock(&filp->f_kqlock);
|
||||
temp = (filp->f_kqflags & (LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE));
|
||||
filp->f_kqflags &= ~(LINUX_KQ_FLAG_NEED_READ | LINUX_KQ_FLAG_NEED_WRITE);
|
||||
spin_unlock(&filp->f_kqlock);
|
||||
|
||||
if (temp != 0) {
|
||||
if (filp->f_kqflags & kqflags) {
|
||||
/* get the latest polling state */
|
||||
temp = filp->f_op->poll(filp, NULL);
|
||||
|
||||
if (temp & (POLLIN | POLLOUT)) {
|
||||
spin_lock(&filp->f_kqlock);
|
||||
/* clear kqflags */
|
||||
filp->f_kqflags &= ~(LINUX_KQ_FLAG_NEED_READ |
|
||||
LINUX_KQ_FLAG_NEED_WRITE);
|
||||
/* update kqflags */
|
||||
if (temp & (POLLIN | POLLOUT)) {
|
||||
if (temp & POLLIN)
|
||||
filp->f_kqflags |= LINUX_KQ_FLAG_NEED_READ;
|
||||
if (temp & POLLOUT)
|
||||
@ -1054,8 +1057,8 @@ linux_dev_kqfilter_poll(struct linux_file *filp)
|
||||
|
||||
/* make sure the "knote" gets woken up */
|
||||
KNOTE_LOCKED(&filp->f_selinfo.si_note, 0);
|
||||
spin_unlock(&filp->f_kqlock);
|
||||
}
|
||||
spin_unlock(&filp->f_kqlock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1099,7 +1102,10 @@ linux_dev_kqfilter(struct cdev *dev, struct knote *kn)
|
||||
|
||||
if (error == 0) {
|
||||
linux_set_current(td);
|
||||
linux_dev_kqfilter_poll(filp);
|
||||
|
||||
/* update kqfilter status, if any */
|
||||
linux_dev_kqfilter_poll(filp,
|
||||
LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user