uc/os-ii源码分析(总体思路一)
首先从main函数开始,下面是uc/os-ii main函数的大致流程:
main()
首先是调用osinit进行初始化,然后使用taskcreate创建几个进程/task,最后调用osstart,操作系统就开始运行了。
osinit
最先看看osinit完成哪些初始化:
void osinit (void)
#if os_version >=204
osinithookbegin();
#endif
os_initmisc();
os_initrdylist();
os_inittcblist();
os_initeventlist();
#if (os_version >=251) &os_flag_en > 0) &os_max_flags > 0)
os_flaginit();
#endif
#if (os_mem_en > 0) &os_max_mem_part > 0)
os_meminit();
#endif
#if (os_q_en > 0) &os_max_qs > 0)
os_qinit();
#endif
os_inittaskidle();
#if os_task_stat_en > 0
os_inittaskstat();
#endif
#if os_version >=204
osinithookend();
#endif
#if os_version >=270 &&os_debug_en > 0
osdebuginit();
#endif
os_initmisc()完成的是一些其其他他的变量的初始化:
osintnesting = 0;
oslocknesting = 0;
ostaskctr = 0;
osrunning = false;
osctxswctr = 0;
osidlectr = 0l;
其中包括:中断嵌套标志osintnesting,调度锁定标志oslocknesting,os标志osrunning等。osrunning在这里设置为false,在后面osstarthighrdy中会被设置为true表示os开始工作。
os_initrdylist()初始化就绪task列表:
static void os_initrdylist (void)
int8u i;
int8u *prdytbl;
osrdygrp = 0x00;
prdytbl = osrdytbl[0];
for (i = 0; i < os_rdy_tbl_size; i++)
prdytbl++ 0x00;
ospriocur = 0;
ospriohighrdy = 0;
ostcbhighrdy = os_tcb *)0;
ostcbcur = os_tcb *)0;
首先将osrdytbl数组中全部初始化0,同时将ospriocur/ostcbcur初始化为0,ospriohighrdy/ostcbhighrdy也初始化为0,这几个变量将在第一个osschedule中被赋予正确的值。
os_inittcblist()这个函数看名称我们就知道是初始化tcb列表。
static void os_inittcblist (void)
int8u i;
os_tcb *ptcb1;
os_tcb *ptcb2;
os_memclr((int8u *)ostcbtbl[0], sizeof(ostcbtbl));
os_memclr((int8u *)ostcbpriotbl[0], sizeof(ostcbpriotbl));
ptcb1 = ostcbtbl[0];
ptcb2 = ostcbtbl[1];
for (i = 0; i < os_max_tasks + os_n_sys_tasks - 1); i++)
ptcb1->ostcbnext = ptcb2;
#if os_task_name_size > 1
ptcb1->ostcbtaskname[0] =
ptcb1->ostcbtaskname[1] =os_ascii_nul;
#endif
ptcb1++;
ptcb2++;
ptcb1->ostcbnext = os_tcb *)0;
#if os_task_name_size > 1
ptcb1->ostcbtaskname[0] =
ptcb1->ostcbtaskname[1] =os_ascii_nul;
#endif
ostcblist = os_tcb *)0;
ostcbfreelist = ostcbtbl[0];
这里完成的工作很简单,首先把整个数组使用ostcbnext指针连接成链表链起来,然后将ostcblist初始化为0,也就是还没有tcb,因为还没有task产生,ostcbfreelist指向ostcbtbl数组的第一个表示所有tcb都处于free状态。
os_initeventlist()初始化event列表。
static void os_initeventlist (void)
#if os_event_en &&os_max_events > 0)
#if (os_max_events > 1)
int16u i;
os_event *pevent1;
os_event *pevent2;
os_memclr((int8u *)oseventtbl[0], sizeof(oseventtbl));
pevent1 = oseventtbl[0];
pevent2 = oseventtbl[1];
for (i = 0; i < os_max_events - 1); i++)
pevent1->oseventtype = os_event_type_unused;
pevent1->oseventptr = pevent2;
#if os_event_name_size > 1
pevent1->oseventname[0] =
pevent1->oseventname[1] =os_ascii_nul;
#endif
pevent1++;
pevent2++;
pevent1->oseventtype = os_event_type_unused;
pevent1->oseventptr = os_event *)0;
#if os_event_name_size > 1
pevent1->oseventname[0] =
pevent1->oseventname[1] =os_ascii_nul;
#endif
oseventfreelist = oseventtbl[0];
#elseoseventfreelist = oseventtbl[0];
oseventfreelist->oseventtype = os_event_type_unused;
oseventfreelist->oseventptr = os_event *)0;
#if os_event_name_size > 1
oseventfreelist->oseventname[0] =
oseventfreelist->oseventname[1] =os_ascii_nul;
#endif
#endif
#endif
同样将eventtbl数组中的oseventtype都初始化为os_event_type_unused。
os_inittaskidle(),中间我们跳过其他的如mem等的初始化,看看idle task的初始化。
void)ostaskcreateext(os_taskidle,void *)0,
ostaskidlestk[os_task_idle_stk_size - 1],os_idle_prio,
os_task_idle_id,ostaskidlestk[0],
os_task_idle_stk_size,void *)0,
os_task_opt_stk_chk | os_task_opt_stk_clr);
其实idle task的初始化很简单就是调用ostaskcrete系列的函数创建一个task, ostaskcreate我们后面再做进一步分析。
初始化state task也是类似调用ostaskcreate系列函数创建stat task。这里只是创建了该task的各个结构还没有真正运行该task,直到osstart中才依据优先级调度运行。
ok,到这里osinit算高一个段落了,我们接着回到main往下看。
uc/os-ii源码分析(总体思路二)
ostaskcreate负责创建task所需的数据结构,该函数原形如下所示:
int8u ostaskcreate (void (*task)(void *pd), void *p_arg, os_stk *ptos, int8u prio)
其中task是一个函数指针,指向该task所开始的函数,当这个task第一次被调度运行时将会从task处开始运行。
p_arg是传给task的参数指针;
ptos是堆栈指针,指向栈顶(堆栈从上往下)或栈底(堆栈从下往上);
prio是进程的优先级,uc/os-ii共支持最大64个优先级,其中最低的两个优先级给idle和stat进程,并且各个task的优先级必须不同。
接下来,我们看看这个函数的执行流程:
#if os_arg_chk_en > 0
if (prio > os_lowest_prio) {
return (os_prio_invalid);
#endif
os_enter_critical();
if (osintnesting > 0) {
os_exit_critical();
ucosII详解
第1章范例1 1.00 安装 c os ii1 1.02 不依赖于编译的数据类型2 1.03 全局变量3 1.04 os enter critical 和 os exit critical5 1.05 基于pc的服务5 1.05.01 字符显示5 1.05.02 花费时间的测量6 1.05.03 其...
软件源码移交保密协议
四 生效条件与协议终止。有关协议一旦签署,立即生效 并将长期有效,除非以下条件之一成立 4.1 双方另有协议,并一致同意废止此协议 4.2 乙方不再使用现行系统 4.3 乙方主动提出终止此协议 4.4 由于乙方过错导致系统源 泄密,甲方有权解除此协议。协议终止时,乙方有责任向甲方提交或立即销毁所持有...
LVDS接口详解
1 lvds输出接口概述。液晶显示器驱动板输出的数字信号中,除了包括rgb数据信号外,还包括行同步 场同步 像素时钟等信号,其中像素时钟信号的最高频率可超过28mhz。采用ttl接口,数据传输速率不高,传输距离较短,且抗电磁干扰 emi 能力也比较差,会对rgb数据造成一定的影响 另外,ttl多路数...