Commit 432569bb authored by Roman Zippel's avatar Roman Zippel Committed by Linus Torvalds

[PATCH] hrtimers: simplify nanosleep

nanosleep is the only user of the expired state, so let it manage this itself,
which makes the hrtimer code a bit simpler.  The remaining time is also only
calculated if requested.
Signed-off-by: default avatarRoman Zippel <zippel@linux-m68k.org>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3b98a532
...@@ -38,9 +38,7 @@ enum hrtimer_restart { ...@@ -38,9 +38,7 @@ enum hrtimer_restart {
* Timer states: * Timer states:
*/ */
enum hrtimer_state { enum hrtimer_state {
HRTIMER_INACTIVE, /* Timer is inactive */ HRTIMER_INACTIVE, /* Timer is inactive */
HRTIMER_EXPIRED, /* Timer is expired */
HRTIMER_RUNNING, /* Timer is running the callback function */
HRTIMER_PENDING, /* Timer is pending */ HRTIMER_PENDING, /* Timer is pending */
}; };
......
...@@ -625,30 +625,20 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base) ...@@ -625,30 +625,20 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base)
fn = timer->function; fn = timer->function;
data = timer->data; data = timer->data;
set_curr_timer(base, timer); set_curr_timer(base, timer);
timer->state = HRTIMER_RUNNING; timer->state = HRTIMER_INACTIVE;
__remove_hrtimer(timer, base); __remove_hrtimer(timer, base);
spin_unlock_irq(&base->lock); spin_unlock_irq(&base->lock);
/* restart = fn(data);
* fn == NULL is special case for the simplest timer
* variant - wake up process and do not restart:
*/
if (!fn) {
wake_up_process(data);
restart = HRTIMER_NORESTART;
} else
restart = fn(data);
spin_lock_irq(&base->lock); spin_lock_irq(&base->lock);
/* Another CPU has added back the timer */ /* Another CPU has added back the timer */
if (timer->state != HRTIMER_RUNNING) if (timer->state != HRTIMER_INACTIVE)
continue; continue;
if (restart == HRTIMER_RESTART) if (restart != HRTIMER_NORESTART)
enqueue_hrtimer(timer, base); enqueue_hrtimer(timer, base);
else
timer->state = HRTIMER_EXPIRED;
} }
set_curr_timer(base, NULL); set_curr_timer(base, NULL);
spin_unlock_irq(&base->lock); spin_unlock_irq(&base->lock);
...@@ -672,79 +662,70 @@ void hrtimer_run_queues(void) ...@@ -672,79 +662,70 @@ void hrtimer_run_queues(void)
* Sleep related functions: * Sleep related functions:
*/ */
/** struct sleep_hrtimer {
* schedule_hrtimer - sleep until timeout struct hrtimer timer;
* struct task_struct *task;
* @timer: hrtimer variable initialized with the correct clock base int expired;
* @mode: timeout value is abs/rel };
*
* Make the current task sleep until @timeout is
* elapsed.
*
* You can set the task state as follows -
*
* %TASK_UNINTERRUPTIBLE - at least @timeout is guaranteed to
* pass before the routine returns. The routine will return 0
*
* %TASK_INTERRUPTIBLE - the routine may return early if a signal is
* delivered to the current task. In this case the remaining time
* will be returned
*
* The current task state is guaranteed to be TASK_RUNNING when this
* routine returns.
*/
static ktime_t __sched
schedule_hrtimer(struct hrtimer *timer, const enum hrtimer_mode mode)
{
/* fn stays NULL, meaning single-shot wakeup: */
timer->data = current;
hrtimer_start(timer, timer->expires, mode); static int nanosleep_wakeup(void *data)
{
struct sleep_hrtimer *t = data;
schedule(); t->expired = 1;
hrtimer_cancel(timer); wake_up_process(t->task);
/* Return the remaining time: */ return HRTIMER_NORESTART;
if (timer->state != HRTIMER_EXPIRED)
return ktime_sub(timer->expires, timer->base->get_time());
else
return (ktime_t) {.tv64 = 0 };
} }
static inline ktime_t __sched static int __sched do_nanosleep(struct sleep_hrtimer *t, enum hrtimer_mode mode)
schedule_hrtimer_interruptible(struct hrtimer *timer,
const enum hrtimer_mode mode)
{ {
set_current_state(TASK_INTERRUPTIBLE); t->timer.function = nanosleep_wakeup;
t->timer.data = t;
t->task = current;
t->expired = 0;
do {
set_current_state(TASK_INTERRUPTIBLE);
hrtimer_start(&t->timer, t->timer.expires, mode);
schedule();
return schedule_hrtimer(timer, mode); if (unlikely(!t->expired)) {
hrtimer_cancel(&t->timer);
mode = HRTIMER_ABS;
}
} while (!t->expired && !signal_pending(current));
return t->expired;
} }
static long __sched nanosleep_restart(struct restart_block *restart) static long __sched nanosleep_restart(struct restart_block *restart)
{ {
struct sleep_hrtimer t;
struct timespec __user *rmtp; struct timespec __user *rmtp;
struct timespec tu; struct timespec tu;
void *rfn_save = restart->fn; ktime_t time;
struct hrtimer timer;
ktime_t rem;
restart->fn = do_no_restart_syscall; restart->fn = do_no_restart_syscall;
hrtimer_init(&timer, (clockid_t) restart->arg3, HRTIMER_ABS); hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS); if (do_nanosleep(&t, HRTIMER_ABS))
if (rem.tv64 <= 0)
return 0; return 0;
rmtp = (struct timespec __user *) restart->arg2; rmtp = (struct timespec __user *) restart->arg2;
tu = ktime_to_timespec(rem); if (rmtp) {
if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) time = ktime_sub(t.timer.expires, t.timer.base->get_time());
return -EFAULT; if (time.tv64 <= 0)
return 0;
tu = ktime_to_timespec(time);
if (copy_to_user(rmtp, &tu, sizeof(tu)))
return -EFAULT;
}
restart->fn = rfn_save; restart->fn = nanosleep_restart;
/* The other values in restart are already filled in */ /* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK; return -ERESTART_RESTARTBLOCK;
...@@ -754,33 +735,34 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, ...@@ -754,33 +735,34 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid) const enum hrtimer_mode mode, const clockid_t clockid)
{ {
struct restart_block *restart; struct restart_block *restart;
struct hrtimer timer; struct sleep_hrtimer t;
struct timespec tu; struct timespec tu;
ktime_t rem; ktime_t rem;
hrtimer_init(&timer, clockid, mode); hrtimer_init(&t.timer, clockid, mode);
t.timer.expires = timespec_to_ktime(*rqtp);
timer.expires = timespec_to_ktime(*rqtp); if (do_nanosleep(&t, mode))
rem = schedule_hrtimer_interruptible(&timer, mode);
if (rem.tv64 <= 0)
return 0; return 0;
/* Absolute timers do not update the rmtp value and restart: */ /* Absolute timers do not update the rmtp value and restart: */
if (mode == HRTIMER_ABS) if (mode == HRTIMER_ABS)
return -ERESTARTNOHAND; return -ERESTARTNOHAND;
tu = ktime_to_timespec(rem); if (rmtp) {
rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) if (rem.tv64 <= 0)
return -EFAULT; return 0;
tu = ktime_to_timespec(rem);
if (copy_to_user(rmtp, &tu, sizeof(tu)))
return -EFAULT;
}
restart = &current_thread_info()->restart_block; restart = &current_thread_info()->restart_block;
restart->fn = nanosleep_restart; restart->fn = nanosleep_restart;
restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF; restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
restart->arg1 = timer.expires.tv64 >> 32; restart->arg1 = t.timer.expires.tv64 >> 32;
restart->arg2 = (unsigned long) rmtp; restart->arg2 = (unsigned long) rmtp;
restart->arg3 = (unsigned long) timer.base->index; restart->arg3 = (unsigned long) t.timer.base->index;
return -ERESTART_RESTARTBLOCK; return -ERESTART_RESTARTBLOCK;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment