diff options
Diffstat (limited to 'kernel/posix-cpu-timers.c')
| -rw-r--r-- | kernel/posix-cpu-timers.c | 84 | 
1 files changed, 58 insertions, 26 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 5667fef89dd..479b16b44f7 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1393,23 +1393,13 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,  	}  } -int posix_cpu_nsleep(const clockid_t which_clock, int flags, -		     struct timespec *rqtp, struct timespec __user *rmtp) +static int do_cpu_nanosleep(const clockid_t which_clock, int flags, +			    struct timespec *rqtp, struct itimerspec *it)  { -	struct restart_block *restart_block = -	    ¤t_thread_info()->restart_block;  	struct k_itimer timer;  	int error;  	/* -	 * Diagnose required errors first. -	 */ -	if (CPUCLOCK_PERTHREAD(which_clock) && -	    (CPUCLOCK_PID(which_clock) == 0 || -	     CPUCLOCK_PID(which_clock) == current->pid)) -		return -EINVAL; - -	/*  	 * Set up a temporary timer and then wait for it to go off.  	 */  	memset(&timer, 0, sizeof timer); @@ -1420,11 +1410,12 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,  	timer.it_process = current;  	if (!error) {  		static struct itimerspec zero_it; -		struct itimerspec it = { .it_value = *rqtp, -					 .it_interval = {} }; + +		memset(it, 0, sizeof *it); +		it->it_value = *rqtp;  		spin_lock_irq(&timer.it_lock); -		error = posix_cpu_timer_set(&timer, flags, &it, NULL); +		error = posix_cpu_timer_set(&timer, flags, it, NULL);  		if (error) {  			spin_unlock_irq(&timer.it_lock);  			return error; @@ -1452,33 +1443,56 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,  		 * 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); +		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) { +		if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {  			/*  			 * It actually did fire already.  			 */  			return 0;  		} +		error = -ERESTART_RESTARTBLOCK; +	} + +	return error; +} + +int posix_cpu_nsleep(const clockid_t which_clock, int flags, +		     struct timespec *rqtp, struct timespec __user *rmtp) +{ +	struct restart_block *restart_block = +	    ¤t_thread_info()->restart_block; +	struct itimerspec it; +	int error; + +	/* +	 * Diagnose required errors first. +	 */ +	if (CPUCLOCK_PERTHREAD(which_clock) && +	    (CPUCLOCK_PID(which_clock) == 0 || +	     CPUCLOCK_PID(which_clock) == current->pid)) +		return -EINVAL; + +	error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); + +	if (error == -ERESTART_RESTARTBLOCK) { + +	       	if (flags & TIMER_ABSTIME) +			return -ERESTARTNOHAND;  		/* -		 * Report back to the user the time still remaining. -		 */ -		if (rmtp != NULL && !(flags & TIMER_ABSTIME) && -		    copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) +	 	 * Report back to the user the time still remaining. +	 	 */ +		if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))  			return -EFAULT;  		restart_block->fn = posix_cpu_nsleep_restart; -		/* Caller already set restart_block->arg1 */  		restart_block->arg0 = which_clock;  		restart_block->arg1 = (unsigned long) rmtp;  		restart_block->arg2 = rqtp->tv_sec;  		restart_block->arg3 = rqtp->tv_nsec; - -		error = -ERESTART_RESTARTBLOCK;  	} -  	return error;  } @@ -1487,13 +1501,31 @@ long posix_cpu_nsleep_restart(struct restart_block *restart_block)  	clockid_t which_clock = restart_block->arg0;  	struct timespec __user *rmtp;  	struct timespec t; +	struct itimerspec it; +	int error;  	rmtp = (struct timespec __user *) restart_block->arg1;  	t.tv_sec = restart_block->arg2;  	t.tv_nsec = restart_block->arg3;  	restart_block->fn = do_no_restart_syscall; -	return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t, rmtp); +	error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); + +	if (error == -ERESTART_RESTARTBLOCK) { +		/* +	 	 * Report back to the user the time still remaining. +	 	 */ +		if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) +			return -EFAULT; + +		restart_block->fn = posix_cpu_nsleep_restart; +		restart_block->arg0 = which_clock; +		restart_block->arg1 = (unsigned long) rmtp; +		restart_block->arg2 = t.tv_sec; +		restart_block->arg3 = t.tv_nsec; +	} +	return error; +  }  |