[PATCH] posix-timers: Fix the flags handling in posix_cpu_nsleep()
When a posix_cpu_nsleep() sleep is interrupted by a signal more than twice, it incorrectly reports the sleep time remaining to the user. Because posix_cpu_nsleep() doesn't report back to the user when it's called from restart function due to the wrong flags handling. This patch, which applies after previous one, moves the nanosleep() function from posix_cpu_nsleep() to do_cpu_nanosleep() and cleans up the flags handling appropriately. Signed-off-by: Toyo Abe <toyoa@mvista.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
1711ef3866
commit
e4b765551a
|
@ -1393,22 +1393,12 @@ 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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user