APM Scheduler 分析
- void AP_Scheduler::run(uint32_t time_available)
- {
- uint32_t run_started_usec = AP_HAL::micros();
- uint32_t now = run_started_usec;
- for (uint8_t i=0; i<_num_tasks; i++) {
- // dt 代表了当前任务已经调度了多少个周期
- uint16_t dt = _tick_counter - _last_run[i];
- // interval_ticks 代表这个任务需要多少个调度周期才能运行
- // 如果任务调度周期 (_loop_rate_hz) 设置成 50hz, 也就是说 20ms 调度一次, _tick_counter+1
- // 如果一个任务被设置成以 10hz 运行, 也就是 100ms 运行一次, 需要进行 50hz/10hz=5 次调度, 此任务才能被运行一次
- uint16_t interval_ticks = _loop_rate_hz / _tasks[i].rate_hz;
- // 如果调度次数小于 1, 也就是说任务调度的频率比_loop_rate_hz 还快, 则只调度一次
- // 这里通过_loop_rate_hz 限制了任务调度的最快频率
- if (interval_ticks <1) {
- interval_ticks = 1;
- }
- // 如果 dt>=interval_ticks, 代表当前任务已经达到了所需调度的周期, 可以进行调度了
- if (dt>= interval_ticks) {
- // _task_time_allowed 代表了当前任务最大允许被运行的时间
- // 这个时间在这个调度策略中并无卵用, 纯属鸡肋!!!
- // 不好意思, 也并不是完全鸡肋, 他的作用体现在当调度器剩余时间是否够当前任务最大所需时间
- // this task is due to run. Do we have enough time to run it?
- _task_time_allowed = _tasks[i].max_time_micros;
- // 当前任务所需的调度周期已经超过 2 次所需时间, 代表此任务本应该被执行了, 但是被延迟了
- // 此处没有做任何处理, 只是做了调试输出
- // 所以说每个任务即使你规定了他的调度频率, 只是一个期望值, 他受到整个系统调度的影响, 他的实时性是不确定的
- if (dt>= interval_ticks*2) {
- // we've slipped a whole run of this task!
- if (_debug> 4) {
- ::printf("Scheduler slip task[%u-%s] (%u/%u/%u)\n",
- (unsigned)i,
- _tasks[i].name,
- (unsigned)dt,
- (unsigned)interval_ticks,
- (unsigned)_task_time_allowed);
- }
- }
- // time_available 代表当前调度器还剩余多少时间来进行任务调度
- // time_available = 1000000/_loop_rate_hz= 20ms
- // 如果当前任务单次最大被允许运行的时间比剩余的时间还小, 证明系统还有足够的时间来运行他, 那么就可以运行此次任务
- // 否则跳出, 继续轮训列表中的下一次任务, 看谁还有机会被执行
- if (_task_time_allowed <= time_available) {
- // run it
- // 记下当前任务运行的开始时间
- _task_time_started = now;
- current_task = i;
- _tasks[i].function();
- current_task = -1;
- // 更新当前任务运行完成后的 tick, 为计算下一次 dt 做准备
- // record the tick counter when we ran. This drives
- // when we next run the event
- _last_run[i] = _tick_counter;
- // work out how long the event actually took
- now = AP_HAL::micros();
- // 计算出当前任务运行的时间
- uint32_t time_taken = now - _task_time_started;
- // 如果当前任务运行的时间超过了最大允许的时间, 代表当前任务已经超时运行
- // 这里只是做了打印输出, 并没有什么卵用
- if (time_taken> _task_time_allowed) {
- // the event overran!
- if (_debug> 4) {
- ::printf("Scheduler overrun task[%u-%s] (%u/%u)\n",
- (unsigned)i,
- _tasks[i].name,
- (unsigned)time_taken,
- (unsigned)_task_time_allowed);
- }
- }
- // 如果当前任务运行的时间已经超过调度器剩余的时间, 那么就直接退出任务列表调度
- // 但前任务后面的任务就不调度了
- if (time_taken>= time_available) {
- goto update_spare_ticks;
- }
- // 把调度器剩余可用的时间更新, 如果当前任务超时运行, 那么下一个任务就可能执行不到了
- time_available -= time_taken;
- }
- }
- }
- // update number of spare microseconds
- _spare_micros += time_available;
- update_spare_ticks:
- _spare_ticks++;
- if (_spare_ticks == 32) {
- _spare_ticks /= 2;
- _spare_micros /= 2;
- }
- }
来源: http://www.bubuko.com/infodetail-3112772.html