RFC: Kill -ERESTART_RESTARTBLOCK.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm looking at implementing ppoll() and pselect(), and the existing
restartblock stuff isn't sufficient for that -- we don't get to store
enough args, and although it could possibly be expanded, I just don't
much like restarting syscalls that way.

I think it makes more sense just to allow the arch-independent code to
deliver signals. So this patch introduces arch_do_signal() and, perhaps
unfortunately, arch_set_sigframe_result().

This allows us to get rid of all the *_nanpsleep 'restart' mess, and
remove the restart block from the thread_info. We can probably also make
sigsuspend a generic function too, rather than having it re-implemented
by every architecture.

Functions which have (successfully) called arch_do_signal() are now
expected to return -ESIGNALLED, and the syscall exit path (or an
assembly wrapper round the syscall itself) _can_ treat that specially if
it needs to, doing whatever it used to do on the way out from
sigsuspend() directly into the signal handler.

This is a proof-of-concept for powerpc; I suspect I might need to do
something about the prototypes of sys_(clock_,}nanosleep().

Comments? Alternative options which would allow pselect() to work?

diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index c9d0275..d14530f 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -64,6 +64,7 @@
 #define sys_sigaction	compat_sys_sigaction
 #define sys_swapcontext	compat_sys_swapcontext
 #define sys_sigreturn	compat_sys_sigreturn
+#define arch_set_sigframe_result arch_set_sigframe_result32
 
 #define old_sigaction	old_sigaction32
 #define sigcontext	sigcontext32
@@ -155,10 +156,9 @@ static inline int save_general_regs(stru
 	elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
 	int i;
 
-	if (!FULL_REGS(regs)) {
+	current_thread_info()->nvgprs_frame = &frame->mc_gregs[0];
+	if (!FULL_REGS(regs))
 		set_thread_flag(TIF_SAVE_NVGPRS);
-		current_thread_info()->nvgprs_frame = frame->mc_gregs;
-	}
 
 	for (i = 0; i <= PT_RESULT; i ++) {
 		if (i == 14 && !FULL_REGS(regs))
@@ -219,6 +219,15 @@ static inline int get_old_sigaction(stru
 static inline int save_general_regs(struct pt_regs *regs,
 		struct mcontext __user *frame)
 {
+	current_thread_info()->nvgprs_frame = &frame->mc_gregs;
+	if (!FULL_REGS(regs)) {
+		/* Zero out the unsaved GPRs to avoid information
+		   leak, and set TIF_SAVE_NVGPRS to ensure that the
+		   registers do actually get saved later. */
+		memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+		set_thread_flag(TIF_SAVE_NVGPRS);
+	}
+
 	return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE);
 }
 
@@ -921,9 +930,6 @@ long sys_rt_sigreturn(int r3, int r4, in
 {
 	struct rt_sigframe __user *rt_sf;
 
-	/* Always make any pending restarted system calls return -EINTR */
-	current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
 	rt_sf = (struct rt_sigframe __user *)
 		(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
 	if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
@@ -1127,9 +1133,6 @@ long sys_sigreturn(int r3, int r4, int r
 	struct mcontext __user *sr;
 	sigset_t set;
 
-	/* Always make any pending restarted system calls return -EINTR */
-	current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
 	sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
@@ -1251,3 +1254,40 @@ no_signal:
 
 	return ret;
 }
+
+int arch_set_sigframe_result(struct pt_regs *regs, int err)
+{
+	struct mcontext __user *mc = current_thread_info()->nvgprs_frame;
+	u32 ccr;
+
+	regs->result = err;
+
+	if (get_user(ccr, &mc->mc_gregs[PT_CCR]) ||
+	    put_user(ccr|0x10000000, &mc->mc_gregs[PT_CCR]) ||
+	    put_user(-err, &mc->mc_gregs[3])) {
+		/* The signal frame on the stack went away after it
+		   was first set up. We want to change the return code
+		   we stored there, but we can't. But then again, it
+		   doesn't matter much because userspace is going to
+		   SEGV if it looks at it anyway. So it doesn't matter
+		   much if we ignore this result. */
+		return -EFAULT;
+		
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PPC32
+int arch_do_signal(struct pt_regs *regs, sigset_t *saveset)
+{
+	int ret;
+
+	ret = do_signal(saveset, regs);
+	if (ret) {
+		set_thread_flag(TIF_RESTOREALL);
+		arch_set_sigframe_result(regs, -EINTR);
+	}
+
+	return ret;
+}
+#endif
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 5462bef..b80d775 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -591,3 +591,42 @@ int do_signal(sigset_t *oldset, struct p
 	return 0;
 }
 EXPORT_SYMBOL(do_signal);
+
+
+int arch_set_sigframe_result(struct pt_regs *regs, int err)
+{
+	struct mcontext __user *mc;
+	u32 ccr;
+
+	if (test_thread_flag(TIF_32BIT))
+		return arch_set_sigframe_result32(regs, err);
+
+	mc = = current_thread_info()->nvgprs_frame;
+	regs->result = err;
+
+	if (get_user(ccr, &mc->mc_gregs[PT_CCR]) ||
+	    put_user(ccr|0x10000000, &mc->mc_gregs[PT_CCR]) ||
+	    put_user(-err, &mc->mc_gregs[3])) {
+		/* The signal frame on the stack went away after it
+		   was first set up. We want to change the return code
+		   we stored there, but we can't. But then again, it
+		   doesn't matter much because userspace is going to
+		   SEGV if it looks at it anyway. So it doesn't matter
+		   much if we ignore this result. */
+		return -EFAULT;
+		
+	}
+	return 0;
+}
+
+int arch_do_signal(struct pt_regs *regs, sigset_t *saveset)
+{
+	int ret;
+
+	ret = do_signal(saveset, regs);
+	if (ret) {
+		set_thread_flag(TIF_RESTOREALL);
+		arch_set_sigframe_result(-EINTR);
+
+	return ret;
+}
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 989f628..385383e 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -41,7 +41,7 @@
 #endif
 
 _GLOBAL(sys_call_table)
-SYSCALL(restart_syscall)
+SYSCALL(ni_syscall)
 SYSCALL(exit)
 PPC_SYS(fork)
 SYSCALL(read)
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index ac1e80e..1e898ad 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -36,7 +36,6 @@ struct thread_info {
 	int		cpu;			/* cpu we're on */
 	int		preempt_count;		/* 0 => preemptable,
 						   <0 => BUG */
-	struct restart_block restart_block;
 	void *nvgprs_frame;
 	/* low level flags - has atomic operations done on it */
 	unsigned long	flags ____cacheline_aligned_in_smp;
@@ -53,9 +52,6 @@ struct thread_info {
 	.exec_domain =	&default_exec_domain,	\
 	.cpu =		0,			\
 	.preempt_count = 1,			\
-	.restart_block = {			\
-		.fn = do_no_restart_syscall,	\
-	},					\
 	.flags =	0,			\
 }
 
diff --git a/include/linux/errno.h b/include/linux/errno.h
index d90b80f..a85da23 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -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 ESIGNALLED	517	/* A signal has already been delivered */
 
 /* Defined for the NFSv3 protocol */
 #define EBADHANDLE	521	/* Illegal NFS file handle */
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index f942e2b..37e2552 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -77,7 +77,7 @@ struct k_clock {
 	int (*clock_set) (clockid_t which_clock, struct timespec * tp);
 	int (*clock_get) (clockid_t which_clock, struct timespec * tp);
 	int (*timer_create) (struct k_itimer *timer);
-	int (*nsleep) (clockid_t which_clock, int flags, struct timespec *);
+	int (*nsleep) (clockid_t which_clock, int flags, struct timespec *, struct pt_regs *);
 	int (*timer_set) (struct k_itimer * timr, int flags,
 			  struct itimerspec * new_setting,
 			  struct itimerspec * old_setting);
@@ -91,7 +91,7 @@ void register_posix_clock(clockid_t cloc
 
 /* Error handlers for timer_create, nanosleep and settime */
 int do_posix_clock_notimer_create(struct k_itimer *timer);
-int do_posix_clock_nonanosleep(clockid_t, int flags, struct timespec *);
+int do_posix_clock_nonanosleep(clockid_t, int flags, struct timespec *, struct pt_regs *);
 int do_posix_clock_nosettime(clockid_t, struct timespec *tp);
 
 /* function to call to trigger timer event */
@@ -121,7 +121,7 @@ int posix_cpu_clock_getres(clockid_t whi
 int posix_cpu_clock_get(clockid_t which_clock, struct timespec *);
 int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp);
 int posix_cpu_timer_create(struct k_itimer *);
-int posix_cpu_nsleep(clockid_t, int, struct timespec *);
+int posix_cpu_nsleep(clockid_t, int, struct timespec *, struct pt_regs *);
 int posix_cpu_timer_set(struct k_itimer *, int,
 			struct itimerspec *, struct itimerspec *);
 int posix_cpu_timer_del(struct k_itimer *);
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 5dd5f02..b825170 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -233,6 +233,8 @@ extern int sigprocmask(int, sigset_t *, 
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 
+extern int arch_do_signal(struct pt_regs *regs, sigset_t *saveset);
+extern int arch_set_sigframe_result(struct pt_regs *regs, int result);
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 44fdd48..0854f5e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -74,7 +74,9 @@ asmlinkage long sys_adjtimex(struct time
 asmlinkage long sys_times(struct tms __user *tbuf);
 
 asmlinkage long sys_gettid(void);
-asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp);
+asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp, 
+			      long x1, long x2, long x3, long x4, /* FIXME */
+			      struct pt_regs *regs);
 asmlinkage unsigned long sys_alarm(unsigned int seconds);
 asmlinkage long sys_getpid(void);
 asmlinkage long sys_getppid(void);
@@ -133,7 +135,9 @@ asmlinkage long sys_clock_getres(clockid
 				struct timespec __user *tp);
 asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags,
 				const struct timespec __user *rqtp,
-				struct timespec __user *rmtp);
+				struct timespec __user *rmtp,
+				    long x1, long x2, /* FIXME */
+				struct pt_regs *regs);
 
 asmlinkage long sys_nice(int increment);
 asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 1c4eb41..78b16e9 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -7,16 +7,6 @@
 #ifndef _LINUX_THREAD_INFO_H
 #define _LINUX_THREAD_INFO_H
 
-/*
- * System call restart block. 
- */
-struct restart_block {
-	long (*fn)(struct restart_block *);
-	unsigned long arg0, arg1, arg2, arg3;
-};
-
-extern long do_no_restart_syscall(struct restart_block *parm);
-
 #include <linux/bitops.h>
 #include <asm/thread_info.h>
 
diff --git a/kernel/compat.c b/kernel/compat.c
index 102296e..93ed67f 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -68,7 +68,8 @@ static long compat_nanosleep_restart(str
 }
 
 asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
-		struct compat_timespec __user *rmtp)
+				     struct compat_timespec __user *rmtp,
+				     struct pt_regs *regs)
 {
 	struct timespec t;
 	struct restart_block *restart;
@@ -81,20 +82,18 @@ asmlinkage long compat_sys_nanosleep(str
 		return -EINVAL;
 
 	expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
-	expire = schedule_timeout_interruptible(expire);
-	if (expire == 0)
-		return 0;
-
-	if (rmtp) {
-		jiffies_to_timespec(expire, &t);
-		if (put_compat_timespec(&t, rmtp))
-			return -EFAULT;
+
+	while ((expire = schedule_timeout_interruptible(expire))) {
+
+		if (arch_do_signal(regs, &current->blocked)) {
+			jiffies_to_timespec(expire, &t);
+			if (rmtp && put_compat_timespec(&t, rmtp))
+				arch_set_sigframe_result(regs, -EFAULT);
+
+			return -ESIGNALLED;
+		}
 	}
-	restart = &current_thread_info()->restart_block;
-	restart->fn = compat_nanosleep_restart;
-	restart->arg0 = jiffies + expire;
-	restart->arg1 = (unsigned long) rmtp;
-	return -ERESTART_RESTARTBLOCK;
+	return 0;
 }
 
 static inline long get_compat_itimerval(struct itimerval *o,
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 84af54c..e3b552f 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -1408,13 +1408,9 @@ void set_process_cpu_timer(struct task_s
 	}
 }
 
-static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
-
 int posix_cpu_nsleep(clockid_t which_clock, int flags,
-		     struct timespec *rqtp)
+		     struct timespec *rqtp, struct pt_regs *regs)
 {
-	struct restart_block *restart_block =
-	    &current_thread_info()->restart_block;
 	struct k_itimer timer;
 	int error;
 
@@ -1436,7 +1432,6 @@ int posix_cpu_nsleep(clockid_t which_clo
 	error = posix_cpu_timer_create(&timer);
 	timer.it_process = current;
 	if (!error) {
-		struct timespec __user *rmtp;
 		static struct itimerspec zero_it;
 		struct itimerspec it = { .it_value = *rqtp,
 					 .it_interval = {} };
@@ -1448,69 +1443,42 @@ int posix_cpu_nsleep(clockid_t which_clo
 			return error;
 		}
 
-		while (!signal_pending(current)) {
-			if (timer.it.cpu.expires.sched == 0) {
-				/*
-				 * Our timer fired and was reset.
-				 */
-				spin_unlock_irq(&timer.it_lock);
-				return 0;
-			}
-
+		while (timer.it.cpu.expires.sched) {
 			/*
 			 * Block until cpu_timer_fire (or a signal) wakes us.
 			 */
 			__set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_irq(&timer.it_lock);
 			schedule();
-			spin_lock_irq(&timer.it_lock);
-		}
 
-		/*
-		 * We were interrupted by a signal.
-		 */
-		sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
-		posix_cpu_timer_set(&timer, 0, &zero_it, &it);
-		spin_unlock_irq(&timer.it_lock);
+			if (test_thread_flag(TIF_SIGPENDING)) {
+				spin_lock_irq(&timer.it_lock);
+				sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
+				posix_cpu_timer_set(&timer, 0, &zero_it, &it);
+				spin_unlock_irq(&timer.it_lock);
 
-		if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
-			/*
-			 * It actually did fire already.
-			 */
-			return 0;
+				if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
+					/*
+					 * It actually did fire already.
+					 */
+					return 0;
+				}
+				if (arch_do_signal(regs, &current->blocked)) {
+					*rqtp = it.it_value;
+					return -ESIGNALLED;
+				}
+			}
+			spin_lock_irq(&timer.it_lock);
 		}
-
 		/*
-		 * Report back to the user the time still remaining.
+		 * Our timer fired and was reset.
 		 */
-		rmtp = (struct timespec __user *) restart_block->arg1;
-		if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
-		    copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
-			return -EFAULT;
-
-		restart_block->fn = posix_cpu_clock_nanosleep_restart;
-		/* Caller already set restart_block->arg1 */
-		restart_block->arg0 = which_clock;
-		restart_block->arg2 = rqtp->tv_sec;
-		restart_block->arg3 = rqtp->tv_nsec;
-
-		error = -ERESTART_RESTARTBLOCK;
+		spin_unlock_irq(&timer.it_lock);
 	}
 
 	return error;
 }
 
-static long
-posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
-{
-	clockid_t which_clock = restart_block->arg0;
-	struct timespec t = { .tv_sec = restart_block->arg2,
-			      .tv_nsec = restart_block->arg3 };
-	restart_block->fn = do_no_restart_syscall;
-	return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t);
-}
-
-
 #define PROCESS_CLOCK	MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
 #define THREAD_CLOCK	MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED)
 
@@ -1528,9 +1496,9 @@ static int process_cpu_timer_create(stru
 	return posix_cpu_timer_create(timer);
 }
 static int process_cpu_nsleep(clockid_t which_clock, int flags,
-			      struct timespec *rqtp)
+			      struct timespec *rqtp, struct pt_regs *regs)
 {
-	return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
+	return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, regs);
 }
 static int thread_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
 {
@@ -1546,7 +1514,7 @@ static int thread_cpu_timer_create(struc
 	return posix_cpu_timer_create(timer);
 }
 static int thread_cpu_nsleep(clockid_t which_clock, int flags,
-			      struct timespec *rqtp)
+			     struct timespec *rqtp, struct pt_regs *regs)
 {
 	return -EINVAL;
 }
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 5870efb..a17f450 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -215,7 +215,7 @@ static inline int common_timer_create(st
 /*
  * These ones are defined below.
  */
-static int common_nsleep(clockid_t, int flags, struct timespec *t);
+static int common_nsleep(clockid_t, int flags, struct timespec *t, struct pt_regs *);
 static void common_timer_get(struct k_itimer *, struct itimerspec *);
 static int common_timer_set(struct k_itimer *, int,
 			    struct itimerspec *, struct itimerspec *);
@@ -1232,7 +1232,7 @@ int do_posix_clock_notimer_create(struct
 }
 EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create);
 
-int do_posix_clock_nonanosleep(clockid_t clock, int flags, struct timespec *t)
+int do_posix_clock_nonanosleep(clockid_t clock, int flags, struct timespec *t, struct pt_regs *regs)
 {
 #ifndef ENOTSUP
 	return -EOPNOTSUPP;	/* aka ENOTSUP in userland for POSIX */
@@ -1392,16 +1392,14 @@ void clock_was_set(void)
 	up(&clock_was_set_lock);
 }
 
-long clock_nanosleep_restart(struct restart_block *restart_block);
-
 asmlinkage long
 sys_clock_nanosleep(clockid_t which_clock, int flags,
 		    const struct timespec __user *rqtp,
-		    struct timespec __user *rmtp)
+		    struct timespec __user *rmtp,
+		    long x1, long x2, /* FIXME */
+		    struct pt_regs *regs)
 {
 	struct timespec t;
-	struct restart_block *restart_block =
-	    &(current_thread_info()->restart_block);
 	int ret;
 
 	if (invalid_clockid(which_clock))
@@ -1413,50 +1411,28 @@ sys_clock_nanosleep(clockid_t which_cloc
 	if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0)
 		return -EINVAL;
 
-	/*
-	 * Do this here as nsleep function does not have the real address.
-	 */
-	restart_block->arg1 = (unsigned long)rmtp;
+	ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t, regs));
 
-	ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t));
-
-	if ((ret == -ERESTART_RESTARTBLOCK) && rmtp &&
-					copy_to_user(rmtp, &t, sizeof (t)))
-		return -EFAULT;
+	if (ret == -ESIGNALLED && !(flags & TIMER_ABSTIME) && 
+	    rmtp && copy_to_user(rmtp, &t, sizeof(t)))
+		arch_set_sigframe_result(regs, -EFAULT);
+		
 	return ret;
 }
 
-
-static int common_nsleep(clockid_t which_clock,
-			 int flags, struct timespec *tsave)
+static int common_nsleep(clockid_t which_clock, int flags,
+			 struct timespec *tsave, struct pt_regs *regs)
 {
 	struct timespec t, dum;
 	DECLARE_WAITQUEUE(abs_wqueue, current);
 	u64 rq_time = (u64)0;
 	s64 left;
 	int abs;
-	struct restart_block *restart_block =
-	    &current_thread_info()->restart_block;
+	int ret = 0;
 
 	abs_wqueue.flags = 0;
 	abs = flags & TIMER_ABSTIME;
 
-	if (restart_block->fn == clock_nanosleep_restart) {
-		/*
-		 * Interrupted by a non-delivered signal, pick up remaining
-		 * time and continue.  Remaining time is in arg2 & 3.
-		 */
-		restart_block->fn = do_no_restart_syscall;
-
-		rq_time = restart_block->arg3;
-		rq_time = (rq_time << 32) + restart_block->arg2;
-		if (!rq_time)
-			return -EINTR;
-		left = rq_time - get_jiffies_64();
-		if (left <= (s64)0)
-			return 0;	/* Already passed */
-	}
-
 	if (abs && (posix_clocks[which_clock].clock_get !=
 			    posix_clocks[CLOCK_MONOTONIC].clock_get))
 		add_wait_queue(&nanosleep_abs_wqueue, &abs_wqueue);
@@ -1477,58 +1453,21 @@ static int common_nsleep(clockid_t which
 		schedule_timeout_interruptible(left);
 
 		left = rq_time - get_jiffies_64();
-	} while (left > (s64)0 && !test_thread_flag(TIF_SIGPENDING));
 
-	if (abs_wqueue.task_list.next)
-		finish_wait(&nanosleep_abs_wqueue, &abs_wqueue);
-
-	if (left > (s64)0) {
-
-		/*
-		 * Always restart abs calls from scratch to pick up any
-		 * clock shifting that happened while we are away.
-		 */
-		if (abs)
-			return -ERESTARTNOHAND;
+		if (test_thread_flag(TIF_SIGPENDING)) {
+			t.tv_sec = div_long_long_rem(left*TICK_NSEC,
+						      NSEC_PER_SEC, 
+						      &t.tv_nsec);
+			if (arch_do_signal(regs, &current->blocked)) {
 
-		left *= TICK_NSEC;
-		tsave->tv_sec = div_long_long_rem(left, 
-						  NSEC_PER_SEC, 
-						  &tsave->tv_nsec);
-		/*
-		 * Restart works by saving the time remaing in 
-		 * arg2 & 3 (it is 64-bits of jiffies).  The other
-		 * info we need is the clock_id (saved in arg0). 
-		 * The sys_call interface needs the users 
-		 * timespec return address which _it_ saves in arg1.
-		 * Since we have cast the nanosleep call to a clock_nanosleep
-		 * both can be restarted with the same code.
-		 */
-		restart_block->fn = clock_nanosleep_restart;
-		restart_block->arg0 = which_clock;
-		/*
-		 * Caller sets arg1
-		 */
-		restart_block->arg2 = rq_time & 0xffffffffLL;
-		restart_block->arg3 = rq_time >> 32;
-
-		return -ERESTART_RESTARTBLOCK;
-	}
+				ret = -ESIGNALLED;
+				break;
+			}
+		}
+	} while (left > (s64)0);
 
-	return 0;
-}
-/*
- * This will restart clock_nanosleep.
- */
-long
-clock_nanosleep_restart(struct restart_block *restart_block)
-{
-	struct timespec t;
-	int ret = common_nsleep(restart_block->arg0, 0, &t);
+	if (abs_wqueue.task_list.next)
+		finish_wait(&nanosleep_abs_wqueue, &abs_wqueue);
 
-	if ((ret == -ERESTART_RESTARTBLOCK) && restart_block->arg1 &&
-	    copy_to_user((struct timespec __user *)(restart_block->arg1), &t,
-			 sizeof (t)))
-		return -EFAULT;
 	return ret;
 }
diff --git a/kernel/signal.c b/kernel/signal.c
index d7611f1..2f1b4e2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1973,21 +1974,6 @@ EXPORT_SYMBOL(unblock_all_signals);
 

 /*
- * System call entry points.
- */
-
-asmlinkage long sys_restart_syscall(void)
-{
-	struct restart_block *restart = &current_thread_info()->restart_block;
-	return restart->fn(restart);
-}
-
-long do_no_restart_syscall(struct restart_block *param)
-{
-	return -EINTR;
-}
-
-/*
  * We don't need to get the kernel lock - this is all local to this
  * particular thread.. (and that's good, because this is _heavily_
  * used by various programs)
diff --git a/kernel/timer.c b/kernel/timer.c
index fd74268..9fa626d 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1118,36 +1118,13 @@ asmlinkage long sys_gettid(void)
 	return current->pid;
 }
 
-static long __sched nanosleep_restart(struct restart_block *restart)
-{
-	unsigned long expire = restart->arg0, now = jiffies;
-	struct timespec __user *rmtp = (struct timespec __user *) restart->arg1;
-	long ret;
-
-	/* Did it expire while we handled signals? */
-	if (!time_after(expire, now))
-		return 0;
-
-	expire = schedule_timeout_interruptible(expire - now);
-
-	ret = 0;
-	if (expire) {
-		struct timespec t;
-		jiffies_to_timespec(expire, &t);
-
-		ret = -ERESTART_RESTARTBLOCK;
-		if (rmtp && copy_to_user(rmtp, &t, sizeof(t)))
-			ret = -EFAULT;
-		/* The 'restart' block is already filled in */
-	}
-	return ret;
-}
-
-asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
+asmlinkage long sys_nanosleep(struct timespec __user *rqtp, 
+			      struct timespec __user *rmtp,
+			      long x1, long x2, long x3, long x4, /* FIXME */
+			      struct pt_regs *regs)
 {
 	struct timespec t;
 	unsigned long expire;
-	long ret;
 
 	if (copy_from_user(&t, rqtp, sizeof(t)))
 		return -EFAULT;
@@ -1156,22 +1133,18 @@ asmlinkage long sys_nanosleep(struct tim
 		return -EINVAL;
 
 	expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
-	expire = schedule_timeout_interruptible(expire);
+ 
+	while ((expire = schedule_timeout_interruptible(expire))) {
 
-	ret = 0;
-	if (expire) {
-		struct restart_block *restart;
-		jiffies_to_timespec(expire, &t);
-		if (rmtp && copy_to_user(rmtp, &t, sizeof(t)))
-			return -EFAULT;
-
-		restart = &current_thread_info()->restart_block;
-		restart->fn = nanosleep_restart;
-		restart->arg0 = jiffies + expire;
-		restart->arg1 = (unsigned long) rmtp;
-		ret = -ERESTART_RESTARTBLOCK;
+		if (arch_do_signal(regs, &current->blocked)) {
+			jiffies_to_timespec(expire, &t);
+			if (rmtp && copy_to_user(rmtp, &t, sizeof(t)))
+				arch_set_sigframe_result(regs, -EFAULT);
+
+			return -ESIGNALLED;
+		}
 	}
-	return ret;
+	return 0;
 }
 
 /*


-- 
dwmw2


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux