aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/hrtimer.h4
-rw-r--r--kernel/hrtimer.c142
2 files changed, 63 insertions, 83 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 84fc186324e6..0e8f4762f6f8 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -38,9 +38,7 @@ enum hrtimer_restart {
38 * Timer states: 38 * Timer states:
39 */ 39 */
40enum hrtimer_state { 40enum hrtimer_state {
41 HRTIMER_INACTIVE, /* Timer is inactive */ 41 HRTIMER_INACTIVE, /* Timer is inactive */
42 HRTIMER_EXPIRED, /* Timer is expired */
43 HRTIMER_RUNNING, /* Timer is running the callback function */
44 HRTIMER_PENDING, /* Timer is pending */ 42 HRTIMER_PENDING, /* Timer is pending */
45}; 43};
46 44
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/** 665struct 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 */
696static ktime_t __sched
697schedule_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); 671static 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
714static inline ktime_t __sched 681static int __sched do_nanosleep(struct sleep_hrtimer *t, enum hrtimer_mode mode)
715schedule_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
723static long __sched nanosleep_restart(struct restart_block *restart) 703static 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 = &current_thread_info()->restart_block; 760 restart = &current_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}