uC/OS-II中,规定最多可以有64个任务。每个任务的优先级不能相同,因此,优先级为0~63.数字越小,优先级越高,那么0就是最高优先级,63就是最低优先级。系统保留了优先级最高及最低的各4个,因此用户不能使用这8个优先级作为自己的任务的优先级。宏OS_LOWEST_PRIO用于设置规定最低优先级,如定义为30,那么比30数字大的更低优先级就不能用了。这里有点拗口。也就是,所有的任务不能多于31个。
系统将64个优先级分为8组,每组8个。OSRdyGrp 表示组, OSRdytbl[]表示每一组。他们定义如下:
#if OS_LOWEST_PRIO <= 63
OS_EXT INT8U OSRdyGrp; /* Ready list group */
OS_EXT INT8U OSRdyTbl[OS_RDY_TBL_SIZE]; /* Table of tasks which are ready to run */
#else
OS_EXT INT16U OSRdyGrp; /* Ready list group */
OS_EXT INT16U OSRdyTbl[OS_RDY_TBL_SIZE]; /* Table of tasks which are ready to run */
#endif
#if OS_LOWEST_PRIO <= 63
....
#define OS_RDY_TBL_SIZE ( ( OS_LOWEST_PRIO ) / 8 + 1 ) /* Size of ready table */
#else
......
#define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 16 + 1) /* Size of ready table */
#endif
这里好像是做了扩展,不局限于
8
位,貌似最多的任务不只
64
了。不管它,我们忽略另一种情况。因为不管多少任务,处理方式的是一样的。我们考虑所有优先级都有可能用到的情况,
OS_LOWEST_PRIO
就应该定义为
63
,
OS_RDY_TBL_SIZE
就是。
OSRdyTbl
就是一个含
8
个元素的数组。
好了,OSRdyGrp的每一位表示一个组,如果该位为1,表示有任务用到了该组内的优先级(由于优先级不能相同,也表明有该任务,否则没有)。OSRdyTbl[x]的每一位表示该组内的每一个优先级,为1就有。例如OSRdyGrp[bit : 2] = 1;第三组内存在一个任务,也即是优先级16~23这8个优先级存在一个及多个。如果此时OSRdyTbl[2][bit :4] = 1; 表示第三组的第5个优先级存在,也就是数值为20的优先级存在。
讲了优先级列表如何表示,那么接下来就是创建一个任务时,如何将其对应的优先级加入到列表中。这是OS_TCBInit函数的关于设置OSRdyGrp及OSRdyTbl的代码。注:以下源码,就不摘录16位的情况。
ptcb->OSTCBY = (INT8U)(prio >> 3); /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
ptcb->OSTCBX = (INT8U)(prio & 0x07);
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
.........
OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
优先级prio是传人的参数,由于不会大于
64
,
prio
为
6
位值,因此
OSTCBY
为
prio
高
3
位,表示组,不会大于
8
,
OSTCBX
为
prio
低
3
位, 表示一个组的偏移量。OSRdyGrp
和OSRdyTbl
是按位表示的,就得将数值转化为位模式。接上面的例子
prio = 20 = 0x10100
,OSTCBY是prio
的高3
位,为
1
, 表明该优先级落在第二组(从
0
开始), OSTCBBitY=0x10
,也就是
bit:1
为
1
。同理,OSTCBX= 4
,OSTCBBitX
的
bit :5
为
1
。
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
就是设置
OSRdyTbl[1]
的
bit5.
uC/OS-II每次任务调度都是运行最高优先级的任务。那么如何在所有的任务中寻找最高优先级了?前面已经介绍了,优先级信息存在OSRdyGrp,OSRdyTbl中。低位代表高优先级。先检查组,由低位到高位检查,检查到后,再在该组中由低位到高位检查,第一个为1的就是最高优先级了。
这个过程,说白了就是检查一个char型的数,所有位是1的最小的那个位。uC/OS-II中用的查表法进行的。表如下:
INT8U const OSUnMapTbl[256] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x10 to 0x1F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x20 to 0x2F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x30 to 0x3F */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x40 to 0x4F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x50 to 0x5F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x60 to 0x6F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x70 to 0x7F */
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x80 to 0x8F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x90 to 0x9F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xA0 to 0xAF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xB0 to 0xBF */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xC0 to 0xCF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xD0 to 0xDF */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xE0 to 0xEF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 0xF0 to 0xFF */
};
下面是OS_SchedNew()函数中获取最高优先级的代码:
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
y
就是查表得到的最小的那一个组的,上面已经解释过了,优先级的高
3
位表示组,所以左移
3
位到高三位。加上查表得到的该组内的偏移量,就是最高优先级的数值了。
该方法还是挺巧妙的。让每次查找进行几条语句就可以实现了。这个方法可以借鉴到其他地方。