优先级是任务的重要属性,也是内核在调度时的依据。对于nucleus中的优先级管理,仔细看过代码的人应该都能够理得清楚。但其中使用的查询表,我想就不是每个人都清楚的了。而如果你不清楚查询表为什么是那个样子,我估计你对于优先级管理这一块也就不会十分透彻了。
下面先结合具体的代码简单介绍一下与优先级相关的操作。
/* 两个全局变量 */
extern UNSIGNED TCD_Priority_Groups; /* unsigned long */
extern DATA_ELEMENT TCD_Sub_Priority_Groups[TC_MAX_GROUPS]; /* unsigned char */
1. 创建一个task时
/* 优先级值的低三位作为其在某一优先级组内的值 */
task -> tc_sub_priority = (DATA_ELEMENT) (1 << (priority & 7));
/* 优先级值的高五位是优先级组的索引值 */
priority = priority >> 3;
/* 若某一优先级属于某一优先级组,则相应位置1 */
task -> tc_priority_group = ((UNSIGNED) 1) << priority;
/* 保存指向优先级组的指针 */
task -> tc_sub_priority_ptr = &(TCD_Sub_Priority_Groups[priority]);
2. 运行一个task时
/* 根据task的两个值置全局变量变量的相应位 */
/* Update the priority group bit map to indicate that this
priority now has a task ready. */
TCD_Priority_Groups =
TCD_Priority_Groups | (task -> tc_priority_group);
/* Update the sub-priority bit map to show that this priority
is ready. */
*(task -> tc_sub_priority_ptr) =
(*(task -> tc_sub_priority_ptr)) | task -> tc_sub_priority;
3. 调度时查询当前最高优先级
#define TC_HIGHEST_MASK 0x000000FFUL
#define TC_NEXT_HIGHEST_MASK 0x0000FF00UL
#define TC_NEXT_LOWEST_MASK 0x00FF0000UL
#define TC_LOWEST_MASK 0xFF000000UL
/* Find the next highest priority task. */
/* 分为两个过程:找最低的优先级组和优先级组中最低优先级
优先级组又按八个一组来组织,查询时先判断属于哪一组,得出一个起始值。*/
if (TCD_Priority_Groups & TC_HIGHEST_MASK)
/* Base of sub-group is 0. */
index = 0;
else if (TCD_Priority_Groups & TC_NEXT_HIGHEST_MASK)
/* Base of sub-group is 8. */
index = 8;
else if (TCD_Priority_Groups & TC_NEXT_LOWEST_MASK)
/* Base of sub-group is 16. */
index = 16;
else
/* Base of sub-group is 24. */
index = 24;
/* Calculate the highest available priority. */
/* 再将TCD_Priority_Groups值中与那一组相关的数据取出作为索引值在表中查询
从而得到相对于起始值的偏移值,两者相加即是当前最高优先级task所在的优先级组的值。*/
index = index + TCD_Lowest_Set_Bit[(INT)(TCD_Priority_Groups >> index) & TC_HIGHEST_MASK)];
/* Get the mask of the priority within the group of 8 priorities. */
temp = TCD_Sub_Priority_Groups[index];
/* Calculate the actual priority. */
/* 根据task对应的优先级组中的值查表得到在该优先组中最高的优先级,将优先级组
的值乘以8再加上该值,即是当前最高优先级 */
TCD_Highest_Priority = (index << 3) + TCD_Lowest_Set_Bit[temp];
/***************************************************************************************/
下面重点说说这个查询表。
先举个例子来说明具体查询过程。假设TCD_Priority_Groups值为 0x00208c00(0000 0000 0010 0000 1000 1100 0000 0000), 则index = 8, 然后再取出0x8c, 作为索引值在表中查询,得到2,两者相加得到10,此即最高优先级所在的优先级组的值。再假设TCD_Sub_Priority_Groups[10]= 2,去表中查询得到1,则最高优先级即为10*8+2=82。
那么这个表中的数据是怎么的呢?其实根据这个表查出来的是某一给定八位二进制值中最低的1所处的位置。明白了这一点,也就可以理解这个表了。例如当最低的1位于第0位(从低位到高位依次为0,1,2...7)时,则不管高位是什么值,查出来的值始终应是0。也即不管给的值是从0000 0001B到1111 1111B中的哪一个值,查询该表得出的值都是0。因而在表的第1(0000 0001), 3(0000 0011), 5(0000 0101)...... 各位置处都应填零。当最低的1位于第1位时,则不管高位是什么值,查出来的值始终应是1。也即不管给的值是从0000 0010B到1111 1110B中的哪一个值,查询该表得出的值都是1。因而在表的第2(0000 0010), 6(0000 0110), 10(0000 1010)...... 各位置处都应填1。当最低的1位于第2位时,在表的第4,12,20......各位置处都应填2。当最低的1位于第3位时,在表的第8,24,40......各位置处都应填3。这些值位于表的第1行。当最低的1位于第4,5,6位时类推。当最低的1位于第7位时,只有一个值,也即第128个值为7。表中第0位置处的数据为0,但实际上这个值并不会被用到。
以上是关于nucleus中用到的查询表的说明,其实ucos-II中的也一样,笔者也曾仔细分析过。
附录:部分代码及查询表
/*TCC_Create_Task()*/
task -> tc_sub_priority = (DATA_ELEMENT) (1 << (priority & 7));
priority = priority >> 3;
task -> tc_priority_group = ((UNSIGNED) 1) << priority;
task -> tc_sub_priority_ptr = &(TCD_Sub_Priority_Groups[priority]);
/*TCC_Resume_Task()*/
/* Update the priority group bit map to indicate that this
priority now has a task ready. */
TCD_Priority_Groups =
TCD_Priority_Groups | (task -> tc_priority_group);
/* Update the sub-priority bit map to show that this priority
is ready. */
*(task -> tc_sub_priority_ptr) =
(*(task -> tc_sub_priority_ptr)) | task -> tc_sub_priority;
/*TCC_Signal_Shell()*/
/* Find the next highest priority task. */
if (TCD_Priority_Groups & TC_HIGHEST_MASK)
/* Base of sub-group is 0. */
index = 0;
else if (TCD_Priority_Groups & TC_NEXT_HIGHEST_MASK)
/* Base of sub-group is 8. */
index = 8;
else if (TCD_Priority_Groups & TC_NEXT_LOWEST_MASK)
/* Base of sub-group is 16. */
index = 16;
else
/* Base of sub-group is 24. */
index = 24;
/* Calculate the highest available priority. */
index = index + TCD_Lowest_Set_Bit[(INT)
((TCD_Priority_Groups >> index) & TC_HIGHEST_MASK)];
/* Get the mask of the priority within the group of
8 priorities. */
temp = TCD_Sub_Priority_Groups[index];
/* Calculate the actual priority. */
TCD_Highest_Priority =
(index << 3) + TCD_Lowest_Set_Bit[temp];
/* 此表经过重新排列,以方便理解 */
UNSIGNED_CHAR TCD_Lowest_Set_Bit[] = {
0, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0,
3, 0, 1, 0, 2, 0, 1, 0
} ;