linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] [1/6] Add pselect/ppoll system call implementation
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
@ 2006-01-10 20:18 ` David Woodhouse
  2006-01-13 11:40   ` Andrew Morton
  2006-01-10 20:18 ` [PATCH] [2/6] TIF_RESTORE_SIGMASK support for arch/powerpc David Woodhouse
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:18 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

This patch adds the pselect() and ppoll() system calls, providing core
routines usable by the original select() and poll() system calls and
also the new calls (with their semantics w.r.t timeouts).

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 fs/compat.c           |  252 +++++++++++++++++++++++++++++++------
 fs/select.c           |  337 +++++++++++++++++++++++++++++++++++++++++---------
 include/linux/poll.h  |    6 
 include/linux/sched.h |    1 
 4 files changed, 501 insertions(+), 95 deletions(-)

diff --git a/fs/compat.c b/fs/compat.c
index 271b75d..e18a7e6 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -53,6 +53,8 @@
 #include <asm/mmu_context.h>
 #include <asm/ioctls.h>
 
+extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
+
 /*
  * Not all architectures have sys_utime, so implement this in terms
  * of sys_utimes.
@@ -1621,36 +1623,14 @@ static void select_bits_free(void *bits,
 #define MAX_SELECT_SECONDS \
 	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-asmlinkage long
-compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
-		compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
+int compat_core_sys_select(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp, int64_t *timeout)
 {
 	fd_set_bits fds;
 	char *bits;
-	long timeout;
 	int size, max_fdset, ret = -EINVAL;
 	struct fdtable *fdt;
 
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
-		    || __get_user(sec, &tvp->tv_sec)
-		    || __get_user(usec, &tvp->tv_usec)) {
-			ret = -EFAULT;
-			goto out_nofds;
-		}
-
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
 	if (n < 0)
 		goto out_nofds;
 
@@ -1687,19 +1667,7 @@ compat_sys_select(int n, compat_ulong_t 
 	zero_fd_set(n, fds.res_out);
 	zero_fd_set(n, fds.res_ex);
 
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		if (put_user(sec, &tvp->tv_sec) ||
-		    put_user(usec, &tvp->tv_usec))
-			ret = -EFAULT;
-	}
+	ret = do_select(n, &fds, timeout);
 
 	if (ret < 0)
 		goto out;
@@ -1720,6 +1688,216 @@ out_nofds:
 	return ret;
 }
 
+asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timeval __user *tvp)
+{
+	int64_t timeout = -1;
+	struct compat_timeval tv;
+	int ret;
+
+	if (tvp) {
+		if (copy_from_user(&tv, tvp, sizeof(tv)))
+			return -EFAULT;
+
+		if (tv.tv_sec < 0 || tv.tv_usec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)tv.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
+			timeout += tv.tv_sec * HZ;
+		}
+	}
+
+	ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tvp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		tv.tv_usec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ));
+		tv.tv_sec = timeout;
+		if (copy_to_user(tvp, &tv, sizeof(tv))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
+	compat_size_t sigsetsize)
+{
+	compat_sigset_t s32;
+	sigset_t ksigmask, sigsaved;
+	long timeout = MAX_SCHEDULE_TIMEOUT;
+	struct compat_timespec ts;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+			return -EINVAL;
+	}
+
+	if (sigmask) {
+		if (sigsetsize != sizeof(compat_sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&s32, sigmask, sizeof(s32)))
+			return -EFAULT;
+		sigset_from_compat(&ksigmask, &s32);
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	do {
+		if (tsp) {
+			if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
+				timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+				timeout += ts.tv_sec * (unsigned long)HZ;
+				ts.tv_sec = 0;
+				ts.tv_nsec = 0;
+			} else {
+				ts.tv_sec -= MAX_SELECT_SECONDS;
+				timeout = MAX_SELECT_SECONDS * HZ;
+			}
+		}
+
+		ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
+
+	} while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));
+
+	if (tsp && !(current->personality & STICKY_TIMEOUTS)) {
+		ts.tv_sec += timeout / HZ;
+		ts.tv_nsec += (timeout % HZ) * (1000000000/HZ);
+		if (ts.tv_nsec >= 1000000000) {
+			ts.tv_sec++;
+			ts.tv_nsec -= 1000000000;
+		}
+		(void)copy_to_user(tsp, &ts, sizeof(ts));
+	}
+
+	if (ret == -ERESTARTNOHAND) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	return ret;
+}
+
+asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timespec __user *tsp, void __user *sig)
+{
+	compat_size_t sigsetsize = 0;
+	compat_uptr_t up = 0;
+
+	if (sig) {
+		if (!access_ok(VERIFY_READ, sig,
+				sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
+		    	__get_user(up, (compat_uptr_t __user *)sig) ||
+		    	__get_user(sigsetsize,
+				(compat_size_t __user *)(sig+sizeof(up))))
+			return -EFAULT;
+	}
+	return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up),
+					sigsetsize);
+}
+
+asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
+	unsigned int nfds, struct compat_timespec __user *tsp,
+	const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
+{
+	compat_sigset_t s32;
+	sigset_t ksigmask, sigsaved;
+	struct compat_timespec ts;
+	int64_t timeout = -1;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		/* We assume that ts.tv_sec is always lower than
+		   the number of seconds that can be expressed in
+		   an int64_t. Otherwise the compiler bitches at us */
+		timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+		timeout += ts.tv_sec * HZ;
+	}
+
+	if (sigmask) {
+		if (sigsetsize |= sizeof(compat_sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&s32, sigmask, sizeof(s32)))
+			return -EFAULT;
+		sigset_from_compat(&ksigmask, &s32);
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	ret = do_sys_poll(ufds, nfds, &timeout);
+
+	/* We can restart this syscall, usually */
+	if (ret == -EINTR) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+		ret = -ERESTARTNOHAND;
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	if (tsp && timeout >= 0) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		/* Yes, we know it's actually an int64_t, but it's also positive. */
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND && timeout >= 0)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+#endif /* TIF_RESTORE_SIGMASK */
+
 #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 /* Stuff for NFS server syscalls... */
 struct compat_nfsctl_svc {
diff --git a/fs/select.c b/fs/select.c
index f10a103..4e0da96 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -179,12 +179,11 @@ get_max:
 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 #define POLLEX_SET (POLLPRI)
 
-int do_select(int n, fd_set_bits *fds, long *timeout)
+int do_select(int n, fd_set_bits *fds, int64_t *timeout)
 {
 	struct poll_wqueues table;
 	poll_table *wait;
 	int retval, i;
-	long __timeout = *timeout;
 
 	rcu_read_lock();
 	retval = max_select_fd(n, fds);
@@ -196,11 +195,12 @@ int do_select(int n, fd_set_bits *fds, l
 
 	poll_initwait(&table);
 	wait = &table.pt;
-	if (!__timeout)
+	if (!*timeout)
 		wait = NULL;
 	retval = 0;
 	for (;;) {
 		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
+		long __timeout;
 
 		set_current_state(TASK_INTERRUPTIBLE);
 
@@ -255,22 +255,32 @@ int do_select(int n, fd_set_bits *fds, l
 				*rexp = res_ex;
 		}
 		wait = NULL;
-		if (retval || !__timeout || signal_pending(current))
+		if (retval || !*timeout || signal_pending(current))
 			break;
 		if(table.error) {
 			retval = table.error;
 			break;
 		}
+
+		if (*timeout < 0) {
+			/* Wait indefinitely */
+			__timeout = MAX_SCHEDULE_TIMEOUT;
+		} else if (unlikely(*timeout >= (int64_t)MAX_SCHEDULE_TIMEOUT - 1)) {
+			/* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
+			__timeout = MAX_SCHEDULE_TIMEOUT - 1;
+			*timeout -= __timeout;
+		} else {
+			__timeout = *timeout;
+			*timeout = 0;
+		}
 		__timeout = schedule_timeout(__timeout);
+		if (*timeout >= 0)
+			*timeout += __timeout;
 	}
 	__set_current_state(TASK_RUNNING);
 
 	poll_freewait(&table);
 
-	/*
-	 * Up-to-date the caller timeout.
-	 */
-	*timeout = __timeout;
 	return retval;
 }
 
@@ -295,36 +305,14 @@ static void select_bits_free(void *bits,
 #define MAX_SELECT_SECONDS \
 	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-asmlinkage long
-sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp)
+static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+			   fd_set __user *exp, int64_t *timeout)
 {
 	fd_set_bits fds;
 	char *bits;
-	long timeout;
 	int ret, size, max_fdset;
 	struct fdtable *fdt;
 
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
-		    || __get_user(sec, &tvp->tv_sec)
-		    || __get_user(usec, &tvp->tv_usec)) {
-			ret = -EFAULT;
-			goto out_nofds;
-		}
-
-		ret = -EINVAL;
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
 	ret = -EINVAL;
 	if (n < 0)
 		goto out_nofds;
@@ -362,18 +350,7 @@ sys_select(int n, fd_set __user *inp, fd
 	zero_fd_set(n, fds.res_out);
 	zero_fd_set(n, fds.res_ex);
 
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
+	ret = do_select(n, &fds, timeout);
 
 	if (ret < 0)
 		goto out;
@@ -395,6 +372,150 @@ out_nofds:
 	return ret;
 }
 
+asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+			fd_set __user *exp, struct timeval __user *tvp)
+{
+	int64_t timeout = -1;
+	struct timeval tv;
+	int ret;
+
+	if (tvp) {
+		if (copy_from_user(&tv, tvp, sizeof(tv)))
+			return -EFAULT;
+
+		if (tv.tv_sec < 0 || tv.tv_usec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)tv.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
+			timeout += tv.tv_sec * HZ;
+		}
+	}
+
+	ret = core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tvp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		tv.tv_usec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ));
+		tv.tv_sec = timeout;
+		if (copy_to_user(tvp, &tv, sizeof(tv))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
+		fd_set __user *exp, struct timespec __user *tsp,
+		const sigset_t __user *sigmask, size_t sigsetsize)
+{
+	int64_t timeout = MAX_SCHEDULE_TIMEOUT;
+	sigset_t ksigmask, sigsaved;
+	struct timespec ts;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)ts.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout += ts.tv_sec * HZ;
+		}
+	}
+
+	if (sigmask) {
+		/* XXX: Don't preclude handling different sized sigset_t's.  */
+		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);
+	}
+
+	ret = core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tsp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	if (ret == -ERESTARTNOHAND) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	return ret;
+}
+
+/*
+ * Most architectures can't handle 7-argument syscalls. So we provide a
+ * 6-argument version where the sixth argument is a pointer to a structure
+ * which has a pointer to the sigset_t itself followed by a size_t containing
+ * the sigset size.
+ */
+asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp,
+	fd_set __user *exp, struct timespec __user *tsp, void __user *sig)
+{
+	size_t sigsetsize = 0;
+	sigset_t __user *up = NULL;
+
+	if (sig) {
+		if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
+		    || __get_user(up, (sigset_t * __user *)sig)
+		    || __get_user(sigsetsize,
+				(size_t * __user)(sig+sizeof(void *))))
+			return -EFAULT;
+	}
+
+	return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize);
+}
+#endif /* TIF_RESTORE_SIGMASK */
+
 struct poll_list {
 	struct poll_list *next;
 	int len;
@@ -436,16 +557,19 @@ static void do_pollfd(unsigned int num, 
 }
 
 static int do_poll(unsigned int nfds,  struct poll_list *list,
-			struct poll_wqueues *wait, long timeout)
+		   struct poll_wqueues *wait, int64_t *timeout)
 {
 	int count = 0;
 	poll_table* pt = &wait->pt;
 
-	if (!timeout)
+	/* Optimise the no-wait case */
+	if (!(*timeout))
 		pt = NULL;
  
 	for (;;) {
 		struct poll_list *walk;
+		long __timeout;
+
 		set_current_state(TASK_INTERRUPTIBLE);
 		walk = list;
 		while(walk != NULL) {
@@ -453,18 +577,33 @@ static int do_poll(unsigned int nfds,  s
 			walk = walk->next;
 		}
 		pt = NULL;
-		if (count || !timeout || signal_pending(current))
+		if (count || !*timeout || signal_pending(current))
 			break;
 		count = wait->error;
 		if (count)
 			break;
-		timeout = schedule_timeout(timeout);
+
+		if (*timeout < 0) {
+			/* Wait indefinitely */
+			__timeout = MAX_SCHEDULE_TIMEOUT;
+		} else if (unlikely(*timeout >= (int64_t)MAX_SCHEDULE_TIMEOUT - 1)) {
+			/* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
+			__timeout = MAX_SCHEDULE_TIMEOUT - 1;
+			*timeout -= __timeout;
+		} else {
+			__timeout = *timeout;
+			*timeout = 0;
+		}
+
+		__timeout = schedule_timeout(__timeout);
+		if (*timeout >= 0)
+			*timeout += __timeout;
 	}
 	__set_current_state(TASK_RUNNING);
 	return count;
 }
 
-asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout)
+int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, int64_t *timeout)
 {
 	struct poll_wqueues table;
  	int fdcount, err;
@@ -482,14 +621,6 @@ asmlinkage long sys_poll(struct pollfd _
 	if (nfds > max_fdset && nfds > OPEN_MAX)
 		return -EINVAL;
 
-	if (timeout) {
-		/* Careful about overflow in the intermediate values */
-		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
-			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
-		else /* Negative or overflow */
-			timeout = MAX_SCHEDULE_TIMEOUT;
-	}
-
 	poll_initwait(&table);
 
 	head = NULL;
@@ -519,6 +650,7 @@ asmlinkage long sys_poll(struct pollfd _
 		}
 		i -= pp->len;
 	}
+
 	fdcount = do_poll(nfds, head, &table, timeout);
 
 	/* OK, now copy the revents fields back to user space. */
@@ -547,3 +679,94 @@ out_fds:
 	poll_freewait(&table);
 	return err;
 }
+
+asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
+			long timeout_msecs)
+{
+	int64_t timeout_jiffies = 0;
+
+	if (timeout_msecs) {
+#if HZ > 1000
+		/* We can only overflow if HZ > 1000 */
+		if (timeout_msecs / 1000 > (int64_t)0x7fffffffffffffffULL / (int64_t)HZ)
+			timeout_jiffies = -1;
+		else
+#endif
+			timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+	}
+
+	return do_sys_poll(ufds, nfds, &timeout_jiffies);
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
+	struct timespec __user *tsp, const sigset_t __user *sigmask,
+	size_t sigsetsize)
+{
+	sigset_t ksigmask, sigsaved;
+	struct timespec ts;
+	int64_t timeout = -1;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)ts.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout += ts.tv_sec * HZ;
+		}
+	}
+
+	if (sigmask) {
+		/* XXX: Don't preclude handling different sized sigset_t's.  */
+		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);
+	}
+
+	ret = do_sys_poll(ufds, nfds, &timeout);
+
+	/* We can restart this syscall, usually */
+	if (ret == -EINTR) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+		ret = -ERESTARTNOHAND;
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	if (tsp && timeout >= 0) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		/* Yes, we know it's actually an int64_t, but it's also positive. */
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND && timeout >= 0)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+#endif /* TIF_RESTORE_SIGMASK */
diff --git a/include/linux/poll.h b/include/linux/poll.h
index f6da702..5b9c85c 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -92,7 +92,11 @@ void zero_fd_set(unsigned long nr, unsig
 	memset(fdset, 0, FDS_BYTES(nr));
 }
 
-extern int do_select(int n, fd_set_bits *fds, long *timeout);
+#define MAX_INT64_SECONDS (((int64_t)(~((uint64_t)0)>>1)/HZ)-1)
+
+extern int do_select(int n, fd_set_bits *fds, int64_t *timeout);
+extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
+		       int64_t *timeout);
 
 #endif /* KERNEL */
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c4ee35d..1be70cf 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -798,6 +798,7 @@ struct task_struct {
 	struct sighand_struct *sighand;
 
 	sigset_t blocked, real_blocked;
+	sigset_t saved_sigmask;		/* To be restored with TIF_RESTORE_SIGMASK */
 	struct sigpending pending;
 
 	unsigned long sas_ss_sp;

-- 
dwmw2


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

* [PATCH] [2/6] TIF_RESTORE_SIGMASK support for arch/powerpc
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
  2006-01-10 20:18 ` [PATCH] [1/6] Add pselect/ppoll system call implementation David Woodhouse
@ 2006-01-10 20:18 ` David Woodhouse
  2006-01-10 20:18 ` [PATCH] [3/6] Generic sys_rt_sigsuspend() David Woodhouse
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:18 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

This patch implements the TIF_RESTORE_SIGMASK flag in the new
arch/powerpc kernel, for both 32-bit and 64-bit system call paths.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 arch/powerpc/kernel/entry_32.S    |    8 ++++----
 arch/powerpc/kernel/entry_64.S    |    2 +-
 arch/powerpc/kernel/signal_32.c   |   20 +++++++++++++++-----
 arch/powerpc/kernel/signal_64.c   |   20 ++++++++++++++++++--
 arch/powerpc/kernel/systbl.S      |    2 ++
 include/asm-powerpc/thread_info.h |    5 ++++-
 include/asm-powerpc/unistd.h      |    4 +++-
 7 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 036b71d..6aa7386 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -227,7 +227,7 @@ ret_from_syscall:
 	MTMSRD(r10)
 	lwz	r9,TI_FLAGS(r12)
 	li	r8,-_LAST_ERRNO
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK)
 	bne-	syscall_exit_work
 	cmplw	0,r3,r8
 	blt+	syscall_exit_cont
@@ -357,7 +357,7 @@ save_user_nvgprs_cont:
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_PR
 	beq	ret_from_except
-	andi.	r0,r9,_TIF_SIGPENDING
+	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
 	beq	ret_from_except
 	b	do_user_signal
 8:
@@ -683,7 +683,7 @@ user_exc_return:		/* r10 contains MSR_KE
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK)
 	bne	do_work
 
 restore_user:
@@ -917,7 +917,7 @@ recheck:
 	lwz	r9,TI_FLAGS(r9)
 	andi.	r0,r9,_TIF_NEED_RESCHED
 	bne-	do_resched
-	andi.	r0,r9,_TIF_SIGPENDING
+	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
 	beq	restore_user
 do_user_signal:			/* r10 contains MSR_KERNEL here */
 	ori	r10,r10,MSR_EE
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index aacebb3..b267045 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -160,7 +160,7 @@ syscall_exit:
 	mtmsrd	r10,1
 	ld	r9,TI_FLAGS(r12)
 	li	r11,-_LAST_ERRNO
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR|_TIF_RESTORE_SIGMASK)
 	bne-	syscall_exit_work
 	cmpld	r3,r11
 	ld	r5,_CCR(r1)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d3f0b6d..784a4c2 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1177,7 +1177,7 @@ int do_signal(sigset_t *oldset, struct p
 {
 	siginfo_t info;
 	struct k_sigaction ka;
-	unsigned int frame, newsp;
+	unsigned int newsp;
 	int signr, ret;
 
 #ifdef CONFIG_PPC32
@@ -1188,11 +1188,11 @@ int do_signal(sigset_t *oldset, struct p
 	}
 #endif
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else if (!oldset)
 		oldset = &current->blocked;
 
-	newsp = frame = 0;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 #ifdef CONFIG_PPC32
 no_signal:
@@ -1222,8 +1222,14 @@ no_signal:
 		}
 	}
 
-	if (signr == 0)
+	if (signr == 0) {
+		/* No signal to deliver -- put the saved sigmask back */
+		if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
+			sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+		}
 		return 0;		/* no signals delivered */
+	}
 
 	if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
 	    && !on_sig_stack(regs->gpr[1]))
@@ -1256,6 +1262,10 @@ no_signal:
 			sigaddset(&current->blocked, signr);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
+		/* A signal was successfully delivered; the saved sigmask is in
+		   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
+		if (test_thread_flag(TIF_RESTORE_SIGMASK))
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
 	}
 
 	return ret;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 5462bef..2903e11 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -554,11 +554,15 @@ int do_signal(sigset_t *oldset, struct p
 	if (test_thread_flag(TIF_32BIT))
 		return do_signal32(oldset, regs);
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else if (!oldset)
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
+		int ret;
+
 		/* Whee!  Actually deliver the signal.  */
 		if (TRAP(regs) == 0x0C00)
 			syscall_restart(regs, &ka);
@@ -571,7 +575,14 @@ int do_signal(sigset_t *oldset, struct p
 		if (current->thread.dabr)
 			set_dabr(current->thread.dabr);
 
-		return handle_signal(signr, &ka, &info, oldset, regs);
+		ret = handle_signal(signr, &ka, &info, oldset, regs);
+
+		/* If a signal was successfully delivered, the saved sigmask is in
+		   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
+		if (ret && test_thread_flag(TIF_RESTORE_SIGMASK))
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+		return ret;
 	}
 
 	if (TRAP(regs) == 0x0C00) {	/* System Call! */
@@ -587,6 +598,11 @@ int do_signal(sigset_t *oldset, struct p
 			regs->result = 0;
 		}
 	}
+	/* No signal to deliver -- put the saved sigmask back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 6801317..007b15e 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -321,3 +321,5 @@ SYSCALL(inotify_add_watch)
 SYSCALL(inotify_rm_watch)
 SYSCALL(spu_run)
 SYSCALL(spu_create)
+COMPAT_SYS(pselect6)
+COMPAT_SYS(ppoll)
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index ac1e80e..27f1312 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -125,6 +125,7 @@ static inline struct thread_info *curren
 #define TIF_RESTOREALL		12	/* Restore all regs (implies NOERROR) */
 #define TIF_SAVE_NVGPRS		13	/* Save r14-r31 in signal frame */
 #define TIF_NOERROR		14	/* Force successful syscall return */
+#define TIF_RESTORE_SIGMASK	15	/* Restore signal mask in do_signal */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -141,10 +142,12 @@ static inline struct thread_info *curren
 #define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
 #define _TIF_SAVE_NVGPRS	(1<<TIF_SAVE_NVGPRS)
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
-				 _TIF_NEED_RESCHED | _TIF_RESTOREALL)
+				 _TIF_NEED_RESCHED | _TIF_RESTOREALL | \
+				 _TIF_RESTORE_SIGMASK)
 #define _TIF_PERSYSCALL_MASK	(_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS)
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 19eaac3..e9cb713 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -298,8 +298,10 @@
 #define __NR_inotify_rm_watch	277
 #define __NR_spu_run		278
 #define __NR_spu_create		279
+#define __NR_pselect6		280
+#define __NR_ppoll		281
 
-#define __NR_syscalls		280
+#define __NR_syscalls		282
 
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit

-- 
dwmw2


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

* [PATCH] [3/6] Generic sys_rt_sigsuspend()
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
  2006-01-10 20:18 ` [PATCH] [1/6] Add pselect/ppoll system call implementation David Woodhouse
  2006-01-10 20:18 ` [PATCH] [2/6] TIF_RESTORE_SIGMASK support for arch/powerpc David Woodhouse
@ 2006-01-10 20:18 ` David Woodhouse
  2006-01-10 20:19 ` [PATCH] [4/6] Handle TIF_RESTORE_SIGMASK for FRV David Woodhouse
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:18 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

The TIF_RESTORE_SIGMASK flag allows us to have a generic implementation
of sys_rt_sigsuspend() instead of duplicating it for each architecture.
This provides such an implementation and makes arch/powerpc use it.

It also tidies up the ppc32 sys_sigsuspend() to use TIF_RESTORE_SIGMASK.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 arch/powerpc/kernel/signal_32.c |   56 +++-------------------------------------
 arch/powerpc/kernel/signal_64.c |   36 -------------------------
 include/asm-powerpc/unistd.h    |    2 +
 kernel/compat.c                 |   28 ++++++++++++++++++++
 kernel/signal.c                 |   26 ++++++++++++++++++
 5 files changed, 61 insertions(+), 87 deletions(-)

diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 784a4c2..a12d0a5 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -252,8 +252,7 @@ int do_signal(sigset_t *oldset, struct p
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
-	       struct pt_regs *regs)
+long sys_sigsuspend(old_sigset_t mask)
 {
 	sigset_t saveset;
 
@@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, i
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
-}
-
-long sys_rt_sigsuspend(
-#ifdef CONFIG_PPC64
-		compat_sigset_t __user *unewset,
-#else
-		sigset_t __user *unewset,
-#endif
-		size_t sigsetsize, int p3, int p4,
-		int p6, int p7, struct pt_regs *regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (get_sigset_t(&newset, unewset))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
+ 	current->state = TASK_INTERRUPTIBLE;
+ 	schedule();
+ 	set_thread_flag(TIF_RESTORE_SIGMASK);
+ 	return -ERESTARTNOHAND;
 }
 
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 2903e11..7a6f0f7 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -67,42 +67,6 @@ struct rt_sigframe {
 	char abigap[288];
 } __attribute__ ((aligned (16)));
 
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4,
-		       int p6, int p7, struct pt_regs *regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&newset, unewset, sizeof(newset)))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
-}
-
 long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
 		     unsigned long r6, unsigned long r7, unsigned long r8,
 		     struct pt_regs *regs)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index e9cb713..a40cdff 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -446,11 +446,13 @@ type name(type1 arg1, type2 arg2, type3 
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #ifdef CONFIG_PPC32
 #define __ARCH_WANT_OLD_STAT
 #endif
 #ifdef CONFIG_PPC64
 #define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #endif
 
 /*
diff --git a/kernel/compat.c b/kernel/compat.c
index 256e5d9..da03f69 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -871,3 +871,31 @@ asmlinkage long compat_sys_stime(compat_
 }
 
 #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
+
+#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
+{
+	sigset_t newset;
+	compat_sigset_t newset32;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
+		return -EFAULT;
+	sigset_from_compat(&newset, &newset32);
+	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+	spin_lock_irq(&current->sighand->siglock);
+	current->saved_sigmask = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
+}
+#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
diff --git a/kernel/signal.c b/kernel/signal.c
index 08aa5b2..f859761 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2720,6 +2720,32 @@ sys_pause(void)
 
 #endif
 
+#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
+long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
+{
+	sigset_t newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+	spin_lock_irq(&current->sighand->siglock);
+	current->saved_sigmask = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
+}
+#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+
 void __init signals_init(void)
 {
 	sigqueue_cachep =

-- 
dwmw2


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

* [PATCH] [4/6] Handle TIF_RESTORE_SIGMASK for FRV
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
                   ` (2 preceding siblings ...)
  2006-01-10 20:18 ` [PATCH] [3/6] Generic sys_rt_sigsuspend() David Woodhouse
@ 2006-01-10 20:19 ` David Woodhouse
  2006-01-10 20:19 ` [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386 David Woodhouse
  2006-01-10 20:23 ` [PATCH] [6/6] Add pselect/ppoll system calls on i386 David Woodhouse
  5 siblings, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:19 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

The attached patch handles TIF_RESTORE_SIGMASK as added by David Woodhouse's
patch entitled:

        [PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
        [PATCH] 3/3 Generic sys_rt_sigsuspend

It does the following:

 (1) Declares TIF_RESTORE_SIGMASK for FRV.

 (2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.

 (3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
     in current->saved_sigmask.

 (4) Discards sys_rt_sigsuspend() from the arch, using the generic one instead.

 (5) Makes sys_sigsuspend() save the signal mask and set TIF_RESTORE_SIGMASK
     rather than attempting to fudge the return registers.

 (6) Makes sys_sigsuspend() return -ERESTARTNOHAND rather than looping
     intrinsically.

 (7) Makes setup_frame(), setup_rt_frame() and handle_signal() return 0 or
     -EFAULT rather than true/false to be consistent with the rest of the
      kernel.

Due to the fact do_signal() is then only called from one place:

 (8) Make do_signal() no longer have a return value is it was just being
     ignored; force_sig() takes care of this.

 (9) Discards the old sigmask argument to do_signal() as it's no longer
     necessary.

This patch depends on the FRV signalling patches as well as the
sys_rt_sigsuspend patch.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 arch/frv/kernel/signal.c      |  120 +++++++++++++++---------------------------
 include/asm-frv/thread_info.h |    2 
 include/asm-frv/unistd.h      |    1 
 3 files changed, 47 insertions(+), 76 deletions(-)

diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 5b7146f..679c1d5 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -35,74 +35,22 @@ struct fdpic_func_descriptor {
 	unsigned long	GOT;
 };
 
-static int do_signal(sigset_t *oldset);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	sigset_t saveset;
-
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
+	current->saved_sigmask = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	__frame->gr8 = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset))
-			/* return the signal number as the return value of this function
-			 * - this is an utterly evil hack. syscalls should not invoke do_signal()
-			 *   as entry.S sets regs->gr8 to the return value of the system call
-			 * - we can't just use sigpending() as we'd have to discard SIG_IGN signals
-			 *   and call waitpid() if SIGCHLD needed discarding
-			 * - this only works on the i386 because it passes arguments to the signal
-			 *   handler on the stack, and the return value in EAX is effectively
-			 *   discarded
-			 */
-			return __frame->gr8;
-	}
-}
-
-asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&newset, unewset, sizeof(newset)))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	__frame->gr8 = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset))
-			/* return the signal number as the return value of this function
-			 * - this is an utterly evil hack. syscalls should not invoke do_signal()
-			 *   as entry.S sets regs->gr8 to the return value of the system call
-			 * - we can't just use sigpending() as we'd have to discard SIG_IGN signals
-			 *   and call waitpid() if SIGCHLD needed discarding
-			 * - this only works on the i386 because it passes arguments to the signal
-			 *   handler on the stack, and the return value in EAX is effectively
-			 *   discarded
-			 */
-			return __frame->gr8;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 asmlinkage int sys_sigaction(int sig,
@@ -372,11 +320,11 @@ static int setup_frame(int sig, struct k
 	       frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sig(SIGSEGV, current);
-	return 0;
+	return -EFAULT;
 
 } /* end setup_frame() */
 
@@ -471,11 +419,11 @@ static int setup_rt_frame(int sig, struc
 	       frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sig(SIGSEGV, current);
-	return 0;
+	return -EFAULT;
 
 } /* end setup_rt_frame() */
 
@@ -516,7 +464,7 @@ static int handle_signal(unsigned long s
 	else
 		ret = setup_frame(sig, ka, oldset);
 
-	if (ret) {
+	if (ret == 0) {
 		spin_lock_irq(&current->sighand->siglock);
 		sigorsets(&current->blocked, &current->blocked,
 			  &ka->sa.sa_mask);
@@ -536,10 +484,11 @@ static int handle_signal(unsigned long s
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-static int do_signal(sigset_t *oldset)
+static void do_signal(void)
 {
 	struct k_sigaction ka;
 	siginfo_t info;
+	sigset_t *oldset;
 	int signr;
 
 	/*
@@ -549,43 +498,62 @@ static int do_signal(sigset_t *oldset)
 	 * if so.
 	 */
 	if (!user_mode(__frame))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, __frame, NULL);
-	if (signr > 0)
-		return handle_signal(signr, &info, &ka, oldset);
+	if (signr > 0) {
+		if (handle_signal(signr, &info, &ka, oldset) == 0) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+
+		return;
+	}
 
 no_signal:
 	/* Did we come from a system call? */
 	if (__frame->syscallno >= 0) {
 		/* Restart the system call - no handlers present */
-		if (__frame->gr8 == -ERESTARTNOHAND ||
-		    __frame->gr8 == -ERESTARTSYS ||
-		    __frame->gr8 == -ERESTARTNOINTR) {
+		switch (__frame->gr8) {
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
 			__frame->gr8 = __frame->orig_gr8;
 			__frame->pc -= 4;
-		}
+			break;
 
-		if (__frame->gr8 == -ERESTART_RESTARTBLOCK){
+		case -ERESTART_RESTARTBLOCK:
 			__frame->gr8 = __NR_restart_syscall;
 			__frame->pc -= 4;
+			break;
 		}
 	}
 
-	return 0;
+	/* if there's no signal to deliver, we just put the saved sigmask
+	 * back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 
 } /* end do_signal() */
 
 /*****************************************************************************/
 /*
  * notification of userspace execution resumption
- * - triggered by current->work.notify_resume
+ * - triggered by the TIF_WORK_MASK flags
  */
 asmlinkage void do_notify_resume(__u32 thread_info_flags)
 {
@@ -594,7 +562,7 @@ asmlinkage void do_notify_resume(__u32 t
 		clear_thread_flag(TIF_SINGLESTEP);
 
 	/* deal with pending signal delivery */
-	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(NULL);
+	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+		do_signal();
 
 } /* end do_notify_resume() */
diff --git a/include/asm-frv/thread_info.h b/include/asm-frv/thread_info.h
index 60f6b2a..0429ca7 100644
--- a/include/asm-frv/thread_info.h
+++ b/include/asm-frv/thread_info.h
@@ -131,6 +131,7 @@ register struct thread_info *__current_t
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_IRET		5	/* return with iret */
+#define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* OOM killer killed process */
 
@@ -140,6 +141,7 @@ register struct thread_info *__current_t
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_IRET		(1 << TIF_IRET)
+#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index cde376a..4d994d2 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -486,6 +486,7 @@ static inline pid_t wait(int * wait_stat
 /* #define __ARCH_WANT_SYS_SIGPENDING */
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #endif
 
 /*

-- 
dwmw2


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

* [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
                   ` (3 preceding siblings ...)
  2006-01-10 20:19 ` [PATCH] [4/6] Handle TIF_RESTORE_SIGMASK for FRV David Woodhouse
@ 2006-01-10 20:19 ` David Woodhouse
  2006-01-13  3:59   ` Andrew Morton
  2006-01-10 20:23 ` [PATCH] [6/6] Add pselect/ppoll system calls on i386 David Woodhouse
  5 siblings, 1 reply; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:19 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

The attached patch handles TIF_RESTORE_SIGMASK as added by David Woodhouse's
patch entitled:

        [PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
        [PATCH] 3/3 Generic sys_rt_sigsuspend

It does the following:

 (1) Declares TIF_RESTORE_SIGMASK for i386.

 (2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.

 (3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
     in current->saved_sigmask.

 (4) Discards sys_rt_sigsuspend() from the arch, using the generic one instead.

 (5) Makes sys_sigsuspend() save the signal mask and set TIF_RESTORE_SIGMASK
     rather than attempting to fudge the return registers.

 (6) Makes sys_sigsuspend() return -ERESTARTNOHAND rather than looping
     intrinsically.

 (7) Makes setup_frame(), setup_rt_frame() and handle_signal() return 0 or
     -EFAULT rather than true/false to be consistent with the rest of the
     kernel.

Due to the fact do_signal() is then only called from one place:

 (8) Makes do_signal() no longer have a return value is it was just being
     ignored; force_sig() takes care of this.

 (9) Discards the old sigmask argument to do_signal() as it's no longer
     necessary.

(10) Makes do_signal() static.

(11) Marks the second argument to do_notify_resume() as unused. The unused
     argument should remain in the middle as the arguments are passed in as
     registers, and the ordering is specific in entry.S

Given the way do_signal() is now no longer called from sys_{,rt_}sigsuspend(),
they no longer need access to the exception frame, and so can just take
arguments normally.

This patch depends on sys_rt_sigsuspend patch.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 arch/i386/kernel/signal.c      |  109 ++++++++++++++++++-----------------------
 include/asm-i386/signal.h      |    1 
 include/asm-i386/thread_info.h |    2 
 include/asm-i386/unistd.h      |    1 
 4 files changed, 51 insertions(+), 62 deletions(-)

diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index adcd069..963616d 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -37,51 +37,17 @@
 asmlinkage int
 sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	struct pt_regs * regs = (struct pt_regs *) &history0;
-	sigset_t saveset;
-
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
+	current->saved_sigmask = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs->eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
-}
-
-asmlinkage int
-sys_rt_sigsuspend(struct pt_regs regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (regs.ecx != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&newset, (sigset_t __user *)regs.ebx, sizeof(newset)))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs.eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&regs, &saveset))
-			return -EINTR;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 asmlinkage int 
@@ -433,11 +399,11 @@ static int setup_frame(int sig, struct k
 		current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
-	return 0;
+	return -EFAULT;
 }
 
 static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -527,11 +493,11 @@ static int setup_rt_frame(int sig, struc
 		current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
-	return 0;
+	return -EFAULT;
 }
 
 /*
@@ -581,7 +547,7 @@ handle_signal(unsigned long sig, siginfo
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ret) {
+	if (ret == 0) {
 		spin_lock_irq(&current->sighand->siglock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -598,11 +564,12 @@ handle_signal(unsigned long sig, siginfo
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void fastcall do_signal(struct pt_regs *regs)
 {
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
+	sigset_t *oldset;
 
 	/*
 	 * We want the common case to go fast, which
@@ -613,12 +580,14 @@ int fastcall do_signal(struct pt_regs *r
  	 * CS suffices.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -628,38 +597,55 @@ int fastcall do_signal(struct pt_regs *r
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		if (unlikely(current->thread.debugreg[7])) {
+		if (unlikely(current->thread.debugreg[7]))
 			set_debugreg(current->thread.debugreg[7], 7);
-		}
 
 		/* Whee!  Actually deliver the signal.  */
-		return handle_signal(signr, &info, &ka, oldset, regs);
+		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+
+		return;
 	}
 
- no_signal:
+no_signal:
 	/* Did we come from a system call? */
 	if (regs->orig_eax >= 0) {
 		/* Restart the system call - no handlers present */
-		if (regs->eax == -ERESTARTNOHAND ||
-		    regs->eax == -ERESTARTSYS ||
-		    regs->eax == -ERESTARTNOINTR) {
+		switch (regs->eax) {
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
 			regs->eax = regs->orig_eax;
 			regs->eip -= 2;
-		}
-		if (regs->eax == -ERESTART_RESTARTBLOCK){
+			break;
+
+		case -ERESTART_RESTARTBLOCK:
 			regs->eax = __NR_restart_syscall;
 			regs->eip -= 2;
+			break;
 		}
 	}
-	return 0;
+
+	/* if there's no signal to deliver, we just put the saved sigmask
+	 * back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 }
 
 /*
  * notification of userspace execution resumption
- * - triggered by current->work.notify_resume
+ * - triggered by the TIF_WORK_MASK flags
  */
 __attribute__((regparm(3)))
-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+void do_notify_resume(struct pt_regs *regs, void *_unused,
 		      __u32 thread_info_flags)
 {
 	/* Pending single-step? */
@@ -667,9 +653,10 @@ void do_notify_resume(struct pt_regs *re
 		regs->eflags |= TF_MASK;
 		clear_thread_flag(TIF_SINGLESTEP);
 	}
+
 	/* deal with pending signal delivery */
-	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(regs,oldset);
+	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+		do_signal(regs);
 	
 	clear_thread_flag(TIF_IRET);
 }
diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h
index 76524b4..026fd23 100644
--- a/include/asm-i386/signal.h
+++ b/include/asm-i386/signal.h
@@ -218,7 +218,6 @@ static __inline__ int sigfindinword(unsi
 }
 
 struct pt_regs;
-extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 #define ptrace_signal_deliver(regs, cookie)		\
 	do {						\
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 8fbf791..d080eea 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -142,6 +142,7 @@ register unsigned long current_stack_poi
 #define TIF_SYSCALL_EMU		6	/* syscall emulation active */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
+#define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 
@@ -154,6 +155,7 @@ register unsigned long current_stack_poi
 #define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 481c3c0..4a8d5ae 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -417,6 +417,7 @@ __syscall_return(type,__res); \
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #endif
 
 #ifdef __KERNEL_SYSCALLS__

-- 
dwmw2


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

* [PATCH] [6/6] Add pselect/ppoll system calls on i386
       [not found] <1136923488.3435.78.camel@localhost.localdomain>
                   ` (4 preceding siblings ...)
  2006-01-10 20:19 ` [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386 David Woodhouse
@ 2006-01-10 20:23 ` David Woodhouse
  5 siblings, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-10 20:23 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, drepper

This patch adds the sys_pselect6() and sys_poll() calls to the i386 syscall
table.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

 arch/i386/kernel/syscall_table.S |    2 ++
 include/asm-i386/unistd.h        |    4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 6ff3e52..14fb84e 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -294,3 +294,5 @@ ENTRY(sys_call_table)
 	.long sys_inotify_add_watch
 	.long sys_inotify_rm_watch
 	.long sys_migrate_pages
+	.long sys_pselect6		/* 295 */
+	.long sys_ppoll
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 4a8d5ae..f2eace9 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -300,8 +300,10 @@
 #define __NR_inotify_add_watch	292
 #define __NR_inotify_rm_watch	293
 #define __NR_migrate_pages	294
+#define __NR_pselect6		295
+#define __NR_ppoll		296
 
-#define NR_syscalls 295
+#define NR_syscalls 297
 
 /*
  * user-visible error numbers are in the range -1 - -128: see

-- 
dwmw2


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-10 20:19 ` [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386 David Woodhouse
@ 2006-01-13  3:59   ` Andrew Morton
  2006-01-13  4:30     ` David Woodhouse
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  3:59 UTC (permalink / raw)
  To: David Woodhouse; +Cc: torvalds, linux-kernel, drepper, David Howells

David Woodhouse <dwmw2@infradead.org> wrote:
>
> The attached patch handles TIF_RESTORE_SIGMASK as added by David Woodhouse's
> patch entitled:
> 
>         [PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
>         [PATCH] 3/3 Generic sys_rt_sigsuspend
> 
> It does the following:
> 
>  (1) Declares TIF_RESTORE_SIGMASK for i386.
> 
>  (2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.
> 
>  (3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
>      in current->saved_sigmask.
> 
>  (4) Discards sys_rt_sigsuspend() from the arch, using the generic one instead.
> 
>  (5) Makes sys_sigsuspend() save the signal mask and set TIF_RESTORE_SIGMASK
>      rather than attempting to fudge the return registers.
> 
>  (6) Makes sys_sigsuspend() return -ERESTARTNOHAND rather than looping
>      intrinsically.
> 
>  (7) Makes setup_frame(), setup_rt_frame() and handle_signal() return 0 or
>      -EFAULT rather than true/false to be consistent with the rest of the
>      kernel.
> 
> Due to the fact do_signal() is then only called from one place:
> 
>  (8) Makes do_signal() no longer have a return value is it was just being
>      ignored; force_sig() takes care of this.
> 
>  (9) Discards the old sigmask argument to do_signal() as it's no longer
>      necessary.
> 
> (10) Makes do_signal() static.
> 
> (11) Marks the second argument to do_notify_resume() as unused. The unused
>      argument should remain in the middle as the arguments are passed in as
>      registers, and the ordering is specific in entry.S
> 
> Given the way do_signal() is now no longer called from sys_{,rt_}sigsuspend(),
> they no longer need access to the exception frame, and so can just take
> arguments normally.
> 
> This patch depends on sys_rt_sigsuspend patch.

I have problems with this patch.

With

	generic-sys_rt_sigsuspend.patch
	handle-tif_restore_sigmask-for-frv.patch
	handle-tif_restore_sigmask-for-i386.patch

applied, or with all of David's patches applied, an FC5-test1 machine hangs
during the login process (local vt or sshd).  An FC1 machine doesn't
exhibit the problem.

dmesg+sysrq-t:
	http://www.zip.com.au/~akpm/linux/patches/stuff/dmesg

.config:
	http://www.zip.com.au/~akpm/linux/patches/stuff/config-sony

culprit patches:
	http://www.zip.com.au/~akpm/linux/patches/stuff/generic-sys_rt_sigsuspend.patch
	http://www.zip.com.au/~akpm/linux/patches/stuff/handle-tif_restore_sigmask-for-i386.patch

(I retested with just current -linus and the above two patches.  Same
deal).


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  3:59   ` Andrew Morton
@ 2006-01-13  4:30     ` David Woodhouse
  2006-01-13  4:54       ` Andrew Morton
  0 siblings, 1 reply; 19+ messages in thread
From: David Woodhouse @ 2006-01-13  4:30 UTC (permalink / raw)
  To: Andrew Morton; +Cc: torvalds, linux-kernel, drepper, David Howells

On Thu, 2006-01-12 at 19:59 -0800, Andrew Morton wrote:
> applied, or with all of David's patches applied, an FC5-test1 machine hangs
> during the login process (local vt or sshd).  An FC1 machine doesn't
> exhibit the problem.

So the 'successful' login reported at 19:21:45 never actually completed
and gave you a shell?

I can't make out which process it is that's misbehaving... and your
login was pid 2292 but I don't see your SysRq-T output going up that
far. Am I missing something?

I note you're running auditd -- FC5-test1 enabled syscall auditing by
default. Does the problem persist if you prevent the auditd initscript
from starting up? If so, let's turn auditing back on and actually make
use of it -- assuming the offending process is actually one of your own
after the login has changed uid, can you set an audit rule to log all
syscalls from your own userid? (add '-Aexit,always -Fuid=500'
to /etc/audit.rules, assuming 500 is your own uid). Then show me the
appropriate section from /var/log/audit/audit.log. 

I tested both with and without audit on PPC -- David, did you test this
patch with auditing enabled on i386?

Will attempt to reproduce locally... I've _also_ seen login hangs on
current linus trees but they've been different (and on that machine I
haven't had the TIF_RESTORE_SIGMASK patches either). It happens on disk
activity though -- after 'rpm -i <kernelpackage>' the whole machine
locks up and I have no more file system access. If your SysRq-T got to
the disk, I suspect you aren't seeing the same problem.

-- 
dwmw2


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  4:30     ` David Woodhouse
@ 2006-01-13  4:54       ` Andrew Morton
  2006-01-13  5:11         ` David Woodhouse
  2006-01-13  6:10         ` Andrew Morton
  0 siblings, 2 replies; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  4:54 UTC (permalink / raw)
  To: David Woodhouse; +Cc: torvalds, linux-kernel, drepper, dhowells

David Woodhouse <dwmw2@infradead.org> wrote:
>
> On Thu, 2006-01-12 at 19:59 -0800, Andrew Morton wrote:
> > applied, or with all of David's patches applied, an FC5-test1 machine hangs
> > during the login process (local vt or sshd).  An FC1 machine doesn't
> > exhibit the problem.
> 
> So the 'successful' login reported at 19:21:45 never actually completed
> and gave you a shell?

Yup.

> I can't make out which process it is that's misbehaving... and your
> login was pid 2292 but I don't see your SysRq-T output going up that
> far. Am I missing something?

Yes, that dmesg output seems to have been truncated.

Here's another one, better:

	http://www.zip.com.au/~akpm/linux/patches/stuff/dmesg

Note that I have /bin/zsh in /etc/passwd.

> I note you're running auditd -- FC5-test1 enabled syscall auditing by
> default.

This is basically the fc5-t1 .config, only it has selinux turned off due to
earlier problems.  Suggest you base testing on my config-sony.

> Does the problem persist if you prevent the auditd initscript
> from starting up?

<chkconfig auditd off>
<reboot>
<problem persists>

> If so, let's turn auditing back on

<chkconfig auditd on>

> and actually make
> use of it -- assuming the offending process is actually one of your own
> after the login has changed uid, can you set an audit rule to log all
> syscalls from your own userid? (add '-Aexit,always -Fuid=500'
> to /etc/audit.rules, assuming 500 is your own uid). Then show me the
> appropriate section from /var/log/audit/audit.log. 

<does that>
<reboots>
<logs in>

You wouldn't believe how much stuff that produces.  Or maybe you would.

<several minutes pass, disk LED flashing>

<crap starts scrolling past too fast to read.  Some complaint from auditd, afaict>

<does alt-SUB>

<grabs the last bit of auditd.log>

	http://www.zip.com.au/~akpm/linux/patches/stuff/auditd.log

That looks like the crap I saw scrolling past.  How come it came out on the
console after a few minutes?

> I tested both with and without audit on PPC -- David, did you test this
> patch with auditing enabled on i386?
> 
> Will attempt to reproduce locally... I've _also_ seen login hangs on
> current linus trees but they've been different (and on that machine I
> haven't had the TIF_RESTORE_SIGMASK patches either). It happens on disk
> activity though -- after 'rpm -i <kernelpackage>' the whole machine
> locks up and I have no more file system access. If your SysRq-T got to
> the disk, I suspect you aren't seeing the same problem.

Sounds like the jens-barrier-bug.  Fixed in current -linus.

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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  4:54       ` Andrew Morton
@ 2006-01-13  5:11         ` David Woodhouse
  2006-01-13  6:10         ` Andrew Morton
  1 sibling, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-13  5:11 UTC (permalink / raw)
  To: Andrew Morton; +Cc: sgrubb, torvalds, linux-kernel, drepper, dhowells

On Thu, 2006-01-12 at 20:54 -0800, Andrew Morton wrote:
> Yes, that dmesg output seems to have been truncated.
> 
> Here's another one, better:
> 
> 	http://www.zip.com.au/~akpm/linux/patches/stuff/dmesg
> 
> Note that I have /bin/zsh in /etc/passwd.

Indeed better; thanks. Will ponder and attempt to reproduce here on
i386.

> That looks like the crap I saw scrolling past.  How come it came out on the
> console after a few minutes?

Not sure. That probably means the kernel has decided that your userspace
audit dæmon has gone AWOL.... and indeed it seems to be stuck on a
futex. I know of no reason why it should be doing that -- Steve?

-- 
dwmw2


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  4:54       ` Andrew Morton
  2006-01-13  5:11         ` David Woodhouse
@ 2006-01-13  6:10         ` Andrew Morton
  2006-01-13  6:23           ` David Woodhouse
  1 sibling, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  6:10 UTC (permalink / raw)
  To: dwmw2, torvalds, linux-kernel, drepper, dhowells

Andrew Morton <akpm@osdl.org> wrote:
>
>  Note that I have /bin/zsh in /etc/passwd.
>

It's zsh.  I can log in as root (root uses bash) and just type "zsh" and
zsh gets stuck chewing 100% CPU.  strace says:


rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)
rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)

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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  6:10         ` Andrew Morton
@ 2006-01-13  6:23           ` David Woodhouse
  2006-01-13  8:28             ` David Woodhouse
  0 siblings, 1 reply; 19+ messages in thread
From: David Woodhouse @ 2006-01-13  6:23 UTC (permalink / raw)
  To: Andrew Morton; +Cc: torvalds, linux-kernel, drepper, dhowells

On Thu, 2006-01-12 at 22:10 -0800, Andrew Morton wrote:
> rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
> rt_sigsuspend(~[HUP CHLD RTMIN RT_1])   = -1 EINVAL (Invalid argument)

OK, that makes it easier to track down -- thanks. Unfortunately my
scratch i386 box in the office hasn't rebooted onto my test kernel so
it'll have to wait until (a sensible hour in) the morning.

I suspect it might be the sigset size. We have a whole bunch of 

	/* XXX: Don't preclude handling different sized sigset_t's.  */
	if (sigsetsize != sizeof(sigset_t))
		return -EINVAL;

-- 
dwmw2


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  6:23           ` David Woodhouse
@ 2006-01-13  8:28             ` David Woodhouse
  2006-01-13  8:48               ` Andrew Morton
  2006-01-13  9:18               ` Andrew Morton
  0 siblings, 2 replies; 19+ messages in thread
From: David Woodhouse @ 2006-01-13  8:28 UTC (permalink / raw)
  To: Andrew Morton; +Cc: torvalds, linux-kernel, drepper, dhowells

On Fri, 2006-01-13 at 06:23 +0000, David Woodhouse wrote:
> I suspect it might be the sigset size. 

I bet this is it, although I haven't yet confirmed the theory....

Sorry, I should have tested this for myself on i386 before forwarding
the patch. Stupid bloody legacy architecture :)

--- linux-2.6.15.ppc/kernel/compat.c~	2006-01-13 04:39:54.000000000 +0000
+++ linux-2.6.15.ppc/kernel/compat.c	2006-01-13 08:23:24.000000000 +0000
@@ -873,7 +873,7 @@ asmlinkage long compat_sys_stime(compat_
 #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
 
 #ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
-long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
+asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
 {
 	sigset_t newset;
 	compat_sigset_t newset32;
--- linux-2.6.15.ppc/kernel/signal.c~	2006-01-13 04:39:54.000000000 +0000
+++ linux-2.6.15.ppc/kernel/signal.c	2006-01-13 08:23:29.000000000 +0000
@@ -2761,7 +2761,7 @@ sys_pause(void)
 #endif
 
 #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
 {
 	sigset_t newset;
 

-- 
dwmw2


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  8:28             ` David Woodhouse
@ 2006-01-13  8:48               ` Andrew Morton
  2006-01-13  8:51                 ` Andrew Morton
  2006-01-13  9:18               ` Andrew Morton
  1 sibling, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  8:48 UTC (permalink / raw)
  To: David Woodhouse; +Cc: torvalds, linux-kernel, drepper, dhowells

David Woodhouse <dwmw2@infradead.org> wrote:
>
> On Fri, 2006-01-13 at 06:23 +0000, David Woodhouse wrote:
> > I suspect it might be the sigset size. 
> 
> I bet this is it, although I haven't yet confirmed the theory....
> 
> Sorry, I should have tested this for myself on i386 before forwarding
> the patch. Stupid bloody legacy architecture :)
> 
> --- linux-2.6.15.ppc/kernel/compat.c~	2006-01-13 04:39:54.000000000 +0000
> +++ linux-2.6.15.ppc/kernel/compat.c	2006-01-13 08:23:24.000000000 +0000
> @@ -873,7 +873,7 @@ asmlinkage long compat_sys_stime(compat_
>  #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
>  
>  #ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
> -long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
> +asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
>  {
>  	sigset_t newset;
>  	compat_sigset_t newset32;
> --- linux-2.6.15.ppc/kernel/signal.c~	2006-01-13 04:39:54.000000000 +0000
> +++ linux-2.6.15.ppc/kernel/signal.c	2006-01-13 08:23:29.000000000 +0000
> @@ -2761,7 +2761,7 @@ sys_pause(void)
>  #endif
>  
>  #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
> -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
> +asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
>  {
>  	sigset_t newset;

I gues we want that, but x86 doesn't compile kernel/compat.c

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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  8:48               ` Andrew Morton
@ 2006-01-13  8:51                 ` Andrew Morton
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  8:51 UTC (permalink / raw)
  To: dwmw2, torvalds, linux-kernel, drepper, dhowells

Andrew Morton <akpm@osdl.org> wrote:
>
> but x86 doesn't compile kernel/compat.c

But it usually compiles singal.c ;)  Hang on a mo..

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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
  2006-01-13  8:28             ` David Woodhouse
  2006-01-13  8:48               ` Andrew Morton
@ 2006-01-13  9:18               ` Andrew Morton
  1 sibling, 0 replies; 19+ messages in thread
From: Andrew Morton @ 2006-01-13  9:18 UTC (permalink / raw)
  To: David Woodhouse; +Cc: torvalds, linux-kernel, drepper, dhowells

David Woodhouse <dwmw2@infradead.org> wrote:
>
> -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
>  +asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)

Fixed, thanks.

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

* Re: [PATCH] [1/6] Add pselect/ppoll system call implementation
  2006-01-10 20:18 ` [PATCH] [1/6] Add pselect/ppoll system call implementation David Woodhouse
@ 2006-01-13 11:40   ` Andrew Morton
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Morton @ 2006-01-13 11:40 UTC (permalink / raw)
  To: David Woodhouse; +Cc: torvalds, linux-kernel, drepper

David Woodhouse <dwmw2@infradead.org> wrote:
>
> This patch adds the pselect() and ppoll() system calls, providing core
>  routines usable by the original select() and poll() system calls and
>  also the new calls (with their semantics w.r.t timeouts).

This patch sends python into a busywait:

root      2041 98.6  0.4  11192  4656 ?        R    02:36   5:29 python ./hpssd.py

strace says:

select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)
select(6, [4 5], [], [], {0, 500000})   = 0 (Timeout)


The below fixes it.

A few slipups here, so please can you re-review the code that lands in next
-mm, make sure we got everything?


--- devel/fs/select.c~add-pselect-ppoll-system-call-implementation-fix	2006-01-13 03:24:53.000000000 -0800
+++ devel-akpm/fs/select.c	2006-01-13 03:30:27.000000000 -0800
@@ -390,7 +390,7 @@ asmlinkage long sys_select(int n, fd_set
 		if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
+			timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
 			timeout += tv.tv_sec * HZ;
 		}
 	}
@@ -441,7 +441,7 @@ asmlinkage long sys_pselect7(int n, fd_s
 		if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
 			timeout += ts.tv_sec * HZ;
 		}
 	}
@@ -723,7 +723,7 @@ asmlinkage long sys_ppoll(struct pollfd 
 		if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
 			timeout += ts.tv_sec * HZ;
 		}
 	}
_


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

* Re: [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
@ 2006-01-15 18:17 Oleg Nesterov
  0 siblings, 0 replies; 19+ messages in thread
From: Oleg Nesterov @ 2006-01-15 18:17 UTC (permalink / raw)
  To: David Woodhouse, David Howells
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Linus Torvalds, Jeff Dike

David Woodhouse wrote:
>
> The attached patch handles TIF_RESTORE_SIGMASK as added by David Woodhouse's
> patch entitled:
>
>         [PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
>         [PATCH] 3/3 Generic sys_rt_sigsuspend
>
> It does the following:
>
>  (1) Declares TIF_RESTORE_SIGMASK for i386.
>
>  (2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.
>
>  (3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
>      in current->saved_sigmask.

Imho, there is a slightly better way to do it, see the patch below.

Instead of adding TIF_RESTORE_SIGMASK we can introduce ERESTART_SIGBLOCK
return value. Now,

sys_rt_sigsuspend(sigset_t *newset)
{
	current->saved_sigmask = current->blocked;
	current->blocked = newset;

	current->state = TASK_INTERRUPTIBLE;
	schedule();
	return -ERESTART_SIGBLOCK;
}

sys_pselect()
{
	...

	ret = core_sys_select();

	if (ret == -ERESTARTNOHAND)
		ret = -ERESTART_SIGBLOCK;
}

handle_signal()
{
	sigset_t *oldset; // removed from param list

	...

	oldset = &current->blocked;
	if (regs->eax == -ERESTART_SIGBLOCK)
		oldset = &current->saved_sigmask;

	...
}

Comments?

Only for illustration, but seems to work.

 include/linux/errno.h     |    1 
 include/linux/sched.h     |    2 -
 include/asm-i386/signal.h |    3 -
 arch/i386/kernel/signal.c |   73 +++++++++++++++++++++-------------------------
 4 files changed, 36 insertions(+), 43 deletions(-)

--- 2.6.15/include/linux/errno.h~1_SIGM	2004-09-13 09:33:11.000000000 +0400
+++ 2.6.15/include/linux/errno.h	2006-01-15 18:42:17.000000000 +0300
@@ -11,6 +11,7 @@
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
 #define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+#define ERESTART_SIGBLOCK     517
 
 /* Defined for the NFSv3 protocol */
 #define EBADHANDLE	521	/* Illegal NFS file handle */
--- 2.6.15/include/linux/sched.h~1_SIGM	2005-12-06 23:33:16.000000000 +0300
+++ 2.6.15/include/linux/sched.h	2006-01-15 18:55:27.000000000 +0300
@@ -799,7 +799,7 @@ struct task_struct {
 	struct signal_struct *signal;
 	struct sighand_struct *sighand;
 
-	sigset_t blocked, real_blocked;
+	sigset_t blocked, real_blocked, saved_blocked;
 	struct sigpending pending;
 
 	unsigned long sas_ss_sp;
--- 2.6.15/include/asm-i386/signal.h~1_SIGM	2005-11-22 19:35:52.000000000 +0300
+++ 2.6.15/include/asm-i386/signal.h	2006-01-15 19:26:58.000000000 +0300
@@ -217,9 +217,6 @@ static __inline__ int sigfindinword(unsi
 	return word;
 }
 
-struct pt_regs;
-extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
-
 #define ptrace_signal_deliver(regs, cookie)		\
 	do {						\
 		if (current->ptrace & PT_DTRACE) {	\
--- 2.6.15/arch/i386/kernel/signal.c~1_SIGM	2005-10-11 16:22:42.000000000 +0400
+++ 2.6.15/arch/i386/kernel/signal.c	2006-01-15 23:13:36.000000000 +0300
@@ -37,29 +37,22 @@
 asmlinkage int
 sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	struct pt_regs * regs = (struct pt_regs *) &history0;
-	sigset_t saveset;
-
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
+	current->saved_blocked = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs->eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTART_SIGBLOCK;
 }
 
 asmlinkage int
 sys_rt_sigsuspend(struct pt_regs regs)
 {
-	sigset_t saveset, newset;
+	sigset_t newset;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (regs.ecx != sizeof(sigset_t))
@@ -69,19 +62,11 @@ sys_rt_sigsuspend(struct pt_regs regs)
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	sigprocmask(SIG_SETMASK, &newset, &current->saved_blocked);
 
-	regs.eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&regs, &saveset))
-			return -EINTR;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTART_SIGBLOCK;
 }
 
 asmlinkage int 
@@ -540,14 +525,18 @@ give_sigsegv:
 
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
-	      sigset_t *oldset,	struct pt_regs * regs)
+		struct pt_regs * regs)
 {
+	sigset_t *oldset;
+	int saved_blocked = 0;
 	int ret;
 
 	/* Are we from a system call? */
 	if (regs->orig_eax >= 0) {
 		/* If so, check system call restarting.. */
 		switch (regs->eax) {
+			case -ERESTART_SIGBLOCK:
+				saved_blocked = 1;
 		        case -ERESTART_RESTARTBLOCK:
 			case -ERESTARTNOHAND:
 				regs->eax = -EINTR;
@@ -575,6 +564,10 @@ handle_signal(unsigned long sig, siginfo
 		regs->eflags &= ~TF_MASK;
 	}
 
+	oldset = &current->blocked;
+	if (saved_blocked)
+		oldset = &current->saved_blocked;
+
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		ret = setup_rt_frame(sig, ka, info, oldset, regs);
@@ -588,7 +581,8 @@ handle_signal(unsigned long sig, siginfo
 			sigaddset(&current->blocked,sig);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
-	}
+	} else if (saved_blocked)
+		regs->eax = -ERESTART_SIGBLOCK;
 
 	return ret;
 }
@@ -598,7 +592,7 @@ handle_signal(unsigned long sig, siginfo
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void fastcall do_signal(struct pt_regs *regs)
 {
 	siginfo_t info;
 	int signr;
@@ -613,14 +607,11 @@ int fastcall do_signal(struct pt_regs *r
  	 * CS suffices.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
-		oldset = &current->blocked;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		/* Reenable any watchpoints before delivering the
@@ -633,25 +624,29 @@ int fastcall do_signal(struct pt_regs *r
 		}
 
 		/* Whee!  Actually deliver the signal.  */
-		return handle_signal(signr, &info, &ka, oldset, regs);
+		handle_signal(signr, &info, &ka, regs);
+		return;
 	}
 
  no_signal:
 	/* Did we come from a system call? */
 	if (regs->orig_eax >= 0) {
 		/* Restart the system call - no handlers present */
-		if (regs->eax == -ERESTARTNOHAND ||
-		    regs->eax == -ERESTARTSYS ||
-		    regs->eax == -ERESTARTNOINTR) {
+		switch (regs->eax) {
+		case -ERESTART_SIGBLOCK:
+			sigprocmask(SIG_SETMASK, &current->saved_blocked, NULL);
+		case -ERESTARTSYS:
+		case -ERESTARTNOHAND:
+		case -ERESTARTNOINTR:
 			regs->eax = regs->orig_eax;
 			regs->eip -= 2;
-		}
-		if (regs->eax == -ERESTART_RESTARTBLOCK){
+			break;
+
+		case -ERESTART_RESTARTBLOCK:
 			regs->eax = __NR_restart_syscall;
 			regs->eip -= 2;
 		}
 	}
-	return 0;
 }
 
 /*
@@ -669,7 +664,7 @@ void do_notify_resume(struct pt_regs *re
 	}
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(regs,oldset);
+		do_signal(regs);
 	
 	clear_thread_flag(TIF_IRET);
 }

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

* [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386
       [not found] <1134732739.7104.54.camel@pmac.infradead.org>
@ 2005-12-16 11:45 ` David Woodhouse
  0 siblings, 0 replies; 19+ messages in thread
From: David Woodhouse @ 2005-12-16 11:45 UTC (permalink / raw)
  To: akpm; +Cc: dhowells, linux-kernel

From: David Howells <dhowells@redhat.com>

The attached patch handles TIF_RESTORE_SIGMASK as added by David Woodhouse's
patch entitled:

        [PATCH] 2/6 TIF_RESTORE_SIGMASK support for arch/powerpc
        [PATCH] 3/6 Generic sys_rt_sigsuspend

It does the following:

 (1) Declares TIF_RESTORE_SIGMASK for i386.

 (2) Invokes it over to do_signal() when TIF_RESTORE_SIGMASK is set.

 (3) Makes do_signal() support TIF_RESTORE_SIGMASK, using the signal mask saved
     in current->saved_sigmask.

 (4) Discards sys_rt_sigsuspend() from the arch, using the generic one instead.

 (5) Makes sys_sigsuspend() save the signal mask and set TIF_RESTORE_SIGMASK
     rather than attempting to fudge the return registers.

 (6) Makes sys_sigsuspend() return -ERESTARTNOHAND rather than looping
     intrinsically.

 (7) Makes setup_frame(), setup_rt_frame() and handle_signal() return 0 or
     -EFAULT rather than true/false to be consistent with the rest of the
     kernel.

Due to the fact do_signal() is then only called from one place:

 (8) Makes do_signal() no longer have a return value is it was just being
     ignored; force_sig() takes care of this.

 (9) Discards the old sigmask argument to do_signal() as it's no longer
     necessary.

(10) Makes do_signal() static.

(11) Marks the second argument to do_notify_resume() as unused. The unused
     argument should remain in the middle as the arguments are passed in as
     registers, and the ordering is specific in entry.S

Given the way do_signal() is now no longer called from sys_{,rt_}sigsuspend(),
they no longer need access to the exception frame, and so can just take
arguments normally.

This patch depends on sys_rt_sigsuspend patch.

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-Off-By: David Woodhouse <dwmw2@infradead.org>

 arch/i386/kernel/signal.c      |  109 ++++++++++++++++++-----------------------
 include/asm-i386/signal.h      |    1 
 include/asm-i386/thread_info.h |    2 
 include/asm-i386/unistd.h      |    1 
 4 files changed, 51 insertions(+), 62 deletions(-)

diff -rup linux-2.6.15-rc5-mm3-pselect4/arch/i386/kernel/signal.c linux-2.6.15-rc5-mm3-pselect5/arch/i386/kernel/signal.c
--- linux-2.6.15-rc5-mm3-pselect4/arch/i386/kernel/signal.c	2005-10-28 01:02:08.000000000 +0100
+++ linux-2.6.15-rc5-mm3-pselect5/arch/i386/kernel/signal.c	2005-12-16 11:09:59.000000000 +0000
@@ -37,51 +37,17 @@
 asmlinkage int
 sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
-	struct pt_regs * regs = (struct pt_regs *) &history0;
-	sigset_t saveset;
-
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
+	current->saved_sigmask = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs->eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(regs, &saveset))
-			return -EINTR;
-	}
-}
-
-asmlinkage int
-sys_rt_sigsuspend(struct pt_regs regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (regs.ecx != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&newset, (sigset_t __user *)regs.ebx, sizeof(newset)))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs.eax = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&regs, &saveset))
-			return -EINTR;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 asmlinkage int 
@@ -433,11 +399,11 @@ static int setup_frame(int sig, struct k
 		current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
-	return 0;
+	return -EFAULT;
 }
 
 static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -527,11 +493,11 @@ static int setup_rt_frame(int sig, struc
 		current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-	return 1;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
-	return 0;
+	return -EFAULT;
 }
 
 /*
@@ -581,7 +547,7 @@ handle_signal(unsigned long sig, siginfo
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ret) {
+	if (ret == 0) {
 		spin_lock_irq(&current->sighand->siglock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -598,11 +564,12 @@ handle_signal(unsigned long sig, siginfo
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void fastcall do_signal(struct pt_regs *regs)
 {
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
+	sigset_t *oldset;
 
 	/*
 	 * We want the common case to go fast, which
@@ -613,12 +580,14 @@ int fastcall do_signal(struct pt_regs *r
  	 * CS suffices.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -628,38 +597,55 @@ int fastcall do_signal(struct pt_regs *r
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		if (unlikely(current->thread.debugreg[7])) {
+		if (unlikely(current->thread.debugreg[7]))
 			set_debugreg(current->thread.debugreg[7], 7);
-		}
 
 		/* Whee!  Actually deliver the signal.  */
-		return handle_signal(signr, &info, &ka, oldset, regs);
+		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+
+		return;
 	}
 
- no_signal:
+no_signal:
 	/* Did we come from a system call? */
 	if (regs->orig_eax >= 0) {
 		/* Restart the system call - no handlers present */
-		if (regs->eax == -ERESTARTNOHAND ||
-		    regs->eax == -ERESTARTSYS ||
-		    regs->eax == -ERESTARTNOINTR) {
+		switch (regs->eax) {
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
 			regs->eax = regs->orig_eax;
 			regs->eip -= 2;
-		}
-		if (regs->eax == -ERESTART_RESTARTBLOCK){
+			break;
+
+		case -ERESTART_RESTARTBLOCK:
 			regs->eax = __NR_restart_syscall;
 			regs->eip -= 2;
+			break;
 		}
 	}
-	return 0;
+
+	/* if there's no signal to deliver, we just put the saved sigmask
+	 * back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 }
 
 /*
  * notification of userspace execution resumption
- * - triggered by current->work.notify_resume
+ * - triggered by the TIF_WORK_MASK flags
  */
 __attribute__((regparm(3)))
-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+void do_notify_resume(struct pt_regs *regs, void *_unused,
 		      __u32 thread_info_flags)
 {
 	/* Pending single-step? */
@@ -667,9 +653,10 @@ void do_notify_resume(struct pt_regs *re
 		regs->eflags |= TF_MASK;
 		clear_thread_flag(TIF_SINGLESTEP);
 	}
+
 	/* deal with pending signal delivery */
-	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(regs,oldset);
+	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+		do_signal(regs);
 	
 	clear_thread_flag(TIF_IRET);
 }
diff -rup linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/signal.h linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/signal.h
--- linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/signal.h	2005-12-16 10:51:25.000000000 +0000
+++ linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/signal.h	2005-12-16 11:09:59.000000000 +0000
@@ -218,7 +218,6 @@ static __inline__ int sigfindinword(unsi
 }
 
 struct pt_regs;
-extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 #define ptrace_signal_deliver(regs, cookie)		\
 	do {						\
diff -rup linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/thread_info.h linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/thread_info.h
--- linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/thread_info.h	2005-10-28 01:02:08.000000000 +0100
+++ linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/thread_info.h	2005-12-16 11:09:59.000000000 +0000
@@ -142,6 +142,7 @@ register unsigned long current_stack_poi
 #define TIF_SYSCALL_EMU		6	/* syscall emulation active */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
+#define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 
@@ -154,6 +155,7 @@ register unsigned long current_stack_poi
 #define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
diff -rup linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/unistd.h linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/unistd.h
--- linux-2.6.15-rc5-mm3-pselect4/include/asm-i386/unistd.h	2005-12-16 10:56:18.000000000 +0000
+++ linux-2.6.15-rc5-mm3-pselect5/include/asm-i386/unistd.h	2005-12-16 11:09:59.000000000 +0000
@@ -420,6 +420,7 @@ __syscall_return(type,__res); \
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #endif
 
 #ifdef __KERNEL_SYSCALLS__


-- 
dwmw2


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

end of thread, other threads:[~2006-01-15 17:01 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1136923488.3435.78.camel@localhost.localdomain>
2006-01-10 20:18 ` [PATCH] [1/6] Add pselect/ppoll system call implementation David Woodhouse
2006-01-13 11:40   ` Andrew Morton
2006-01-10 20:18 ` [PATCH] [2/6] TIF_RESTORE_SIGMASK support for arch/powerpc David Woodhouse
2006-01-10 20:18 ` [PATCH] [3/6] Generic sys_rt_sigsuspend() David Woodhouse
2006-01-10 20:19 ` [PATCH] [4/6] Handle TIF_RESTORE_SIGMASK for FRV David Woodhouse
2006-01-10 20:19 ` [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386 David Woodhouse
2006-01-13  3:59   ` Andrew Morton
2006-01-13  4:30     ` David Woodhouse
2006-01-13  4:54       ` Andrew Morton
2006-01-13  5:11         ` David Woodhouse
2006-01-13  6:10         ` Andrew Morton
2006-01-13  6:23           ` David Woodhouse
2006-01-13  8:28             ` David Woodhouse
2006-01-13  8:48               ` Andrew Morton
2006-01-13  8:51                 ` Andrew Morton
2006-01-13  9:18               ` Andrew Morton
2006-01-10 20:23 ` [PATCH] [6/6] Add pselect/ppoll system calls on i386 David Woodhouse
2006-01-15 18:17 [PATCH] [5/6] Handle TIF_RESTORE_SIGMASK for i386 Oleg Nesterov
     [not found] <1134732739.7104.54.camel@pmac.infradead.org>
2005-12-16 11:45 ` David Woodhouse

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).