摘录原文:
http://blog.csdn.net/bresponse/article/details/7164895
os_core.c
/*
*********************************************************************************************************
* PRIORITY RESOLUTION TABLE
*
* Note: Index into table is bit pattern to resolve highest priority
* Indexed value corresponds to highest priority bit position (i.e. 0..7)
*********************************************************************************************************
*/
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 */
};
ucos_ii.h
#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
INT8U OSTCBX; /* Bit position in group corresponding to task priority */012位
// ptcb->OSTCBX = (INT8U)(prio & 0x07);
INT8U OSTCBY; /* Index into ready table corresponding to task priority */345位
//ptcb->OSTCBY = (INT8U)(prio >> 3);
#if OS_LOWEST_PRIO <= 63
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */根据优先级012位的值定
//ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */
//ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
#else
INT16U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT16U OSTCBBitY; /* Bit mask to access bit position in ready group */
#endif
见os_core.c的void OSTimeTick (void)有如下
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
os_core.c
void OS_EventTaskWait (OS_EVENT *pevent)
{
INT8U y;
OSTCBCur->OSTCBEventPtr = pevent; /* Store pointer to event control block in TCB */
y = OSTCBCur->OSTCBY; /* Task no longer ready */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
}
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
}
static void OS_SchedNew (void)
{
#if OS_LOWEST_PRIO <= 63 /* See if we support up to 64 tasks */
INT8U y;
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
#else /* We support up to 256 tasks */
INT8U y;
INT16U *ptbl;
if ((OSRdyGrp & 0xFF) != 0) {
y = OSUnMapTbl[OSRdyGrp & 0xFF];
} else {
y = OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8;
}
ptbl = &OSRdyTbl[y];
if ((*ptbl & 0xFF) != 0) {
OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl & 0xFF)]);
} else {
OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8);
}
#endif
}
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
{
OS_TCB *ptcb;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
ptcb = OSTCBFreeList; /* Get a free TCB from the free TCB list */
if (ptcb != (OS_TCB *)0) {
OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list */
OS_EXIT_CRITICAL();
ptcb->OSTCBStkPtr = ptos; /* Load Stack pointer in TCB */
ptcb->OSTCBPrio = prio; /* Load task priority into TCB */
ptcb->OSTCBStat = OS_STAT_RDY; /* Task is ready to run */
ptcb->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
ptcb->OSTCBDly = 0; /* Task is not delayed */
#if OS_TASK_CREATE_EXT_EN > 0
ptcb->OSTCBExtPtr = pext; /* Store pointer to TCB extension */
ptcb->OSTCBStkSize = stk_size; /* Store stack size */
ptcb->OSTCBStkBottom = pbos; /* Store pointer to bottom of stack */
ptcb->OSTCBOpt = opt; /* Store task options */
ptcb->OSTCBId = id; /* Store task ID */
#else
pext = pext; /* Prevent compiler warning if not used */
stk_size = stk_size;
pbos = pbos;
opt = opt;
id = id;
#endif
#if OS_LOWEST_PRIO <= 63
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);
#else
ptcb->OSTCBY = (INT8U)((prio >> 4) & 0xFF);/* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY);
ptcb->OSTCBX = (INT8U)(prio & 0x0F);
ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX);
#endif
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = ptcb;
ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */
ptcb->OSTCBPrev = (OS_TCB *)0;
if (OSTCBList != (OS_TCB *)0) {
OSTCBList->OSTCBPrev = ptcb;
}
OSTCBList = ptcb;
OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OSTaskCtr++; /* Increment the #tasks counter */
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
}
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NO_MORE_TCB);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OSOSRdyTbl[0]的bit7-bit0对应于优先级7-0,
OSOSRdyTbl[1]的bit7-bit0对应于优先级15-8,
OSOSRdyTbl[2]的bit7-bit0对应于优先级23-16,
OSOSRdyTbl[3]的bit7-bit0对应于优先级31-24,
OSOSRdyTbl[4]的bit7-bit0对应于优先级39-32,
OSOSRdyTbl[5]的bit7-bit0对应于优先级47-40,
OSOSRdyTbl[6]的bit7-bit0对应于优先级55-48,
OSOSRdyTbl[7]的bit7-bit0对应于优先级63-56
OSRdyGrp确定了优先级的次低三位(bit5-bit3),OSOSRdyTbl确定了优先级的低三位(bit2-bit0),
OSRdyGrp = 0x011; //0b00010001
OSRdyTbl[0] = 0x0a; //0b00001010
OSRdyTbl[4] = 0x01; //0b00000001
计算出存在的几个优先级为;0*8+1=1,0*8+3=3,4*8+0=32
假设OSRdyGrp最低位为1的是X位,OSRdyTbl[X]最低为1的是Y位,
则优先级=X*8+Y
因此只要知道了上述的X,Y就可算出最高优先级
OSUnMapTbl就是将0x00-0xff每个数据中最低位为1的位数一一列举出来
INT8U const OSUnMapTbl[256] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */
//OSUnMapTbl[0]
//OSUnMapTbl[1] 1 bit0
//OSUnMapTbl[2] 2 bit1
//OSUnMapTbl[3] 3 bit0
//................
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 */
};
其中第一行
0u==0x00 ==00000000b 最低位为1的位数为 bit0==0u (其实为空,空的情况默认为0,不影响计算)
1u==0x01 ==00000001b 最低位为1的位数为 bit0==0u
2u==0x02 ==00000010b 最低位为1的位数为 bit1==1u
3u==0x03 ==00000011b 最低位为1的位数为 bit0==0u (有两个为1的位,bit0,bit1,取最小的,因为OSRdyGrp或OSOSRdyTbl中最小的位数 对应的优先级越大)
4u==0x04 ==00000100b 最低位为1的位数为 bit2==2u
5u==0x05 ==00000101b 最低位为1的位数为 bit0==0u
6u==0x06 ==00000110b 最低位为1的位数为 bit1==1u
7u==0x07 ==00000111b 最低位为1的位数为 bit0==0u
8u==0x08 ==00001000b 最低位为1的位数为 bit3==3u
9u==0x09 ==00001001b 最低位为1的位数为 bit0==0u
Au==0x0A ==00001010b 最低位为1的位数为 bit1==1u
Bu==0x0B ==00001011b 最低位为1的位数为 bit0==0u
Cu==0x0C ==00001100b 最低位为1的位数为 bit2==2u
Du==0x0D ==00001101b 最低位为1的位数为 bit0==0u
Eu==0x0E ==00001110b 最低位为1的位数为 bit1==1u
Fu==0x0F ==00001111b 最低位为1的位数为 bit0==0u
其他行类推,能得出上表,其实通过上面的推导,可以看出,上表中主要是求0~255(0x00~0xFF)之间数的最低位为1的所在的位数,
X = OSUnMapTbl[OSRdyGrp];
Y = OSUnMapTbl[OSRdyTbl[X]];
最高优先级为X*8+Y
----------------------------------
咋一看这个数组还真有点怪异。数组如下:
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 */
};
INT8U是为防止不同编译器相同数据类型的长度不一导致代码可移植差而在在os_cpu.h中声明的一个数据类型,跟unsigned char相同,表示无符号的8位数。
这个有256个元素的数组是通过任务就绪表找到就绪任务中优先级最高的任务所用到的数组。代码如下:
y=OSUnMapTal[OSRdyGrp];//获得优先级别的D5、D4、D3位
x=OSUnMapTal[OSRdyTbl[y]]; //获得优先级别的D2、D1 、D0位
prio=(y<<3)+x;
prio是表示优先级的一个无符号八位数,不过只有低六位有效。prio与就绪任务表的两个数组的关系是这样的:prio高三位表示组数,即OSRdyGrp中的哪一位是一。低三位表示这一组中的位数,即OSRdyTbl中的哪一位是一。例如,如果prio是
0b00 011 001(十进制25),即优先级是25。则OSRdyGrp中的第三位是被置一的(25/8=3),
OSRdyTb(25&0b0111=1)中的第一位是被置一的。
由于有可能有很多任务是处于就绪状态的,也就是说OSRdyGrp和OSRdyTbl[]中均有可能不止一位是被置一的。由于优先级的数字越小,级数越高,所以要从这些就绪的任务中找出优先级最高的任务,就需要找出这两个数组中被置为一的最低位。
于是这个数组就这样产生了:当OSRdyGrp中被置为一的最低位是第三位(0~7位)时,表示优先级最高位是处于第三组(0~7),也就是说prio的有效位的高三位应该是011。于是OSUnMapTbl[]数组中所有对应于0bx x x x1000的元素的值都是011(3)。其它元素值同理可得。
低三位同理。由就绪任务表通过这个数组就找到了所有就绪任务中优先级最高的任务的优先级了。
当然由任务表找出处于就绪状态的拥有最高优先级的任务的优先级也可以编写一个循环程序在就绪表中查找。但是这样比较耗时,并且犯了实时系统的大忌——运算时间不可预测。所以采用了这样一个查表的方法。也算是用空间换取时间吧。
接触过uCOS-II的都应该知道,任务调度中的就绪表由两部分组成:OSRdyGrp和OSRdyTbl[]。在需要进行任务切换时,通过:
y = OSUnMapTbl[OSRdyGrp];-----------(1)
x = OSUnMapTbl[OSRdyTbl[y]];--------(2)
prio = (y << 3) + x;----------------(3)
即可以查到当前就绪态的任务中的最高优先级任务。
在此,便有一个疑问:为什么通过查找OSUnMapTbl[]中的数据,便能间接得到当前就绪态的任务中的最高优先级呢?
首先,来看看OSRdyGrp和OSRdyTbl[]。
ptcb->OSTCBY = (INT8U)(prio >> 3) ;//=1 /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);//=2 第1位置一;
ptcb->OSTCBX = (INT8U)(prio & 0x07);// = 0b110=6
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);// =64 第六位置1
OSRdyGrp |= ptcb->OSTCBBitY; //=2 ;OSRdyGrp第1位置一。
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; //OSRdyTbl[1]=64的第6位置1
取 static void OS_SchedNew (void)函数
INT8U y;
y = OSUnMapTbl[OSRdyGrp]; // = OSUnMapTbl[2]=1
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
// OSPrioHighRdy = 1 << 3 + OSUnMapTbl[OSRdyTbl[1]]
// OSPrioHighRdy = 1 << 3 + OSUnMapTbl[64] //而查表OSUnMapTbl[64] = 6
//OSPrioHighRdy = 1 << 3 + 6=0b1000+0b0110=0b1110=14
/////////////////////////
如果还有一个13优先级的0b1 101
存
ptcb->OSTCBY = (INT8U)(prio >> 3) ;//=1 /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);//=2 第1位置一;
ptcb->OSTCBX = (INT8U)(prio & 0x07);// = 0b101=5
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);// =32 第5位置1
OSRdyGrp |= ptcb->OSTCBBitY; //=2 ;OSRdyGrp第1位置一。依旧是这个位置一
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; //OSRdyTbl[1]=64+32的第6位置1,而且第5位置1;96=0b1100000
取:
y = OSUnMapTbl[OSRdyGrp]; // = OSUnMapTbl[2]=1
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
// OSPrioHighRdy = 1 << 3 + OSUnMapTbl[OSRdyTbl[96]]
// OSPrioHighRdy = 1 << 3 + OSUnMapTbl[96] //而查表OSUnMapTbl[64] = 6
//OSPrioHighRdy = 1 << 3 + 5=0b1000+0b0101=0b1101=13
也就是 OSRdyTbl[ 1 ] 中的值是优先级3,4,5位为0b1即(0b1xxx)这一些优先级的每个优先级的第0,1,2位的值 (ptcb->OSTCBX)
经过1 << ptcb->OSTCBX (ptcb->OSTCBBitX )相加(相与OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX)的累加和。这就是2的八次方为256。也就是为什么 OSUnMapTbl表的个数为256.也就是说OSRdyTbl[96]中的96是1<<6+1<<5.;而OSUnMapTbl[96]把比较低的第5位的5字记录在OSUnMapTbl表中。
由此,我们可以清楚的看出OSUnMapTbl[]表格是如何生成的,反过来也可以发现,该表是为了满足嵌入式系统实时性的特性而使用的,这种通过查表降低运算量提高实时性的思想在做项目的时候可以进行借鉴