[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>
This commit is contained in:
Davide Libenzi 2006-10-11 01:21:44 -07:00 committed by Linus Torvalds
parent 0f836e5fec
commit b611967de4
4 changed files with 60 additions and 4 deletions

View file

@ -318,3 +318,4 @@ ENTRY(sys_call_table)
.long sys_vmsplice .long sys_vmsplice
.long sys_move_pages .long sys_move_pages
.long sys_getcpu .long sys_getcpu
.long sys_epoll_pwait

View file

@ -105,6 +105,8 @@
/* Maximum msec timeout value storeable in a long int */ /* Maximum msec timeout value storeable in a long int */
#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
struct epoll_filefd { struct epoll_filefd {
struct file *file; struct file *file;
@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)
*/ */
asmlinkage long sys_epoll_create(int size) asmlinkage long sys_epoll_create(int size)
{ {
int error, fd; int error, fd = -1;
struct eventpoll *ep; struct eventpoll *ep;
struct inode *inode; struct inode *inode;
struct file *file; struct file *file;
@ -640,7 +642,6 @@ eexit_1:
return error; return error;
} }
#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
/* /*
* Implement the event wait interface for the eventpoll file. It is the kernel * 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,
current, epfd, events, maxevents, timeout)); current, epfd, events, maxevents, timeout));
/* The maximum number of event must be greater than zero */ /* The maximum number of event must be greater than zero */
if (maxevents <= 0 || maxevents > MAX_EVENTS) if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
return -EINVAL; return -EINVAL;
/* Verify that the area passed by the user is writeable */ /* Verify that the area passed by the user is writeable */
@ -699,6 +700,55 @@ eexit_1:
} }
#ifdef TIF_RESTORE_SIGMASK
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
* part of the user space epoll_pwait(2).
*/
asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout, const sigset_t __user *sigmask,
size_t sigsetsize)
{
int error;
sigset_t ksigmask, sigsaved;
/*
* If the caller wants a certain signal mask to be set during the wait,
* we apply it here.
*/
if (sigmask) {
if (sigsetsize != sizeof(sigset_t))
return -EINVAL;
if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
return -EFAULT;
sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
error = sys_epoll_wait(epfd, events, maxevents, timeout);
/*
* If we changed the signal mask, we need to restore the original one.
* In case we've got a signal while waiting, we do not restore the
* signal mask yet, and we allow do_signal() to deliver the signal on
* the way back to userspace, before the signal mask is restored.
*/
if (sigmask) {
if (error == -EINTR) {
memcpy(&current->saved_sigmask, &sigsaved,
sizeof(sigsaved));
set_thread_flag(TIF_RESTORE_SIGMASK);
} else
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
}
return error;
}
#endif /* #ifdef TIF_RESTORE_SIGMASK */
/* /*
* Creates the file descriptor to be used by the epoll interface. * Creates the file descriptor to be used by the epoll interface.
*/ */

View file

@ -324,10 +324,11 @@
#define __NR_vmsplice 316 #define __NR_vmsplice 316
#define __NR_move_pages 317 #define __NR_move_pages 317
#define __NR_getcpu 318 #define __NR_getcpu 318
#define __NR_epoll_pwait 319
#ifdef __KERNEL__ #ifdef __KERNEL__
#define NR_syscalls 319 #define NR_syscalls 320
#include <linux/err.h> #include <linux/err.h>
/* /*

View file

@ -431,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
struct epoll_event __user *event); struct epoll_event __user *event);
asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout); int maxevents, int timeout);
asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout,
const sigset_t __user *sigmask,
size_t sigsetsize);
asmlinkage long sys_gethostname(char __user *name, int len); asmlinkage long sys_gethostname(char __user *name, int len);
asmlinkage long sys_sethostname(char __user *name, int len); asmlinkage long sys_sethostname(char __user *name, int len);
asmlinkage long sys_setdomainname(char __user *name, int len); asmlinkage long sys_setdomainname(char __user *name, int len);