APM 任務調度器的原理分析

  1 APM Scheduler 分析
  2 
  3 void AP_Scheduler::run(uint32_t time_available)
  4 {
  5     uint32_t run_started_usec = AP_HAL::micros();
  6     uint32_t now = run_started_usec;
  7 
  8     for (uint8_t i=0; i<_num_tasks; i++) {
  9         // dt表明了當前任務已經調度了多少個週期
 10         uint16_t dt = _tick_counter - _last_run[i];
 11 
 12         // interval_ticks表明這個任務須要多少個調度週期才能運行
 13         // 若是任務調度週期(_loop_rate_hz)設置成50hz,也就是說20ms調度一次, _tick_counter+1
 14         // 若是一個任務被設置成以10hz運行,也就是100ms運行一次,須要進行50hz/10hz=5次調度,此任務才能被運行一次
 15         uint16_t interval_ticks = _loop_rate_hz / _tasks[i].rate_hz;
 16 
 17         // 若是調度次數小於1,也就是說任務調度的頻率比_loop_rate_hz還快,則只調度一次
 18         // 這裏經過_loop_rate_hz限制了任務調度的最快頻率
 19         if (interval_ticks < 1) { 
 20             interval_ticks = 1;
 21         }
 22 
 23         // 若是dt>=interval_ticks,表明當前任務已經達到了所需調度的週期,能夠進行調度了
 24         if (dt >= interval_ticks) {
 25             // _task_time_allowed表明了當前任務最大容許被運行的時間
 26             // 這個時間在這個調度策略中並沒有卵用,純屬雞肋!!!
 27             // 很差意思,也並非徹底雞肋,他的做用體如今當調度器剩餘時間是否夠當前任務最大所需時間
 28             
 29             // this task is due to run. Do we have enough time to run it?
 30             _task_time_allowed = _tasks[i].max_time_micros;
 31 
 32             // 當前任務所需的調度週期已經超過2次所需時間,表明此任務本應該被執行了,可是被延遲了
 33             // 此處沒有作任何處理,只是作了調試輸出
 34             // 因此說每一個任務即便你規定了他的調度頻率,只是一個指望值,他受到整個系統調度的影響,他的實時性是不肯定的
 35             if (dt >= interval_ticks*2) {
 36                 // we've slipped a whole run of this task!
 37                 if (_debug > 4) {
 38                     ::printf("Scheduler slip task[%u-%s] (%u/%u/%u)\n",
 39                              (unsigned)i,
 40                              _tasks[i].name,
 41                              (unsigned)dt,
 42                              (unsigned)interval_ticks,
 43                              (unsigned)_task_time_allowed);
 44                 }
 45             }
 46 
 47             // time_available表明當前調度器還剩餘多少時間來進行任務調度
 48      // time_available = 1000000/_loop_rate_hz= 20ms
 49             // 若是當前任務單次最大被容許運行的時間比剩餘的時間還小,證實系統還有足夠的時間來運行他,那麼就能夠運行這次任務
 50             // 不然跳出,繼續輪訓列表中的下一次任務,看誰還有機會被執行
 51             if (_task_time_allowed <= time_available) {
 52                 // run it
 53                 //記下當前任務運行的開始時間
 54                 _task_time_started = now;
 55                 current_task = i;
 56                 _tasks[i].function();
 57                 current_task = -1;
 58 
 59                 // 更新當前任務運行完成後的tick,爲計算下一次dt作準備
 60                 // record the tick counter when we ran. This drives
 61                 // when we next run the event
 62                 _last_run[i] = _tick_counter;
 63 
 64                 // work out how long the event actually took
 65                 now = AP_HAL::micros();
 66                 // 計算出當前任務運行的時間
 67                 uint32_t time_taken = now - _task_time_started;
 68 
 69                 // 若是當前任務運行的時間超過了最大容許的時間,表明當前任務已經超時運行
 70                 // 這裏只是作了打印輸出,並無什麼卵用
 71                 if (time_taken > _task_time_allowed) {
 72                     // the event overran!
 73                     if (_debug > 4) {
 74                         ::printf("Scheduler overrun task[%u-%s] (%u/%u)\n",
 75                                  (unsigned)i,
 76                                  _tasks[i].name,
 77                                  (unsigned)time_taken,
 78                                  (unsigned)_task_time_allowed);
 79                     }
 80                 }
 81                 // 若是當前任務運行的時間已經超過調度器剩餘的時間,那麼就直接退出任務列表調度
 82  // 但前任務後面的任務就不調度了
 83                 if (time_taken >= time_available) {
 84                     goto update_spare_ticks;
 85                 }
 86                 // 把調度器剩餘可用的時間更新,若是當前任務超時運行,那麼下一個任務就可能執行不到了
 87                 time_available -= time_taken;
 88             }
 89         }
 90     }
 91 
 92     // update number of spare microseconds
 93     _spare_micros += time_available;
 94 
 95 update_spare_ticks:
 96     _spare_ticks++;
 97     if (_spare_ticks == 32) {
 98         _spare_ticks /= 2;
 99         _spare_micros /= 2;
100     }
101 }
相關文章
相關標籤/搜索