History

[PATCH] hrtimer: create hrtimer nanosleep API

introduce the hrtimer_nanosleep() and hrtimer_nanosleep_real() APIs. Not yet used by any code.

Thomas Gleixner committed 20 years ago

Commit 10c94ec1 parent 2ff678b2 files · +133 −0Browse files

Unified · Split

2 files
  1. include/linux/hrtimer.h +6 −0
  2. kernel/hrtimer.c +127 −0
include/linux/hrtimer.h+6−0
@@ -121,6 +121,12 @@ static inline int hrtimer_active(const struct hrtimer *timer) · 120 unmodified lines
121121 extern unsigned long hrtimer_forward(struct hrtimer *timer,
122122 const ktime_t interval);
123123
124+/* Precise sleep: */
125+extern long hrtimer_nanosleep(struct timespec *rqtp,
126+ struct timespec __user *rmtp,
127+ const enum hrtimer_mode mode,
128+ const clockid_t clockid);
129+
124130 /* Soft interrupt function to run the hrtimer queues: */
125131 extern void hrtimer_run_queues(void);
126132
kernel/hrtimer.c+127−0
@@ -580,6 +580,133 @@ void hrtimer_run_queues(void) · 579 unmodified lines
580580 run_hrtimer_queue(&base[i]);
581581 }
582582
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 = &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+
583710 /*
584711 * Functions related to boot-time initialization:
585712 */