发新话题
打印

关于Itron4.0内核中任务调度,进程通信与cpu分发机制的讨论

关于Itron4.0内核中任务调度,进程通信与cpu分发机制的讨论

今天和冷夜一起讨论了下,下面把qq聊天记录发下,有需要的同学可以看下,
也希望其他学习嵌入式操作系统内核的同学多发些经验心得来和大家一起分享,讨论

田里的雨 19:51:53
好了
冷夜 19:54:00
在kernel.c里,void OSStart(void)
{
ID id;
    //RTOS初始化(TCB,SEM,MBX)//
sysini();
    //启动任务//
for(id=1; id<TSKID_MAX+1; id++)
{
  _ista_tsk(id, DUMMY);   //通过带i的系统调用不激活分发器//
}
    //系统定时器的初始化//
systimini();
    //开始多任务系统//
syssta();   //此函数模拟一次中断,永远不会返回//
}
冷夜 19:55:11
OSStart(void)最后调用了syssta(),可是在kernel.c没有syssta()
田里的雨 19:55:56
这个在汇编文件里
冷夜 19:55:57
但是确有另外一个函数void _syssta(void)
冷夜 19:56:50
对,是在interf.a30里面
田里的雨 19:59:23
昨天你写的那个word里,
            if (++(mbx->msgtail) >= (T_MSG *)(msgq_tbl[mbxid]+msgsizlen_tbl[mbxid]))
            {
                mbx->msgtail = (T_MSG *)msgq_tbl[mbxid];

            }
你说由这个知道邮箱等待链表是循环链表,有问题
冷夜 20:00:59
我今天又看了看,邮件队列的建立和形式我还是没弄明白
田里的雨 20:01:03
这个和上面的那个rcv中的,判断一样,是对刚取走的邮件是邮箱里唯一的邮件的判断,
链表中只有一个邮件时,此时mbx->msgtail=mbx->msghead
田里的雨 20:04:37
rcv_msg时,用++(mbx->msghead)判断时,顺便将头指针后移,来取走邮件,从头上取
snd_msg时,用++(mbx->msgtail)判断时,顺便将尾指针后移,因为队列尾刚增加了一个邮件,在尾上加
冷夜 20:05:22
extern void ** const msgq_tbl[]; //邮箱msg的头指针表//
msgq_tbl[]这个数组里存放的应该是指向指针的指针啊
田里的雨 20:10:37
比如数组的定义a[5]={1,2,3,4,5}
为什么可以得到a[3]呢,他用的其实是*(a+3)得到的,对指针的指针取*,结果不就是指针吗?也就是地址
冷夜 20:13:20
要建立一个有五个int 型数据组成的数组,定义方式为:
int a[5]={1,2,3,4,5}
田里的雨 20:14:00
我明白你说的了。。。。你是说哪个msgq_tbl中的类型是**吧?
冷夜 20:14:40
对了,是数组中存储的内容的类型时**
冷夜 20:15:31
而我最开始的时候是按void * const msgq_tbl[]去理解的
田里的雨 20:16:24
而他里面放的却是邮箱中邮件的头指针
冷夜 20:17:12
对啊
如果是** ,那么++(mbx->msghead) >=(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])中的(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])
就有问题了
田里的雨 20:21:05
他通过(T_MSG *) 将他强制转化了
田里的雨 20:22:20
其实不管他怎么定义的,**里放的还是地址,所以他取的时候没有发生问题
冷夜 20:22:21
是可以,但是觉得没有必要啊  
冷夜 20:22:49
那也就只有这样去理解了
田里的雨 20:23:12
可能是他裁剪内核的时候,没有改这个地方,更完整的版本里也许有用
冷夜 20:24:51
那为什么 在队列中只有一个邮件的时候有: ++(mbx->msghead) >=(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])
那如果多于一个的时候就不成立了吗?
田里的雨 20:27:30
恩,多于一个时,这个判断无法通过,但是++(mbx->msghead)的动作却执行了,所以实现了头指针后移
田里的雨 20:29:09
其实这个用的是数据结构中的队列,一边只能进,一边只能出
冷夜 20:31:06
msgq_tbl[mbxid]是邮箱的头指针,msgsizlen_tbl[mbxid]是邮件的长度(占用的存储空间)
那(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])应该就是第二个邮件的地址吧
田里的雨 20:43:06
msgsizlen_tbl[mbxid]是邮件的长度,这个定义了却没有说明他的功能,按照推断是邮箱中依然存在消息的总长。。。。
我们先假设,这个邮箱里有2个邮件,目前放被取走了第一个(地址为a1),此时来进行这个 ++(mbx->msghead) >=(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])判断的话,首先,msghead指向了第2个邮件的地址了吧(a2),  而msgq_tbl中放的还是a1吧,用他再加上邮件长度(2个消息的),自然无法比他大,于是无法通过。

再看只有1个邮件的时候,目前被取走了唯一的一个(地址a2),此时来进行这个 ++(mbx->msghead) >=(T_MSG *) (msgq_tbl[mbxid]+msgsizlen_tbl[mbxid])判断的话,首先,msghead指向了队列最末端,而msgq_tbl中放的还是a2吧,用他再加上邮件长度(1个消息的),符合等于的条件,于是无法通过。
田里的雨 20:43:32
最后一句改为于是通过
田里的雨 20:45:00
关于msgsizlen_tbl[mbxid]部分的控制应该是被裁掉了。。。各种都没看到有应用,肯定不是单纯的用来定义消息长的,因为这里已经有个wvdCopyArray(ppk_msg,(INT8U *)mbx->msghead,MSG_LEN);中的MSG_LEN来履行这个功能了
冷夜 20:48:40
恩,的确有道理
冷夜 20:49:00
这样的话,的确是通过了
田里的雨 20:49:49
哪天找个完整的内核看看,这个裁的太多,好多东西要猜
冷夜 21:04:32
我刚才把整个的邮箱机制看了一下,
typedef struct t_msg
{
INT8U   SrcTskID;
INT8U    DestTskID;
INT8U  Msg;
union Option_msg  MsgOpt;
}T_MSG;
实际上在消息里面包含了SrcTskID和DestTskID,而这些都没有用到,没有相关的处理
冷夜 21:08:04
还有在interf.a30中出现了对任务切换中的现场的保存,以及对DELAY = SET的利用
田里的雨 21:10:10
我一看汇编就头大。。。。
冷夜 21:12:09
在interf.a30也可以看出中断返回时,如果没有其他的中断而且CPU允许的话,就会通过 JSR.A   _dispatch       来激活分发器,进行新的任务的调度
ret_int:
                LDIPL   #SYS_IPL        ;中断优先级设定为系统优先级
                SUB.W   #1, _INEST      ;中断嵌套次数减1
                JGTU    __ret_int_end   ;如果中断嵌套次数等于0则激活分发器,否则延迟分发
                CMP.W   #0, _DELAY      ;如果DELAY=0则不用任务切换,直接返回
                JZ    __ret_int_end     ;中断嵌返回
                ;中断发生时将FLG,PC压入中断堆栈,我们要将它压入任务堆栈用于恢复任务运行
                PUSH.W  R0              ;R0入栈
                MOV.W   +4[SP], R0      ;将FLG的15~12,PC的16~19,FLG的7~0位写入R0寄存器
                FSET    U               ;使用任务堆栈
                PUSH.W  R0              ;R0值入栈
                FCLR    U               ;恢复中断堆栈
                MOV.W   +2[SP], R0      ;将PC的低16位写入R0寄存器
                FSET    U               ;使用任务堆栈
                PUSH.W  R0              ;R0值入栈
                FCLR    U               ;恢复中断堆栈
                POP.W   R0              ;R0出栈
                ADD.W   #4, SP          ;调整中断堆栈指针值(相当于将FLG,PC出栈)
                FSET    U               ;使用任务堆栈
                PUSHM   R0,R1,R2,R3,A0,A1,SB,FB ;寄存器入栈(任务堆栈)
                STC     SP, _USP        ;任务堆栈指针保存到任务TCB的堆栈指针中
                LDC     #SYS_SP, SP     ;系统堆栈设定为当前的堆栈指针
                JSR.A   _dispatch       ;激活分发器
                LDC     _USP, SP        ;新任务堆栈设定为当前的堆栈指针,USP是新任务堆栈指针的指针
                POPM    R0,R1,R2,R3,A0,A1,SB,FB ;寄存器出栈(新任务堆栈)
__ret_int_end:
                REIT                    ;中断返回,返回到新任务中运行
冷夜 21:13:43
呵呵,我的汇编更不咋样,不过也没有什么,其实无论哪种语言,里面的思想都是一样的,区别只不过在于外表和限制
田里的雨 21:16:26
恩,看到了,按优先级来讲的话,中断>CPU锁定>分发器,他是在那里对cpu锁定进行判断的?
冷夜 21:21:36
#define TSS_TSK         0  //正常状态,任务状态//
#define TSS_DDSP        1  //分发器禁止状态//
#define TSS_LOC         3  //CPU加锁状态//
在CPU加锁状态(TSS_LOC  )下,是不响应中断和高优先级的任务的,而在分发器禁止状态(TSS_DDSP )下是不响应任务,而只响应中断请求
冷夜 21:22:22
所以他的有些关于这两个CPU状态的注释是由问题的
田里的雨 21:30:07
恩,所有中断中的处理函数中都没有激活分发器,就是等中断返回时候,通过JSR.A   _dispatch 来激发的
冷夜 21:33:13
这样任务间切换和中断与任务间的切换机制基本上就解决了
田里的雨 21:34:12
恩,呵呵
冷夜 21:36:18
我同意找个比较完善的内核来读
冷夜 21:36:57
关于itron的资料也很难找
田里的雨 21:37:40
找T-Kernel的,据说去他的网站注册就能得到
冷夜 21:39:15
好,今天就先这样,明天还得上课,都休息休息
田里的雨 21:39:27
恩,那下了,88
冷夜 21:39:33
88

[ 本帖最后由 五尺之图 于 2008-8-18 22:32 编辑 ]

TOP

最近在看LDD3,似乎和这个没有关系...
强哥说,你很胖啊;我说嗯,为明年的经济危机准备的... ...

TOP

强啊。。。。
对嵌入式。。。甚少甚少。

TOP

本来下学期有嵌入式的限选课,可是院里没给开
不抱希望,就不会有失望;
所以,为了不让你们自己失望,请不要对我抱有任何希望……

TOP

发新话题