aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2006-01-09 23:52:35 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-10 11:01:38 -0500
commit10c94ec16dd187f8d8dfdbb088e98330c05bf03c (patch)
treed24036d92c24cea0c1cd163409177ecb735468e6
parent2ff678b8da6478d861c1b0ecb3ac14575760e906 (diff)
[PATCH] hrtimer: create hrtimer nanosleep API
introduce the hrtimer_nanosleep() and hrtimer_nanosleep_real() APIs. Not yet used by any code. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/hrtimer.h6
-rw-r--r--kernel/hrtimer.c127
2 files changed, 133 insertions, 0 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 64f8d554fbb8..2ac20b48b2f3 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -121,6 +121,12 @@ static inline int hrtimer_active(const struct hrtimer *timer)
121extern unsigned long hrtimer_forward(struct hrtimer *timer, 121extern unsigned long hrtimer_forward(struct hrtimer *timer,
122 const ktime_t interval); 122 const ktime_t interval);
123 123
124/* Precise sleep: */
125extern long hrtimer_nanosleep(struct timespec *rqtp,
126 struct timespec __user *rmtp,
127 const enum hrtimer_mode mode,
128 const clockid_t clockid);
129
124/* Soft interrupt function to run the hrtimer queues: */ 130/* Soft interrupt function to run the hrtimer queues: */
125extern void hrtimer_run_queues(void); 131extern void hrtimer_run_queues(void);
126 132
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 690efd9d9adf..64d37a3c5948 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -581,6 +581,133 @@ void hrtimer_run_queues(void)
581} 581}
582 582
583/* 583/*
584 * Sleep related functions:
585 */
586
587/**
588 * schedule_hrtimer - sleep until timeout
589 *
590 * @timer: hrtimer variable initialized with the correct clock base
591 * @mode: timeout value is abs/rel
592 *
593 * Make the current task sleep until @timeout is
594 * elapsed.
595 *
596 * You can set the task state as follows -
597 *
598 * %TASK_UNINTERRUPTIBLE - at least @timeout is guaranteed to
599 * pass before the routine returns. The routine will return 0
600 *
601 * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
602 * delivered to the current task. In this case the remaining time
603 * will be returned
604 *
605 * The current task state is guaranteed to be TASK_RUNNING when this
606 * routine returns.
607 */
608static ktime_t __sched
609schedule_hrtimer(struct hrtimer *timer, const enum hrtimer_mode mode)
610{
611 /* fn stays NULL, meaning single-shot wakeup: */
612 timer->data = current;
613
614 hrtimer_start(timer, timer->expires, mode);
615
616 schedule();
617 hrtimer_cancel(timer);
618
619 /* Return the remaining time: */
620 if (timer->state != HRTIMER_EXPIRED)
621 return ktime_sub(timer->expires, timer->base->get_time());
622 else
623 return (ktime_t) {.tv64 = 0 };
624}
625
626static inline ktime_t __sched
627schedule_hrtimer_interruptible(struct hrtimer *timer,
628 const enum hrtimer_mode mode)
629{
630 set_current_state(TASK_INTERRUPTIBLE);
631
632 return schedule_hrtimer(timer, mode);
633}
634
635static long __sched
636nanosleep_restart(struct restart_block *restart, clockid_t clockid)
637{
638 struct timespec __user *rmtp, tu;
639 void *rfn_save = restart->fn;
640 struct hrtimer timer;
641 ktime_t rem;
642
643 restart->fn = do_no_restart_syscall;
644
645 hrtimer_init(&timer, clockid);
646
647 timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
648
649 rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS);
650
651 if (rem.tv64 <= 0)
652 return 0;
653
654 rmtp = (struct timespec __user *) restart->arg2;
655 tu = ktime_to_timespec(rem);
656 if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
657 return -EFAULT;
658
659 restart->fn = rfn_save;
660
661 /* The other values in restart are already filled in */
662 return -ERESTART_RESTARTBLOCK;
663}
664
665static long __sched nanosleep_restart_mono(struct restart_block *restart)
666{
667 return nanosleep_restart(restart, CLOCK_MONOTONIC);
668}
669
670static long __sched nanosleep_restart_real(struct restart_block *restart)
671{
672 return nanosleep_restart(restart, CLOCK_REALTIME);
673}
674
675long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
676 const enum hrtimer_mode mode, const clockid_t clockid)
677{
678 struct restart_block *restart;
679 struct hrtimer timer;
680 struct timespec tu;
681 ktime_t rem;
682
683 hrtimer_init(&timer, clockid);
684
685 timer.expires = timespec_to_ktime(*rqtp);
686
687 rem = schedule_hrtimer_interruptible(&timer, mode);
688 if (rem.tv64 <= 0)
689 return 0;
690
691 /* Absolute timers do not update the rmtp value: */
692 if (mode == HRTIMER_ABS)
693 return -ERESTARTNOHAND;
694
695 tu = ktime_to_timespec(rem);
696
697 if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
698 return -EFAULT;
699
700 restart = &current_thread_info()->restart_block;
701 restart->fn = (clockid == CLOCK_MONOTONIC) ?
702 nanosleep_restart_mono : nanosleep_restart_real;
703 restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF;
704 restart->arg1 = timer.expires.tv64 >> 32;
705 restart->arg2 = (unsigned long) rmtp;
706
707 return -ERESTART_RESTARTBLOCK;
708}
709
710/*
584 * Functions related to boot-time initialization: 711 * Functions related to boot-time initialization:
585 */ 712 */
586static void __devinit init_hrtimers_cpu(int cpu) 713static void __devinit init_hrtimers_cpu(int cpu)