long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; struct hrtimer_sleeper t; struct timespec tu; ktime_t rem; hrtimer_init(&t.timer, clockid, mode); hrtimer_set_expires(&t.timer, timespec_to_ktime(*rqtp)); if (do_nanosleep(&t, mode)) return 0; /* Absolute timers do not update the rmtp value and restart: */ if (mode == HRTIMER_MODE_ABS) return -ERESTARTNOHAND; if (rmtp) { rem = hrtimer_expires_remaining(&t.timer); if (rem.tv64 <= 0) return 0; tu = ktime_to_timespec(rem); if (copy_to_user(rmtp, &tu, sizeof(tu))) return -EFAULT; } restart = ¤t_thread_info()->restart_block; restart->fn = hrtimer_nanosleep_restart; restart->nanosleep.index = t.timer.base->index; restart->nanosleep.rmtp = rmtp; restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); return -ERESTART_RESTARTBLOCK; }
long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; struct timespec __user *rmtp; struct timespec tu; ktime_t time; hrtimer_init(&t.timer, restart->nanosleep.index, HRTIMER_MODE_ABS); hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); if (do_nanosleep(&t, HRTIMER_MODE_ABS)) return 0; rmtp = restart->nanosleep.rmtp; if (rmtp) { time = hrtimer_expires_remaining(&t.timer); if (time.tv64 <= 0) return 0; tu = ktime_to_timespec(time); if (copy_to_user(rmtp, &tu, sizeof(tu))) return -EFAULT; } /* The other values in restart are already filled in */ return -ERESTART_RESTARTBLOCK; }
int cancel_enforcement_timer(struct task_struct* t) { struct enforcement_timer* et; int ret = 0; unsigned long flags; BUG_ON(!t); BUG_ON(!is_realtime(t)); et = &tsk_rt(t)->budget.timer; TRACE_TASK(t, "canceling enforcement timer.\n"); if (et->armed) { raw_spin_lock_irqsave(&et->lock, flags); if (et->armed) { ret = hrtimer_try_to_cancel(&et->timer); if (ret < 0) TRACE_TASK(t, "timer already running. failed to cancel.\n"); else { TRACE_TASK(t, "canceled timer with %lld ns remaining.\n", ktime_to_ns(hrtimer_expires_remaining(&et->timer))); et->armed = 0; } } else TRACE_TASK(t, "timer was not armed (race).\n"); raw_spin_unlock_irqrestore(&et->lock, flags); } else TRACE_TASK(t, "timer was not armed.\n"); return ret; }
/** * hrtimer_get_remaining - get remaining time for the timer * @timer: the timer to read */ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) { unsigned long flags; ktime_t rem; lock_hrtimer_base(timer, &flags); rem = hrtimer_expires_remaining(timer); unlock_hrtimer_base(timer, &flags); return rem; }
/** * hrtimer_get_remaining - get remaining time for the timer * @timer: the timer to read * @adjust: adjust relative timers when CONFIG_TIME_LOW_RES=y */ ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust) { unsigned long flags; ktime_t rem; lock_hrtimer_base(timer, &flags); if (IS_ENABLED(CONFIG_TIME_LOW_RES) && adjust) rem = hrtimer_expires_remaining_adjusted(timer); else rem = hrtimer_expires_remaining(timer); unlock_hrtimer_base(timer, &flags); return rem; }
static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) { struct timespec rmt; ktime_t rem; rem = hrtimer_expires_remaining(timer); if (rem.tv64 <= 0) return 0; rmt = ktime_to_timespec(rem); if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) return -EFAULT; return 1; }
int sched_wait_interval(int flags, const struct timespec __user * rqtp, struct timespec __user * rmtp) { struct hrtimer_sleeper t; enum hrtimer_mode mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; int ret = 0; hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, mode); hrtimer_set_expires(&t.timer, timespec_to_ktime(*rqtp)); hrtimer_init_sleeper(&t, current); do { set_current_state(TASK_INTERRUPTIBLE); hrtimer_start_expires(&t.timer, mode); if (!hrtimer_active(&t.timer)) t.task = NULL; if (likely(t.task)) { t.task->dl.flags |= DL_NEW; schedule(); } hrtimer_cancel(&t.timer); mode = HRTIMER_MODE_ABS; } while (t.task && !signal_pending(current)); __set_current_state(TASK_RUNNING); if (t.task == NULL) goto out; if (mode == HRTIMER_MODE_ABS) { ret = -ERESTARTNOHAND; goto out; } if (rmtp) { ktime_t rmt; struct timespec rmt_ts; rmt = hrtimer_expires_remaining(&t.timer); if (rmt.tv64 > 0) goto out; rmt_ts = ktime_to_timespec(rmt); if (!timespec_valid(&rmt_ts)) goto out; *rmtp = rmt_ts; } out: destroy_hrtimer_on_stack(&t.timer); return ret; }
static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) { struct restart_block *restart; hrtimer_init_sleeper(t, current); do { set_current_state(TASK_INTERRUPTIBLE); hrtimer_start_expires(&t->timer, mode); if (likely(t->task)) freezable_schedule(); hrtimer_cancel(&t->timer); mode = HRTIMER_MODE_ABS; } while (t->task && !signal_pending(current)); __set_current_state(TASK_RUNNING); if (!t->task) return 0; restart = ¤t->restart_block; if (restart->nanosleep.type != TT_NONE) { ktime_t rem = hrtimer_expires_remaining(&t->timer); struct timespec64 rmt; if (rem <= 0) return 0; rmt = ktime_to_timespec64(rem); return nanosleep_copyout(restart, &rmt); } return -ERESTART_RESTARTBLOCK; }