Linux 内核时钟之高精度处理

 
 

/*  * Called from run_local_timers in hardirq context every jiffy  */ void hrtimer_run_queues(void) {  struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);  ktime_t now;

 if (__hrtimer_hres_active(cpu_base))   return;

 /*   * This _is_ ugly: We have to check periodically, whether we   * can switch to highres and / or nohz mode. The clocksource   * switch happens with xtime_lock held. Notification from   * there only sets the check bit in the tick_oneshot code,   * otherwise we might deadlock vs. xtime_lock.   */  if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {   hrtimer_switch_to_hres();   return;  }

 raw_spin_lock(&cpu_base->lock);  now = hrtimer_update_base(cpu_base);  __hrtimer_run_queues(cpu_base, now);  raw_spin_unlock(&cpu_base->lock); }

static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) {  struct hrtimer_clock_base *base = cpu_base->clock_base;  unsigned int active = cpu_base->active_bases;

 for (; active; base++, active >>= 1) {   struct timerqueue_node *node;   ktime_t basenow;

  if (!(active & 0x01))    continue;

  basenow = ktime_add(now, base->offset);

  while ((node = timerqueue_getnext(&base->active))) {    struct hrtimer *timer;

   timer = container_of(node, struct hrtimer, node);

   /*     * The immediate goal for using the softexpires is     * minimizing wakeups, not running timers at the     * earliest interrupt after their soft expiration.     * This allows us to avoid using a Priority Search     * Tree, which can answer a stabbing querry for     * overlapping intervals and instead use the simple     * BST we already have.     * We don't add extra wakeups by delaying timers that     * are right-of a not yet expired timer, because that     * timer will have to trigger a wakeup anyway.     */    if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer))     break;

   __run_hrtimer(cpu_base, base, timer, &basenow);   }  } }

/*  * The write_seqcount_barrier()s in __run_hrtimer() split the thing into 3  * distinct sections:  *  *  - queued: the timer is queued  *  - callback: the timer is being ran  *  - post: the timer is inactive or (re)queued  *  * On the read side we ensure we observe timer->state and cpu_base->running  * from the same section, if anything changed while we looked at it, we retry.  * This includes timer->base changing because sequence numbers alone are  * insufficient for that.  *  * The sequence numbers are required because otherwise we could still observe  * a false negative if the read side got smeared over multiple consequtive  * __run_hrtimer() invocations.  */

static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,      struct hrtimer_clock_base *base,      struct hrtimer *timer, ktime_t *now) {  enum hrtimer_restart (*fn)(struct hrtimer *);  int restart;

 lockdep_assert_held(&cpu_base->lock);

 debug_deactivate(timer);  cpu_base->running = timer;

 /*   * Separate the ->running assignment from the ->state assignment.   *   * As with a regular write barrier, this ensures the read side in   * hrtimer_active() cannot observe cpu_base->running == NULL &&   * timer->state == INACTIVE.   */  raw_write_seqcount_barrier(&cpu_base->seq);

 __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0);  timer_stats_account_hrtimer(timer);  fn = timer->function;

 /*   * Clear the 'is relative' flag for the TIME_LOW_RES case. If the   * timer is restarted with a period then it becomes an absolute   * timer. If its not restarted it does not matter.   */  if (IS_ENABLED(CONFIG_TIME_LOW_RES))   timer->is_rel = false;

 /*   * Because we run timers from hardirq context, there is no chance   * they get migrated to another cpu, therefore its safe to unlock   * the timer base.   */  raw_spin_unlock(&cpu_base->lock);  trace_hrtimer_expire_entry(timer, now);  restart = fn(timer);  trace_hrtimer_expire_exit(timer);  raw_spin_lock(&cpu_base->lock);

 /*   * Note: We clear the running state after enqueue_hrtimer and   * we do not reprogram the event hardware. Happens either in   * hrtimer_start_range_ns() or in hrtimer_interrupt()   *   * Note: Because we dropped the cpu_base->lock above,   * hrtimer_start_range_ns() can have popped in and enqueued the timer   * for us already.   */  if (restart != HRTIMER_NORESTART &&      !(timer->state & HRTIMER_STATE_ENQUEUED))   enqueue_hrtimer(timer, base);

 /*   * Separate the ->running assignment from the ->state assignment.   *   * As with a regular write barrier, this ensures the read side in   * hrtimer_active() cannot observe cpu_base->running == NULL &&   * timer->state == INACTIVE.   */  raw_write_seqcount_barrier(&cpu_base->seq);

 WARN_ON_ONCE(cpu_base->running != timer);  cpu_base->running = NULL; }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值