Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -121,6 +121,12 @@ static inline int hrtimer_active(const struct hrtimer *timer)
extern unsigned long hrtimer_forward(struct hrtimer *timer,
				     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: */
extern void hrtimer_run_queues(void);

+127 −0
Original line number Diff line number Diff line
@@ -580,6 +580,133 @@ void hrtimer_run_queues(void)
		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:
 */