diff options
Diffstat (limited to 'fs/select.c')
| -rw-r--r-- | fs/select.c | 83 |
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 | ||
| 549 | static 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 | */ | ||
| 556 | static 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 | ||
| 582 | static int do_poll(unsigned int nfds, struct poll_list *list, | 583 | static 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; |
