diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2006-01-09 23:52:35 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-10 11:01:38 -0500 |
| commit | 10c94ec16dd187f8d8dfdbb088e98330c05bf03c (patch) | |
| tree | d24036d92c24cea0c1cd163409177ecb735468e6 /kernel | |
| parent | 2ff678b8da6478d861c1b0ecb3ac14575760e906 (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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/hrtimer.c | 127 |
1 files changed, 127 insertions, 0 deletions
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 | */ | ||
| 608 | static ktime_t __sched | ||
| 609 | schedule_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 | |||
| 626 | static inline ktime_t __sched | ||
| 627 | schedule_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 | |||
| 635 | static long __sched | ||
| 636 | nanosleep_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 | |||
| 665 | static long __sched nanosleep_restart_mono(struct restart_block *restart) | ||
| 666 | { | ||
| 667 | return nanosleep_restart(restart, CLOCK_MONOTONIC); | ||
| 668 | } | ||
| 669 | |||
| 670 | static long __sched nanosleep_restart_real(struct restart_block *restart) | ||
| 671 | { | ||
| 672 | return nanosleep_restart(restart, CLOCK_REALTIME); | ||
| 673 | } | ||
| 674 | |||
| 675 | long 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 = ¤t_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 | */ |
| 586 | static void __devinit init_hrtimers_cpu(int cpu) | 713 | static void __devinit init_hrtimers_cpu(int cpu) |
