Commit b611967de4dc5c52049676c4369dcac622a7cdfe
Committed by
Linus Torvalds
1 parent
0f836e5fec
Exists in
master
and in
7 other branches
[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
fs/eventpoll.c
... | ... | @@ -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(¤t->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); |