diff options
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) |