Commit b611967de4dc5c52049676c4369dcac622a7cdfe

Authored by Davide Libenzi
Committed by Linus Torvalds
1 parent 0f836e5fec

[PATCH] epoll_pwait()

Implement the epoll_pwait system call, that extend the event wait mechanism
with the same logic ppoll and pselect do.  The definition of epoll_pwait
is:

int epoll_pwait(int epfd, struct epoll_event *events, int maxevents,
                 int timeout, const sigset_t *sigmask, size_t sigsetsize);

The difference between the vanilla epoll_wait and epoll_pwait is that the
latter allows the caller to specify a signal mask to be set while waiting
for events.  Hence epoll_pwait will wait until either one monitored event,
or an unmasked signal happen.  If sigmask is NULL, the epoll_pwait system
call will act exactly like epoll_wait.  For the POSIX definition of
pselect, information is available here:

http://www.opengroup.org/onlinepubs/009695399/functions/select.html

Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Andi Kleen <ak@muc.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 4 changed files with 60 additions and 4 deletions Side-by-side Diff

arch/i386/kernel/syscall_table.S
... ... @@ -318,4 +318,5 @@
318 318 .long sys_vmsplice
319 319 .long sys_move_pages
320 320 .long sys_getcpu
  321 + .long sys_epoll_pwait
... ... @@ -105,7 +105,9 @@
105 105 /* Maximum msec timeout value storeable in a long int */
106 106 #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
107 107  
  108 +#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
108 109  
  110 +
109 111 struct epoll_filefd {
110 112 struct file *file;
111 113 int fd;
... ... @@ -497,7 +499,7 @@
497 499 */
498 500 asmlinkage long sys_epoll_create(int size)
499 501 {
500   - int error, fd;
  502 + int error, fd = -1;
501 503 struct eventpoll *ep;
502 504 struct inode *inode;
503 505 struct file *file;
... ... @@ -640,7 +642,6 @@
640 642 return error;
641 643 }
642 644  
643   -#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
644 645  
645 646 /*
646 647 * Implement the event wait interface for the eventpoll file. It is the kernel
... ... @@ -657,7 +658,7 @@
657 658 current, epfd, events, maxevents, timeout));
658 659  
659 660 /* The maximum number of event must be greater than zero */
660   - if (maxevents <= 0 || maxevents > MAX_EVENTS)
  661 + if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
661 662 return -EINVAL;
662 663  
663 664 /* Verify that the area passed by the user is writeable */
... ... @@ -697,6 +698,55 @@
697 698  
698 699 return error;
699 700 }
  701 +
  702 +
  703 +#ifdef TIF_RESTORE_SIGMASK
  704 +
  705 +/*
  706 + * Implement the event wait interface for the eventpoll file. It is the kernel
  707 + * part of the user space epoll_pwait(2).
  708 + */
  709 +asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
  710 + int maxevents, int timeout, const sigset_t __user *sigmask,
  711 + size_t sigsetsize)
  712 +{
  713 + int error;
  714 + sigset_t ksigmask, sigsaved;
  715 +
  716 + /*
  717 + * If the caller wants a certain signal mask to be set during the wait,
  718 + * we apply it here.
  719 + */
  720 + if (sigmask) {
  721 + if (sigsetsize != sizeof(sigset_t))
  722 + return -EINVAL;
  723 + if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
  724 + return -EFAULT;
  725 + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
  726 + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
  727 + }
  728 +
  729 + error = sys_epoll_wait(epfd, events, maxevents, timeout);
  730 +
  731 + /*
  732 + * If we changed the signal mask, we need to restore the original one.
  733 + * In case we've got a signal while waiting, we do not restore the
  734 + * signal mask yet, and we allow do_signal() to deliver the signal on
  735 + * the way back to userspace, before the signal mask is restored.
  736 + */
  737 + if (sigmask) {
  738 + if (error == -EINTR) {
  739 + memcpy(&current->saved_sigmask, &sigsaved,
  740 + sizeof(sigsaved));
  741 + set_thread_flag(TIF_RESTORE_SIGMASK);
  742 + } else
  743 + sigprocmask(SIG_SETMASK, &sigsaved, NULL);
  744 + }
  745 +
  746 + return error;
  747 +}
  748 +
  749 +#endif /* #ifdef TIF_RESTORE_SIGMASK */
700 750  
701 751  
702 752 /*
include/asm-i386/unistd.h
... ... @@ -324,10 +324,11 @@
324 324 #define __NR_vmsplice 316
325 325 #define __NR_move_pages 317
326 326 #define __NR_getcpu 318
  327 +#define __NR_epoll_pwait 319
327 328  
328 329 #ifdef __KERNEL__
329 330  
330   -#define NR_syscalls 319
  331 +#define NR_syscalls 320
331 332 #include <linux/err.h>
332 333  
333 334 /*
include/linux/syscalls.h
... ... @@ -431,6 +431,10 @@
431 431 struct epoll_event __user *event);
432 432 asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
433 433 int maxevents, int timeout);
  434 +asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
  435 + int maxevents, int timeout,
  436 + const sigset_t __user *sigmask,
  437 + size_t sigsetsize);
434 438 asmlinkage long sys_gethostname(char __user *name, int len);
435 439 asmlinkage long sys_sethostname(char __user *name, int len);
436 440 asmlinkage long sys_setdomainname(char __user *name, int len);