Commit 10c94ec1 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Linus Torvalds

[PATCH] hrtimer: create hrtimer nanosleep API

introduce the hrtimer_nanosleep() and hrtimer_nanosleep_real() APIs.  Not yet
used by any code.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 2ff678b8
...@@ -121,6 +121,12 @@ static inline int hrtimer_active(const struct hrtimer *timer) ...@@ -121,6 +121,12 @@ static inline int hrtimer_active(const struct hrtimer *timer)
extern unsigned long hrtimer_forward(struct hrtimer *timer, extern unsigned long hrtimer_forward(struct hrtimer *timer,
const ktime_t interval); const ktime_t interval);
/* Precise sleep: */
extern long hrtimer_nanosleep(struct timespec *rqtp,
struct timespec __user *rmtp,
const enum hrtimer_mode mode,
const clockid_t clockid);
/* Soft interrupt function to run the hrtimer queues: */ /* Soft interrupt function to run the hrtimer queues: */
extern void hrtimer_run_queues(void); extern void hrtimer_run_queues(void);
......
...@@ -580,6 +580,133 @@ void hrtimer_run_queues(void) ...@@ -580,6 +580,133 @@ void hrtimer_run_queues(void)
run_hrtimer_queue(&base[i]); run_hrtimer_queue(&base[i]);
} }
/*
* Sleep related functions:
*/
/**
* schedule_hrtimer - sleep until timeout
*
* @timer: hrtimer variable initialized with the correct clock base
* @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);
schedule();
hrtimer_cancel(timer);
/* Return the remaining time: */
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
schedule_hrtimer_interruptible(struct hrtimer *timer,
const enum hrtimer_mode mode)
{
set_current_state(TASK_INTERRUPTIBLE);
return schedule_hrtimer(timer, mode);
}
static long __sched
nanosleep_restart(struct restart_block *restart, clockid_t clockid)
{
struct timespec __user *rmtp, tu;
void *rfn_save = restart->fn;
struct hrtimer timer;
ktime_t rem;
restart->fn = do_no_restart_syscall;
hrtimer_init(&timer, clockid);
timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS);
if (rem.tv64 <= 0)
return 0;
rmtp = (struct timespec __user *) restart->arg2;
tu = ktime_to_timespec(rem);
if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
return -EFAULT;
restart->fn = rfn_save;
/* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK;
}
static long __sched nanosleep_restart_mono(struct restart_block *restart)
{
return nanosleep_restart(restart, CLOCK_MONOTONIC);
}
static long __sched nanosleep_restart_real(struct restart_block *restart)
{
return nanosleep_restart(restart, CLOCK_REALTIME);
}
long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid)
{
struct restart_block *restart;
struct hrtimer timer;
struct timespec tu;
ktime_t rem;
hrtimer_init(&timer, clockid);
timer.expires = timespec_to_ktime(*rqtp);
rem = schedule_hrtimer_interruptible(&timer, mode);
if (rem.tv64 <= 0)
return 0;
/* Absolute timers do not update the rmtp value: */
if (mode == HRTIMER_ABS)
return -ERESTARTNOHAND;
tu = ktime_to_timespec(rem);
if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
return -EFAULT;
restart = &current_thread_info()->restart_block;
restart->fn = (clockid == CLOCK_MONOTONIC) ?
nanosleep_restart_mono : nanosleep_restart_real;
restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF;
restart->arg1 = timer.expires.tv64 >> 32;
restart->arg2 = (unsigned long) rmtp;
return -ERESTART_RESTARTBLOCK;
}
/* /*
* Functions related to boot-time initialization: * Functions related to boot-time initialization:
*/ */
......
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