rt-thread線程調度器源碼分析

1 前言

RT-Thread中提供的線程調度器是基於全搶佔式優先級的調度,在系統中除了中斷處理函數、調度器上鎖部分的代碼和禁止中斷的代碼是不可搶佔的之外,系統的其他部分都是可以搶佔的,包括線程調度器自身.系統總共支持256個優先級(0 ~ 255,數值越小的優先級越高,0爲最高優先級,255分配給空閒線程使用,一般用戶不使用。在一些資源比較緊張的系統中,可以根據情況選擇只支持8個或32個優先級的系統配置)。在系統中,當有比當前線程優先級還要高的線程就緒時,當前線程將立刻被換出,高優先級線程搶佔處理機進行執行。

2 線程優先級管理系統

rt-thread採用一個數組來實現線程優先級管理系統,如下圖所示,RT-Thread調度器實現中包含一組,總共256個優先級隊列數組(如果系統最大支持32個優先級,那麼這裏將是32個優先級隊列數組),每個優先級隊列採用雙向環形鏈表的方式鏈接,255優先級隊列中一般只包含一個idle線程。

其源碼定義如下:

[cpp] view plain copy
  1. rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];  

2 調度器初始化

[cpp] view plain copy
  1. /** 
  2.  * @ingroup SystemInit 
  3.  * This function will initialize the system scheduler 
  4.  */  
  5. void rt_system_scheduler_init(void)  
  6. {  
  7.     register rt_base_t offset;  
  8.   
  9.     rt_scheduler_lock_nest = 0;//調度器嵌套鎖計數器設爲0  
  10.   
  11.     RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",  
  12.                                       RT_THREAD_PRIORITY_MAX));  
  13.   
  14.     for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)//所有優先級對應的線程鏈表初始化  
  15.     {  
  16.         rt_list_init(&rt_thread_priority_table[offset]);  
  17.     }  
  18.   
  19.     rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;//rt_current_prority爲全局變量,初始化  
  20.     rt_current_thread = RT_NULL;//全局變量rt_current_thread初始化爲空  
  21.   
  22.     /* initialize ready priority group */  
  23.     rt_thread_ready_priority_group = 0;//全局變量rt_thread_ready_priority_group初始化爲0  
  24.   
  25. #if RT_THREAD_PRIORITY_MAX > 32  
  26.     /* initialize ready table */  
  27.     rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));  
  28. #endif  
  29.   
  30.     /* initialize thread defunct */  
  31.     rt_list_init(&rt_thread_defunct);//初始化全局空閒線程處理的回調線程鏈表,rt_thread_defunct爲這線程鏈表,只在系統空閒時被空閒線程操作  
  32. }  

3 啓動線程調度器

[cpp] view plain copy
  1. /** 
  2.  * @ingroup SystemInit 
  3.  * This function will startup scheduler. It will select one thread 
  4.  * with the highest priority level, then switch to it. 
  5.  */  
  6. void rt_system_scheduler_start(void)  
  7. {  
  8.     register struct rt_thread *to_thread;  
  9.     register rt_ubase_t highest_ready_priority;  
  10.     //以下代碼是查找出新高優先級的線程  
  11. #if RT_THREAD_PRIORITY_MAX == 8  
  12.     highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];  
  13. #else  
  14.     register rt_ubase_t number;  
  15.     /* find out the highest priority task */  
  16.     if (rt_thread_ready_priority_group & 0xff)  
  17.     {  
  18.         number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];  
  19.     }  
  20.     else if (rt_thread_ready_priority_group & 0xff00)  
  21.     {  
  22.         number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;  
  23.     }  
  24.     else if (rt_thread_ready_priority_group & 0xff0000)  
  25.     {  
  26.         number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;  
  27.     }  
  28.     else  
  29.     {  
  30.         number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;  
  31.     }  
  32.   
  33. #if RT_THREAD_PRIORITY_MAX > 32  
  34.     highest_ready_priority = (number << 3) +  
  35.                              rt_lowest_bitmap[rt_thread_ready_table[number]];  
  36. #else  
  37.     highest_ready_priority = number;  
  38. #endif  
  39. #endif  
  40.   
  41.     /* get switch to thread *///得到線程  
  42.     to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,  
  43.                               struct rt_thread,  
  44.                               tlist);  
  45.   
  46.     rt_current_thread = to_thread;//設置當前線程  
  47.   
  48.     /* switch to new thread */  
  49.     rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);//此函數是與MCU相關的函數,實現切換到目的線程的功能  
  50.   
  51.     /* never come back */  
  52. }  


4 往調度器添加線程

[cpp] view plain copy
  1. /* 
  2.  * This function will insert a thread to system ready queue. The state of 
  3.  * thread will be set as READY and remove from suspend queue. 
  4.  * 
  5.  * @param thread the thread to be inserted 
  6.  * @note Please do not invoke this function in user application. 
  7.  */  
  8. void rt_schedule_insert_thread(struct rt_thread *thread)  
  9. {  
  10.     register rt_base_t temp;  
  11.   
  12.     RT_ASSERT(thread != RT_NULL);  
  13.   
  14.     /* disable interrupt */  
  15.     temp = rt_hw_interrupt_disable();//關中斷  
  16.   
  17.     /* change stat */  
  18.     thread->stat = RT_THREAD_READY;  
  19.   
  20.     /* insert thread to ready list */  
  21.     rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),//往當前優先級鏈表中添加線程節點  
  22.                           &(thread->tlist));  
  23.   
  24.     /* set priority mask */  
  25. #if RT_THREAD_PRIORITY_MAX <= 32  
  26.     RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%s], the priority: %d\n",   
  27.                                       thread->name, thread->current_priority));  
  28. #else  
  29.     RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,  
  30.                  ("insert thread[%s], the priority: %d 0x%x %d\n",   
  31.                   thread->name,  
  32.                   thread->number,  
  33.                   thread->number_mask,  
  34.                   thread->high_mask));  
  35. #endif  
  36.   
  37. #if RT_THREAD_PRIORITY_MAX > 32  
  38.     rt_thread_ready_table[thread->number] |= thread->high_mask;  
  39. #endif  
  40.     rt_thread_ready_priority_group |= thread->number_mask;  
  41.   
  42.     /* enable interrupt */  
  43.     rt_hw_interrupt_enable(temp);//開中斷  
  44. }  

5 將線程從調度器中移除

[cpp] view plain copy
  1. /* 
  2.  * This function will remove a thread from system ready queue. 
  3.  * 
  4.  * @param thread the thread to be removed 
  5.  * 
  6.  * @note Please do not invoke this function in user application. 
  7.  */  
  8. void rt_schedule_remove_thread(struct rt_thread *thread)  
  9. {  
  10.     register rt_base_t temp;  
  11.   
  12.     RT_ASSERT(thread != RT_NULL);  
  13.   
  14.     /* disable interrupt */  
  15.     temp = rt_hw_interrupt_disable();//關中斷  
  16.   
  17. #if RT_THREAD_PRIORITY_MAX <= 32  
  18.     RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%s], the priority: %d\n",   
  19.                                       thread->name, thread->current_priority));  
  20. #else  
  21.     RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,  
  22.                  ("remove thread[%s], the priority: %d 0x%x %d\n",   
  23.                   thread->name,  
  24.                   thread->number,  
  25.                   thread->number_mask,  
  26.                   thread->high_mask));  
  27. #endif  
  28.   
  29.     /* remove thread from ready list */  
  30.     rt_list_remove(&(thread->tlist));//從隊列中移除  
  31.     if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))//如果當前優先級鏈表已空  
  32.     {  
  33. #if RT_THREAD_PRIORITY_MAX > 32  
  34.         rt_thread_ready_table[thread->number] &= ~thread->high_mask;  
  35.         if (rt_thread_ready_table[thread->number] == 0)  
  36.         {  
  37.             rt_thread_ready_priority_group &= ~thread->number_mask;  
  38.         }  
  39. #else  
  40.         rt_thread_ready_priority_group &= ~thread->number_mask;  
  41. #endif  
  42.     }  
  43.   
  44.     /* enable interrupt */  
  45.     rt_hw_interrupt_enable(temp);//開中斷  
  46. }  

6 線程調度

[cpp] view plain copy
  1. /** 
  2.  * @addtogroup Thread 
  3.  */  
  4.   
  5. /*@{*/  
  6.   
  7. /** 
  8.  * This function will perform one schedule. It will select one thread 
  9.  * with the highest priority level, then switch to it. 
  10.  */  
  11. void rt_schedule(void)  
  12. {  
  13.     rt_base_t level;  
  14.     struct rt_thread *to_thread;  
  15.     struct rt_thread *from_thread;  
  16.   
  17.     /* disable interrupt */  
  18.     level = rt_hw_interrupt_disable();//關中斷  
  19.   
  20.     /* check the scheduler is enabled or not */  
  21.     if (rt_scheduler_lock_nest == 0)//當前不處於線程嵌套中  
  22.     {  
  23.         register rt_ubase_t highest_ready_priority;  
  24.         //以下代碼是獲取當前最高優先級的線程的優先級  
  25. #if RT_THREAD_PRIORITY_MAX == 8  
  26.         highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];  
  27. #else  
  28.         register rt_ubase_t number;  
  29.         /* find out the highest priority task */  
  30.         if (rt_thread_ready_priority_group & 0xff)  
  31.         {  
  32.             number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];  
  33.         }  
  34.         else if (rt_thread_ready_priority_group & 0xff00)  
  35.         {  
  36.             number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;  
  37.         }  
  38.         else if (rt_thread_ready_priority_group & 0xff0000)  
  39.         {  
  40.             number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;  
  41.         }  
  42.         else  
  43.         {  
  44.             number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;  
  45.         }  
  46.   
  47. #if RT_THREAD_PRIORITY_MAX > 32  
  48.         highest_ready_priority = (number << 3) +  
  49.                                  rt_lowest_bitmap[rt_thread_ready_table[number]];  
  50. #else  
  51.         highest_ready_priority = number;  
  52. #endif  
  53. #endif  
  54.         /* get switch to thread *///得到最高優先級線程  
  55.         to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,  
  56.                                   struct rt_thread,  
  57.                                   tlist);  
  58.   
  59.         /* if the destination thread is not the same as current thread */  
  60.         if (to_thread != rt_current_thread)//需要線程切換  
  61.         {  
  62.             rt_current_priority = (rt_uint8_t)highest_ready_priority;//更新一些變量  
  63.             from_thread         = rt_current_thread;  
  64.             rt_current_thread   = to_thread;  
  65.   
  66.             RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));  
  67.   
  68.             /* switch to new thread */  
  69.             RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,  
  70.                          ("[%d]switch to priority#%d thread:%s\n",  
  71.                           rt_interrupt_nest,  
  72.                           highest_ready_priority,  
  73.                           to_thread->name));  
  74.   
  75. #ifdef RT_USING_OVERFLOW_CHECK  
  76.             _rt_scheduler_stack_check(to_thread);//線程棧溢出檢查  
  77. #endif  
  78.   
  79.             if (rt_interrupt_nest == 0)//如果當前沒有處於中斷嵌套中  
  80.             {  
  81.                 rt_hw_context_switch((rt_uint32_t)&from_thread->sp,//線程切換,此函數爲MCU相關函數,與具體使用的MCU相關,這裏不作介紹  
  82.                                      (rt_uint32_t)&to_thread->sp);  
  83.             }  
  84.             else//如果當前處於中斷例程中  
  85.             {  
  86.                 RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));  
  87.   
  88.                 rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,//線程切換,與rt_hw_context_switch類似  
  89.                                                (rt_uint32_t)&to_thread->sp);  
  90.             }  
  91.         }  
  92.     }  
  93.   
  94.     /* enable interrupt */  
  95.     rt_hw_interrupt_enable(level);//開中斷  
  96. }  

7 進入臨界區

此函數實現上實現的是禁止調度,也就是說,執行了此函數,調度器將不再調度線程,這個從第6章的語句if (rt_scheduler_lock_nest == 0) ...可以看出來。

[cpp] view plain copy
  1. /** 
  2.  * This function will lock the thread scheduler. 
  3.  */  
  4. void rt_enter_critical(void)  
  5. {  
  6.     register rt_base_t level;  
  7.   
  8.     /* disable interrupt */  
  9.     level = rt_hw_interrupt_disable();//關中斷  
  10.   
  11.     /* 
  12.      * the maximal number of nest is RT_UINT16_MAX, which is big 
  13.      * enough and does not check here 
  14.      */  
  15.     rt_scheduler_lock_nest ++;//調度鎖計數器加1  
  16.   
  17.     /* enable interrupt */  
  18.     rt_hw_interrupt_enable(level);//開中斷  
  19. }  

8 退出臨界區

與進入臨界區對應,此函數實現的是讓之前禁止的調度器重新調度線程,其源碼如下所示:

[cpp] view plain copy
  1. /** 
  2.  * This function will unlock the thread scheduler. 
  3.  */  
  4. void rt_exit_critical(void)  
  5. {  
  6.     register rt_base_t level;  
  7.   
  8.     /* disable interrupt */  
  9.     level = rt_hw_interrupt_disable();//關中斷  
  10.   
  11.     rt_scheduler_lock_nest --;//調度鎖嵌套計數器減1  
  12.   
  13.     if (rt_scheduler_lock_nest <= 0)//如果調度鎖嵌套計數器小於或等於0,則置其爲0  
  14.     {  
  15.         rt_scheduler_lock_nest = 0;  
  16.         /* enable interrupt */  
  17.         rt_hw_interrupt_enable(level);//開中斷  
  18.   
  19.         rt_schedule();//調度線程  
  20.     }  
  21.     else  
  22.     {  
  23.         /* enable interrupt */  
  24.         rt_hw_interrupt_enable(level);//開中斷  
  25.     }  
  26. }  

前面源碼中的調度器啓動rt_system_scheduler_start和調度rt_schedule的對應源碼中都有使用位圖來實現獲取當前最高優先級線程對應的優先緩的算法,就不在這裏做詳細介紹,下一章將專門來討論此算法。

發佈了1 篇原創文章 · 獲贊 48 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章