Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 295229
b: refs/heads/master
c: 626cf23
h: refs/heads/master
i:
  295227: b8c3b51
v: v3
  • Loading branch information
Hans Verkuil authored and Linus Torvalds committed Mar 23, 2012
1 parent 89f586e commit d4f9601
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 34 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5cde7656d0dd222170eb0250bd1f70c9018fd438
refs/heads/master: 626cf236608505d376e4799adb4f7eb00a8594af
18 changes: 15 additions & 3 deletions trunk/fs/eventpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,12 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
void *priv)
{
struct epitem *epi, *tmp;
poll_table pt;

init_poll_funcptr(&pt, NULL);
list_for_each_entry_safe(epi, tmp, head, rdllink) {
if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
pt._key = epi->event.events;
if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
epi->event.events)
return POLLIN | POLLRDNORM;
else {
Expand Down Expand Up @@ -1097,6 +1100,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
/* Initialize the poll table using the queue callback */
epq.epi = epi;
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
epq.pt._key = event->events;

/*
* Attach the item to the poll hooks and get current event bits.
Expand Down Expand Up @@ -1191,20 +1195,24 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
{
int pwake = 0;
unsigned int revents;
poll_table pt;

init_poll_funcptr(&pt, NULL);

/*
* Set the new event interest mask before calling f_op->poll();
* otherwise we might miss an event that happens between the
* f_op->poll() call and the new event set registering.
*/
epi->event.events = event->events;
pt._key = event->events;
epi->event.data = event->data; /* protected by mtx */

/*
* Get current event bits. We can safely use the file* here because
* its usage count has been increased by the caller of this function.
*/
revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt);

/*
* If the item is "hot" and it is not registered inside the ready
Expand Down Expand Up @@ -1239,6 +1247,9 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
unsigned int revents;
struct epitem *epi;
struct epoll_event __user *uevent;
poll_table pt;

init_poll_funcptr(&pt, NULL);

/*
* We can loop without lock because we are passed a task private list.
Expand All @@ -1251,7 +1262,8 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,

list_del_init(&epi->rdllink);

revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
pt._key = epi->event.events;
revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
epi->event.events;

/*
Expand Down
40 changes: 18 additions & 22 deletions trunk/fs/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
get_file(filp);
entry->filp = filp;
entry->wait_address = wait_address;
entry->key = p->key;
entry->key = p->_key;
init_waitqueue_func_entry(&entry->wait, pollwake);
entry->wait.private = pwq;
add_wait_queue(wait_address, &entry->wait);
Expand Down Expand Up @@ -386,13 +386,11 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds)
static inline void wait_key_set(poll_table *wait, unsigned long in,
unsigned long out, unsigned long bit)
{
if (wait) {
wait->key = POLLEX_SET;
if (in & bit)
wait->key |= POLLIN_SET;
if (out & bit)
wait->key |= POLLOUT_SET;
}
wait->_key = POLLEX_SET;
if (in & bit)
wait->_key |= POLLIN_SET;
if (out & bit)
wait->_key |= POLLOUT_SET;
}

int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
Expand All @@ -414,7 +412,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
poll_initwait(&table);
wait = &table.pt;
if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
wait = NULL;
wait->_qproc = NULL;
timed_out = 1;
}

Expand Down Expand Up @@ -459,17 +457,17 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit;
retval++;
wait = NULL;
wait->_qproc = NULL;
}
if ((mask & POLLOUT_SET) && (out & bit)) {
res_out |= bit;
retval++;
wait = NULL;
wait->_qproc = NULL;
}
if ((mask & POLLEX_SET) && (ex & bit)) {
res_ex |= bit;
retval++;
wait = NULL;
wait->_qproc = NULL;
}
}
}
Expand All @@ -481,7 +479,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
*rexp = res_ex;
cond_resched();
}
wait = NULL;
wait->_qproc = NULL;
if (retval || timed_out || signal_pending(current))
break;
if (table.error) {
Expand Down Expand Up @@ -720,7 +718,7 @@ struct poll_list {
* interested in events matching the pollfd->events mask, and the result
* matching that mask is both recorded in pollfd->revents and returned. The
* pwait poll_table will be used by the fd-provided poll handler for waiting,
* if non-NULL.
* if pwait->_qproc is non-NULL.
*/
static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
Expand All @@ -738,9 +736,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll) {
if (pwait)
pwait->key = pollfd->events |
POLLERR | POLLHUP;
pwait->_key = pollfd->events|POLLERR|POLLHUP;
mask = file->f_op->poll(file, pwait);
}
/* Mask out unneeded events. */
Expand All @@ -763,7 +759,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list,

/* Optimise the no-wait case */
if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
pt = NULL;
pt->_qproc = NULL;
timed_out = 1;
}

Expand All @@ -781,22 +777,22 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
for (; pfd != pfd_end; pfd++) {
/*
* Fish for events. If we found one, record it
* and kill the poll_table, so we don't
* and kill poll_table->_qproc, so we don't
* needlessly register any other waiters after
* this. They'll get immediately deregistered
* when we break out and return.
*/
if (do_pollfd(pfd, pt)) {
count++;
pt = NULL;
pt->_qproc = NULL;
}
}
}
/*
* All waiters have already been registered, so don't provide
* a poll_table to them on the next loop iteration.
* a poll_table->_qproc to them on the next loop iteration.
*/
pt = NULL;
pt->_qproc = NULL;
if (!count) {
count = wait->error;
if (signal_pending(current))
Expand Down
37 changes: 31 additions & 6 deletions trunk/include/linux/poll.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,46 @@ struct poll_table_struct;
*/
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);

/*
* Do not touch the structure directly, use the access functions
* poll_does_not_wait() and poll_requested_events() instead.
*/
typedef struct poll_table_struct {
poll_queue_proc qproc;
unsigned long key;
poll_queue_proc _qproc;
unsigned long _key;
} poll_table;

static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (p && wait_address)
p->qproc(filp, wait_address, p);
if (p && p->_qproc && wait_address)
p->_qproc(filp, wait_address, p);
}

/*
* Return true if it is guaranteed that poll will not wait. This is the case
* if the poll() of another file descriptor in the set got an event, so there
* is no need for waiting.
*/
static inline bool poll_does_not_wait(const poll_table *p)
{
return p == NULL || p->_qproc == NULL;
}

/*
* Return the set of events that the application wants to poll for.
* This is useful for drivers that need to know whether a DMA transfer has
* to be started implicitly on poll(). You typically only want to do that
* if the application is actually polling for POLLIN and/or POLLOUT.
*/
static inline unsigned long poll_requested_events(const poll_table *p)
{
return p ? p->_key : ~0UL;
}

static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
{
pt->qproc = qproc;
pt->key = ~0UL; /* all events enabled */
pt->_qproc = qproc;
pt->_key = ~0UL; /* all events enabled */
}

struct poll_table_entry {
Expand Down
2 changes: 1 addition & 1 deletion trunk/include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -1854,7 +1854,7 @@ static inline bool wq_has_sleeper(struct socket_wq *wq)
static inline void sock_poll_wait(struct file *filp,
wait_queue_head_t *wait_address, poll_table *p)
{
if (p && wait_address) {
if (!poll_does_not_wait(p) && wait_address) {
poll_wait(filp, wait_address, p);
/*
* We need to be sure we are in sync with the
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/unix/af_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -2206,7 +2206,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
}

/* No write status requested, avoid expensive OUT tests. */
if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT)))
if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
return mask;

writable = unix_writable(sk);
Expand Down

0 comments on commit d4f9601

Please sign in to comment.