Skip to content

Commit

Permalink
[PATCH] epoll_pwait()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: Michael Kerrisk <[email protected]>
Cc: Ulrich Drepper <[email protected]>
Cc: Roland McGrath <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
davidel authored and Linus Torvalds committed Oct 11, 2006
1 parent 0f836e5 commit b611967
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 4 deletions.
1 change: 1 addition & 0 deletions arch/i386/kernel/syscall_table.S
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,4 @@ ENTRY(sys_call_table)
.long sys_vmsplice
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
56 changes: 53 additions & 3 deletions fs/eventpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
/* 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_EVENTS (INT_MAX / sizeof(struct epoll_event))


struct epoll_filefd {
struct file *file;
Expand Down Expand Up @@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)
*/
asmlinkage long sys_epoll_create(int size)
{
int error, fd;
int error, fd = -1;
struct eventpoll *ep;
struct inode *inode;
struct file *file;
Expand Down Expand Up @@ -640,7 +642,6 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
return error;
}

#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))

/*
* Implement the event wait interface for the eventpoll file. It is the kernel
Expand All @@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
current, epfd, events, maxevents, timeout));

/* 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;

/* Verify that the area passed by the user is writeable */
Expand Down Expand Up @@ -699,6 +700,55 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
}


#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.
*/
Expand Down
3 changes: 2 additions & 1 deletion include/asm-i386/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,11 @@
#define __NR_vmsplice 316
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319

#ifdef __KERNEL__

#define NR_syscalls 319
#define NR_syscalls 320
#include <linux/err.h>

/*
Expand Down
4 changes: 4 additions & 0 deletions include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
struct epoll_event __user *event);
asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
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_sethostname(char __user *name, int len);
asmlinkage long sys_setdomainname(char __user *name, int len);
Expand Down

0 comments on commit b611967

Please sign in to comment.