aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/select.c83
1 files changed, 51 insertions, 32 deletions
diff --git a/fs/select.c b/fs/select.c
index a8109baa5e46..9c4f0f2604f1 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -546,37 +546,38 @@ struct poll_list {
546 546
547#define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd)) 547#define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd))
548 548
549static void do_pollfd(unsigned int num, struct pollfd * fdpage, 549/*
550 poll_table ** pwait, int *count) 550 * Fish for pollable events on the pollfd->fd file descriptor. We're only
551 * interested in events matching the pollfd->events mask, and the result
552 * matching that mask is both recorded in pollfd->revents and returned. The
553 * pwait poll_table will be used by the fd-provided poll handler for waiting,
554 * if non-NULL.
555 */
556static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
551{ 557{
552 int i; 558 unsigned int mask;
553 559 int fd;
554 for (i = 0; i < num; i++) { 560
555 int fd; 561 mask = 0;
556 unsigned int mask; 562 fd = pollfd->fd;
557 struct pollfd *fdp; 563 if (fd >= 0) {
558 564 int fput_needed;
559 mask = 0; 565 struct file * file;
560 fdp = fdpage+i; 566
561 fd = fdp->fd; 567 file = fget_light(fd, &fput_needed);
562 if (fd >= 0) { 568 mask = POLLNVAL;
563 int fput_needed; 569 if (file != NULL) {
564 struct file * file = fget_light(fd, &fput_needed); 570 mask = DEFAULT_POLLMASK;
565 mask = POLLNVAL; 571 if (file->f_op && file->f_op->poll)
566 if (file != NULL) { 572 mask = file->f_op->poll(file, pwait);
567 mask = DEFAULT_POLLMASK; 573 /* Mask out unneeded events. */
568 if (file->f_op && file->f_op->poll) 574 mask &= pollfd->events | POLLERR | POLLHUP;
569 mask = file->f_op->poll(file, *pwait); 575 fput_light(file, fput_needed);
570 mask &= fdp->events | POLLERR | POLLHUP;
571 fput_light(file, fput_needed);
572 }
573 if (mask) {
574 *pwait = NULL;
575 (*count)++;
576 }
577 } 576 }
578 fdp->revents = mask;
579 } 577 }
578 pollfd->revents = mask;
579
580 return mask;
580} 581}
581 582
582static int do_poll(unsigned int nfds, struct poll_list *list, 583static int do_poll(unsigned int nfds, struct poll_list *list,
@@ -594,11 +595,29 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
594 long __timeout; 595 long __timeout;
595 596
596 set_current_state(TASK_INTERRUPTIBLE); 597 set_current_state(TASK_INTERRUPTIBLE);
597 walk = list; 598 for (walk = list; walk != NULL; walk = walk->next) {
598 while(walk != NULL) { 599 struct pollfd * pfd, * pfd_end;
599 do_pollfd( walk->len, walk->entries, &pt, &count); 600
600 walk = walk->next; 601 pfd = walk->entries;
602 pfd_end = pfd + walk->len;
603 for (; pfd != pfd_end; pfd++) {
604 /*
605 * Fish for events. If we found one, record it
606 * and kill the poll_table, so we don't
607 * needlessly register any other waiters after
608 * this. They'll get immediately deregistered
609 * when we break out and return.
610 */
611 if (do_pollfd(pfd, pt)) {
612 count++;
613 pt = NULL;
614 }
615 }
601 } 616 }
617 /*
618 * All waiters have already been registered, so don't provide
619 * a poll_table to them on the next loop iteration.
620 */
602 pt = NULL; 621 pt = NULL;
603 if (count || !*timeout || signal_pending(current)) 622 if (count || !*timeout || signal_pending(current))
604 break; 623 break;