diff options
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r-- | kernel/hrtimer.c | 142 |
1 files changed, 62 insertions, 80 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index e989c9981a96..59ec50c1e905 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -625,30 +625,20 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base) | |||
625 | fn = timer->function; | 625 | fn = timer->function; |
626 | data = timer->data; | 626 | data = timer->data; |
627 | set_curr_timer(base, timer); | 627 | set_curr_timer(base, timer); |
628 | timer->state = HRTIMER_RUNNING; | 628 | timer->state = HRTIMER_INACTIVE; |
629 | __remove_hrtimer(timer, base); | 629 | __remove_hrtimer(timer, base); |
630 | spin_unlock_irq(&base->lock); | 630 | spin_unlock_irq(&base->lock); |
631 | 631 | ||
632 | /* | 632 | restart = fn(data); |
633 | * fn == NULL is special case for the simplest timer | ||
634 | * variant - wake up process and do not restart: | ||
635 | */ | ||
636 | if (!fn) { | ||
637 | wake_up_process(data); | ||
638 | restart = HRTIMER_NORESTART; | ||
639 | } else | ||
640 | restart = fn(data); | ||
641 | 633 | ||
642 | spin_lock_irq(&base->lock); | 634 | spin_lock_irq(&base->lock); |
643 | 635 | ||
644 | /* Another CPU has added back the timer */ | 636 | /* Another CPU has added back the timer */ |
645 | if (timer->state != HRTIMER_RUNNING) | 637 | if (timer->state != HRTIMER_INACTIVE) |
646 | continue; | 638 | continue; |
647 | 639 | ||
648 | if (restart == HRTIMER_RESTART) | 640 | if (restart != HRTIMER_NORESTART) |
649 | enqueue_hrtimer(timer, base); | 641 | enqueue_hrtimer(timer, base); |
650 | else | ||
651 | timer->state = HRTIMER_EXPIRED; | ||
652 | } | 642 | } |
653 | set_curr_timer(base, NULL); | 643 | set_curr_timer(base, NULL); |
654 | spin_unlock_irq(&base->lock); | 644 | spin_unlock_irq(&base->lock); |
@@ -672,79 +662,70 @@ void hrtimer_run_queues(void) | |||
672 | * Sleep related functions: | 662 | * Sleep related functions: |
673 | */ | 663 | */ |
674 | 664 | ||
675 | /** | 665 | struct sleep_hrtimer { |
676 | * schedule_hrtimer - sleep until timeout | 666 | struct hrtimer timer; |
677 | * | 667 | struct task_struct *task; |
678 | * @timer: hrtimer variable initialized with the correct clock base | 668 | int expired; |
679 | * @mode: timeout value is abs/rel | 669 | }; |
680 | * | ||
681 | * Make the current task sleep until @timeout is | ||
682 | * elapsed. | ||
683 | * | ||
684 | * You can set the task state as follows - | ||
685 | * | ||
686 | * %TASK_UNINTERRUPTIBLE - at least @timeout is guaranteed to | ||
687 | * pass before the routine returns. The routine will return 0 | ||
688 | * | ||
689 | * %TASK_INTERRUPTIBLE - the routine may return early if a signal is | ||
690 | * delivered to the current task. In this case the remaining time | ||
691 | * will be returned | ||
692 | * | ||
693 | * The current task state is guaranteed to be TASK_RUNNING when this | ||
694 | * routine returns. | ||
695 | */ | ||
696 | static ktime_t __sched | ||
697 | schedule_hrtimer(struct hrtimer *timer, const enum hrtimer_mode mode) | ||
698 | { | ||
699 | /* fn stays NULL, meaning single-shot wakeup: */ | ||
700 | timer->data = current; | ||
701 | 670 | ||
702 | hrtimer_start(timer, timer->expires, mode); | 671 | static int nanosleep_wakeup(void *data) |
672 | { | ||
673 | struct sleep_hrtimer *t = data; | ||
703 | 674 | ||
704 | schedule(); | 675 | t->expired = 1; |
705 | hrtimer_cancel(timer); | 676 | wake_up_process(t->task); |
706 | 677 | ||
707 | /* Return the remaining time: */ | 678 | return HRTIMER_NORESTART; |
708 | if (timer->state != HRTIMER_EXPIRED) | ||
709 | return ktime_sub(timer->expires, timer->base->get_time()); | ||
710 | else | ||
711 | return (ktime_t) {.tv64 = 0 }; | ||
712 | } | 679 | } |
713 | 680 | ||
714 | static inline ktime_t __sched | 681 | static int __sched do_nanosleep(struct sleep_hrtimer *t, enum hrtimer_mode mode) |
715 | schedule_hrtimer_interruptible(struct hrtimer *timer, | ||
716 | const enum hrtimer_mode mode) | ||
717 | { | 682 | { |
718 | set_current_state(TASK_INTERRUPTIBLE); | 683 | t->timer.function = nanosleep_wakeup; |
684 | t->timer.data = t; | ||
685 | t->task = current; | ||
686 | t->expired = 0; | ||
687 | |||
688 | do { | ||
689 | set_current_state(TASK_INTERRUPTIBLE); | ||
690 | hrtimer_start(&t->timer, t->timer.expires, mode); | ||
691 | |||
692 | schedule(); | ||
719 | 693 | ||
720 | return schedule_hrtimer(timer, mode); | 694 | if (unlikely(!t->expired)) { |
695 | hrtimer_cancel(&t->timer); | ||
696 | mode = HRTIMER_ABS; | ||
697 | } | ||
698 | } while (!t->expired && !signal_pending(current)); | ||
699 | |||
700 | return t->expired; | ||
721 | } | 701 | } |
722 | 702 | ||
723 | static long __sched nanosleep_restart(struct restart_block *restart) | 703 | static long __sched nanosleep_restart(struct restart_block *restart) |
724 | { | 704 | { |
705 | struct sleep_hrtimer t; | ||
725 | struct timespec __user *rmtp; | 706 | struct timespec __user *rmtp; |
726 | struct timespec tu; | 707 | struct timespec tu; |
727 | void *rfn_save = restart->fn; | 708 | ktime_t time; |
728 | struct hrtimer timer; | ||
729 | ktime_t rem; | ||
730 | 709 | ||
731 | restart->fn = do_no_restart_syscall; | 710 | restart->fn = do_no_restart_syscall; |
732 | 711 | ||
733 | hrtimer_init(&timer, (clockid_t) restart->arg3, HRTIMER_ABS); | 712 | hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS); |
734 | 713 | t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; | |
735 | timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; | ||
736 | 714 | ||
737 | rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS); | 715 | if (do_nanosleep(&t, HRTIMER_ABS)) |
738 | |||
739 | if (rem.tv64 <= 0) | ||
740 | return 0; | 716 | return 0; |
741 | 717 | ||
742 | rmtp = (struct timespec __user *) restart->arg2; | 718 | rmtp = (struct timespec __user *) restart->arg2; |
743 | tu = ktime_to_timespec(rem); | 719 | if (rmtp) { |
744 | if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) | 720 | time = ktime_sub(t.timer.expires, t.timer.base->get_time()); |
745 | return -EFAULT; | 721 | if (time.tv64 <= 0) |
722 | return 0; | ||
723 | tu = ktime_to_timespec(time); | ||
724 | if (copy_to_user(rmtp, &tu, sizeof(tu))) | ||
725 | return -EFAULT; | ||
726 | } | ||
746 | 727 | ||
747 | restart->fn = rfn_save; | 728 | restart->fn = nanosleep_restart; |
748 | 729 | ||
749 | /* The other values in restart are already filled in */ | 730 | /* The other values in restart are already filled in */ |
750 | return -ERESTART_RESTARTBLOCK; | 731 | return -ERESTART_RESTARTBLOCK; |
@@ -754,33 +735,34 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
754 | const enum hrtimer_mode mode, const clockid_t clockid) | 735 | const enum hrtimer_mode mode, const clockid_t clockid) |
755 | { | 736 | { |
756 | struct restart_block *restart; | 737 | struct restart_block *restart; |
757 | struct hrtimer timer; | 738 | struct sleep_hrtimer t; |
758 | struct timespec tu; | 739 | struct timespec tu; |
759 | ktime_t rem; | 740 | ktime_t rem; |
760 | 741 | ||
761 | hrtimer_init(&timer, clockid, mode); | 742 | hrtimer_init(&t.timer, clockid, mode); |
762 | 743 | t.timer.expires = timespec_to_ktime(*rqtp); | |
763 | timer.expires = timespec_to_ktime(*rqtp); | 744 | if (do_nanosleep(&t, mode)) |
764 | |||
765 | rem = schedule_hrtimer_interruptible(&timer, mode); | ||
766 | if (rem.tv64 <= 0) | ||
767 | return 0; | 745 | return 0; |
768 | 746 | ||
769 | /* Absolute timers do not update the rmtp value and restart: */ | 747 | /* Absolute timers do not update the rmtp value and restart: */ |
770 | if (mode == HRTIMER_ABS) | 748 | if (mode == HRTIMER_ABS) |
771 | return -ERESTARTNOHAND; | 749 | return -ERESTARTNOHAND; |
772 | 750 | ||
773 | tu = ktime_to_timespec(rem); | 751 | if (rmtp) { |
774 | 752 | rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); | |
775 | if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) | 753 | if (rem.tv64 <= 0) |
776 | return -EFAULT; | 754 | return 0; |
755 | tu = ktime_to_timespec(rem); | ||
756 | if (copy_to_user(rmtp, &tu, sizeof(tu))) | ||
757 | return -EFAULT; | ||
758 | } | ||
777 | 759 | ||
778 | restart = ¤t_thread_info()->restart_block; | 760 | restart = ¤t_thread_info()->restart_block; |
779 | restart->fn = nanosleep_restart; | 761 | restart->fn = nanosleep_restart; |
780 | restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF; | 762 | restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF; |
781 | restart->arg1 = timer.expires.tv64 >> 32; | 763 | restart->arg1 = t.timer.expires.tv64 >> 32; |
782 | restart->arg2 = (unsigned long) rmtp; | 764 | restart->arg2 = (unsigned long) rmtp; |
783 | restart->arg3 = (unsigned long) timer.base->index; | 765 | restart->arg3 = (unsigned long) t.timer.base->index; |
784 | 766 | ||
785 | return -ERESTART_RESTARTBLOCK; | 767 | return -ERESTART_RESTARTBLOCK; |
786 | } | 768 | } |