linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] pepoll_wait ...
@ 2006-01-18  3:36 Davide Libenzi
  2006-01-18  4:20 ` Ulrich Drepper
  2006-01-18 18:38 ` Michael Tokarev
  0 siblings, 2 replies; 11+ messages in thread
From: Davide Libenzi @ 2006-01-18  3:36 UTC (permalink / raw)
  To: Linux Kernel Mailing List
  Cc: David Miller, Ulrich Drepper, Andrew Morton, David Woodhouse

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1206 bytes --]


The attached patch implements the pepoll_wait system call, that extend the 
event wait mechanism with the same logic ppoll and pselect do. The definition 
of pepoll_wait is:

int pepoll_wait(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 pepoll_wait is that the 
latter allows the caller to specify a signal mask to be set while waiting for 
events. Hence pepoll_wait will wait until either one monitored event, or an 
unmasked signal happen. If sigmask is NULL, the pepoll_wait 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

This patch goes over 2.6.15-mm4 and depends on the TIF_RESTORE_SIGMASK bits.




Signed-off-by: Davide Libenzi <davidel@xmailserver.org>



- Davide



arch/i386/kernel/syscall_table.S |    1
fs/eventpoll.c                   |   58 ++++++++++++++++++++++++++++++++++-----
include/asm-i386/unistd.h        |    3 +-
include/linux/syscalls.h         |    3 ++
4 files changed, 57 insertions(+), 8 deletions(-)

[-- Attachment #2: Type: TEXT/PLAIN, Size: 5351 bytes --]

diff -Nru linux-2.6.15/arch/i386/kernel/syscall_table.S linux-2.6.15.mod/arch/i386/kernel/syscall_table.S
--- linux-2.6.15/arch/i386/kernel/syscall_table.S	2006-01-17 17:11:12.000000000 -0800
+++ linux-2.6.15.mod/arch/i386/kernel/syscall_table.S	2006-01-17 17:11:59.000000000 -0800
@@ -310,3 +310,4 @@
 	.long sys_pselect6
 	.long sys_ppoll
 	.long sys_unshare		/* 310 */
+	.long sys_pepoll_wait
diff -Nru linux-2.6.15/fs/eventpoll.c linux-2.6.15.mod/fs/eventpoll.c
--- linux-2.6.15/fs/eventpoll.c	2006-01-17 17:11:14.000000000 -0800
+++ linux-2.6.15.mod/fs/eventpoll.c	2006-01-17 17:11:59.000000000 -0800
@@ -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;
@@ -649,24 +651,25 @@
 	return error;
 }
 
-#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
 
 /*
  * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_wait(2).
+ * part of the user space pepoll_wait(2).
  */
-asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
-			       int maxevents, int timeout)
+asmlinkage long sys_pepoll_wait(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;
 	struct file *file;
 	struct eventpoll *ep;
 
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_pepoll_wait(%d, %p, %d, %d)\n",
 		     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 */
@@ -695,13 +698,41 @@
 	 */
 	ep = file->private_data;
 
+	/*
+	 * 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))
+			goto eexit_2;
+		error = -EFAULT;
+		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+			goto eexit_2;
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
 	/* Time to fish for events ... */
 	error = ep_poll(ep, 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 (error == -EINTR) {
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
 eexit_2:
 	fput(file);
 eexit_1:
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_pepoll_wait(%d, %p, %d, %d) = %d\n",
 		     current, epfd, events, maxevents, timeout, error));
 
 	return error;
@@ -709,6 +740,19 @@
 
 
 /*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_wait(2). This just calls the super-sister
+ * sys_pepoll_wait() without signal parameters.
+ */
+asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+			       int maxevents, int timeout)
+{
+
+	return sys_pepoll_wait(epfd, events, maxevents, timeout, NULL, 0);
+}
+
+
+/*
  * Creates the file descriptor to be used by the epoll interface.
  */
 static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
diff -Nru linux-2.6.15/include/asm-i386/unistd.h linux-2.6.15.mod/include/asm-i386/unistd.h
--- linux-2.6.15/include/asm-i386/unistd.h	2006-01-17 17:11:14.000000000 -0800
+++ linux-2.6.15.mod/include/asm-i386/unistd.h	2006-01-17 17:11:59.000000000 -0800
@@ -316,8 +316,9 @@
 #define __NR_pselect6		308
 #define __NR_ppoll		309
 #define __NR_unshare		310
+#define __NR_pepoll_wait	311
 
-#define NR_syscalls 311
+#define NR_syscalls 312
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
diff -Nru linux-2.6.15/include/linux/syscalls.h linux-2.6.15.mod/include/linux/syscalls.h
--- linux-2.6.15/include/linux/syscalls.h	2006-01-17 17:11:15.000000000 -0800
+++ linux-2.6.15.mod/include/linux/syscalls.h	2006-01-17 17:12:59.000000000 -0800
@@ -428,6 +428,9 @@
 				struct epoll_event __user *event);
 asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
 				int maxevents, int timeout);
+asmlinkage long sys_pepoll_wait(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);

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2006-01-18 19:07 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-18  3:36 [PATCH] pepoll_wait Davide Libenzi
2006-01-18  4:20 ` Ulrich Drepper
2006-01-18  5:03   ` Andrew Morton
2006-01-18  7:13     ` David Woodhouse
2006-01-18  7:40     ` Davide Libenzi
2006-01-18  7:48       ` David Woodhouse
2006-01-18  8:14         ` Davide Libenzi
2006-01-18  7:38   ` Davide Libenzi
2006-01-18 18:38 ` Michael Tokarev
2006-01-18 18:51   ` Davide Libenzi
2006-01-18 19:07   ` Ulrich Drepper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).