aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavide Libenzi <davidel@xmailserver.org>2006-10-11 04:21:44 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-11 14:14:21 -0400
commitb611967de4dc5c52049676c4369dcac622a7cdfe (patch)
tree8c19038c8bbaa4851dcb99bed33707deaf5170d1
parent0f836e5fecf59d0d0353e9af11fd14a32a3001ae (diff)
[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>
-rw-r--r--arch/i386/kernel/syscall_table.S1
-rw-r--r--fs/eventpoll.c56
-rw-r--r--include/asm-i386/unistd.h3
-rw-r--r--include/linux/syscalls.h4
4 files changed, 60 insertions, 4 deletions
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 7e639f78b0b9..2697e9210e92 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -318,3 +318,4 @@ ENTRY(sys_call_table)
318 .long sys_vmsplice 318 .long sys_vmsplice
319 .long sys_move_pages 319 .long sys_move_pages
320 .long sys_getcpu 320 .long sys_getcpu
321 .long sys_epoll_pwait
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 557d5b614fae..ae228ec54e94 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -105,6 +105,8 @@
105/* Maximum msec timeout value storeable in a long int */ 105/* Maximum msec timeout value storeable in a long int */
106#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) 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))
109
108 110
109struct epoll_filefd { 111struct epoll_filefd {
110 struct file *file; 112 struct file *file;
@@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)
497 */ 499 */
498asmlinkage long sys_epoll_create(int size) 500asmlinkage long sys_epoll_create(int size)
499{ 501{
500 int error, fd; 502 int error, fd = -1;
501 struct eventpoll *ep; 503 struct eventpoll *ep;
502 struct inode *inode; 504 struct inode *inode;
503 struct file *file; 505 struct file *file;
@@ -640,7 +642,6 @@ eexit_1:
640 return error; 642 return error;
641} 643}
642 644
643#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
644 645
645/* 646/*
646 * Implement the event wait interface for the eventpoll file. It is the kernel 647 * Implement the event wait interface for the eventpoll file. It is the kernel
@@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
657 current, epfd, events, maxevents, timeout)); 658 current, epfd, events, maxevents, timeout));
658 659
659 /* The maximum number of event must be greater than zero */ 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 return -EINVAL; 662 return -EINVAL;
662 663
663 /* Verify that the area passed by the user is writeable */ 664 /* Verify that the area passed by the user is writeable */
@@ -699,6 +700,55 @@ eexit_1:
699} 700}
700 701
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 */
709asmlinkage 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 */
750
751
702/* 752/*
703 * Creates the file descriptor to be used by the epoll interface. 753 * Creates the file descriptor to be used by the epoll interface.
704 */ 754 */
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 3ca7ab963d7d..beeeaf6b054a 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -324,10 +324,11 @@
324#define __NR_vmsplice 316 324#define __NR_vmsplice 316
325#define __NR_move_pages 317 325#define __NR_move_pages 317
326#define __NR_getcpu 318 326#define __NR_getcpu 318
327#define __NR_epoll_pwait 319
327 328
328#ifdef __KERNEL__ 329#ifdef __KERNEL__
329 330
330#define NR_syscalls 319 331#define NR_syscalls 320
331#include <linux/err.h> 332#include <linux/err.h>
332 333
333/* 334/*
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index b0ace3fd7eb9..1912c6cbef55 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -431,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
431 struct epoll_event __user *event); 431 struct epoll_event __user *event);
432asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, 432asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
433 int maxevents, int timeout); 433 int maxevents, int timeout);
434asmlinkage 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);
434asmlinkage long sys_gethostname(char __user *name, int len); 438asmlinkage long sys_gethostname(char __user *name, int len);
435asmlinkage long sys_sethostname(char __user *name, int len); 439asmlinkage long sys_sethostname(char __user *name, int len);
436asmlinkage long sys_setdomainname(char __user *name, int len); 440asmlinkage long sys_setdomainname(char __user *name, int len);