【解析新特性】300W单路输出工业电源>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » 更新-任务五:互斥体。FDZ组的进程贴

共22条 1/3 1 2 3 跳转至

更新-任务五:互斥体。FDZ组的进程贴

菜鸟
2013-07-12 21:17:30    评分

实验一分析:http://forum.eepw.com.cn/thread/234186/1#4 (个人认为实验1很重要,有关任务的基础知识)

实验二分析:http://forum.eepw.com.cn/thread/234186/1#8 (信号量)

实验三分析:http://forum.eepw.com.cn/thread/234186/2#13 (事件标志)

实验四分析:http://forum.eepw.com.cn/thread/234186/2#15 (邮箱)

实验五分析:http://forum.eepw.com.cn/thread/234186/2#17 (互斥体)

资料分享:

实验教程:uTenux_Kernel_BasisExercise.pdf

uTenux内核规范:uTenux_Kernel_Spec.pdf

T-Kernel详细说明(英文版):T-Kernel内核规范英文版.pdf

很多实验我没有贴代码,建议还是自己看,都很容易理解。

板子就不晒了,懒得拍照了。悠龙提供的资料很全面。不太会论坛发帖。。这个帖子主要介绍我对uTenux的一个初步的认识。


以下为我的学习进程。


对uTenux的初步认识


uTenux是一个嵌入式操作系统。uTenuxT-engine+linux缩写,内核采用uT/Kernel。中间件选用Linux的开源中间件。

关于内核:uT/Kernel 是面向小规模嵌入式系统的实时操作系统内核,它的目标系统是假设为32 位单芯片的微控制器,带有有限的ROM/RAM,或者没有MMU 的系统等。因此,这个规范允许开发人员在小规模嵌入式系统上容易的进行优化和裁减。(摘自μT/Kernel内核规范)

uTenux提供的系统服务:API总共131个。系统提供的api函数名称均为       *_*_*。系统状态管理函数没看出什么规律,调试支持的API在开头(第一个*)处均为td。其余API的关键字出现在结尾(第三个*),关键字如下图。其中括号内第二个参数为此类函数API的个数。这张图是我自己画的,方便自己学习。









关键词: 更新     任务     互斥     进程    

菜鸟
2013-07-12 21:20:08    评分
2楼

接下来主要介绍今天自己学习的一些术语,供以后学习的参考。


SVC: 服务调用(SerVice Call)的缩写,包括以下两种:

 System Call: 也称内核服务调用(Kernel Service Call )或者系统调用(System Call),由内核提供;

        extended SVC:扩展服务调用由内核或者软件部件提供。

 

Object ID Numbers:对象标识号,每个对象都有一个唯一的ID

        User Objects:用户对象的ID是正号,从1开始;

System Objects:系统对象的ID负号。

 

Priorities:优先级表示任务处理的顺序,一般是从1开始的整数,数越小代表越高的优先级,默认是32个优先级,最多可配置255个优先级。

 

Function Codes:功能号,每个SVC都有一个唯一的功能号,用在中

断中调用SVC的时候,正号标示内核和软件部件中的SVC,负号表示扩

SVC

 

Return Values:返回值,SVC运行结束时通过返回值将运行状态返

回,E_OK(0)或者正数表示正常返回,负数表示出错。

 

Timeout:超时,SVC在指定的超时过后,自动退出,而且Task不进

wait状态。

 

Relative TimeSystem Time:相对时间和系统时间。



菜鸟
2013-07-12 21:26:48    评分
3楼

这一楼介绍关于任务状态的重要概念,建议图文一起观看。


non_existent:未登录状态。

        没有作为任务注册到系统中,或被删除后的状态。也就是说虽然已经装配到内存中,但没有接受OS管理的任务。

dormant:静止状态。

        任务创建时的状态(tk_cre_tsk系统调用时)或者是运行终了时的状态。处于静止状态的任务,不会被调度。

Ready:就绪状态。

        成为内核调度器管理的状态,具备除了CPU之外的所有必要资源,由于有更高优先级别(或者相同任务优先级别)的任务正在运行,因此处在等待运行权到达的状态,就是说,只要运行权到达,马上就能迁移到运行状态的状态。

Run:运行状态。

        得到了CPU的控制权,正在处于运行处理中的状态。系统中处于运行状态的任务同时只能有一个(单CPU的情况下)。

Wait:等待状态。

        由于缺少运行的必要条件,不能进入到运行状态的状态,就是说正在等待必要运行条件满足的状态。

从等待状态的重新执行是从进入到等待状态时中断的场所开始执行,就是说运行程序时必要的各种内部环境(寄存器、堆栈等)会复原。

Suspend:挂起状态

       被其他任务通知中断执行(tk_sus_tsk调用的发行)的状态,还可以通过多重执行tk_sus_tsk调用,使挂起状态嵌套。 挂起状态的解除是通过执行tk_rsm_tsk系统调用来进行的,如果要执行依次tk_rsm_tsk系统调用来解除被嵌套的挂起状态,必须使用参数T_FRCPSM(0X1)。

     从挂起状态重新实行是指从为进入挂起状态处理中断的位置开始,就是说运行程序时必要的各种内部环境(寄存器、堆栈等)会复原。

Wait_suspend:等待挂起状态

    由上面等待状态和挂起状态合成的状态,就是对应等待状态执行了

tk_sus_tsk调用的场合迁移到的场合。

    等待挂起状态是当挂起状态被解除时,就迁移到等待状态,而等待状态被解除时,就迁移到挂起状态。

接下来是任务各种状态的关系图:

还有这张表格:



菜鸟
2013-07-14 21:32:59    评分
4楼

实验一     2013713

按照实验步骤,一步一步的来。程序运行正常。

接下来开始分析代码。

main函数在usermain.c中,在usermain.c中有一个全局变量initctsk,其具体的声明方式为

static        T_CTSK     initcstk

其中T_CTSK为一个结构体,其具体的定义为:

typedef struct t_ctsk {

         void  *               exinf;                   /* Extended information,32bit */

         unsigned long          tskatr;                  /* Task attribute,32bit */

         void                  (*task)();                    /* Task startup address */

         signed int              itskpri;                 /* Priority at task startup */

         signed long            stksz;                   /* User stack size (byte) */

         unsigned char            dsname[8];               /* Object name */

         void *                  bufptr;                  /* User buffer */

} T_CTSK;

主函数代码如下:

EXPORT INT main( void )

{

         /* Initialize bsp sequence */

    bsp_init();//

        

         /* Start uT/Kernel and Never return*/

         initctsk.exinf   = NULL;

         initctsk.tskatr  = TA_HLNG | TA_RNG0 | TA_DSNAME;

         initctsk.task    = (FP)&inittask;

         initctsk.itskpri = (MAX_PRI-2);

         initctsk.stksz   = 512;

         strcpy(initctsk.dsname, "inittsk");

         initctsk.bufptr  = NULL;

         tk_sta_sys((T_CTSK *)&initctsk);

 

         return 0;

}

bsp_init()的具体实现先不管。在它之后的代码中,是对initctsk结构体的各项数据初始化数据,其中initctsk.task = (FP)&inittask对任务函数的地址进行赋值。然后通过tk_sta_sys()函数启动内核。

然后观察inittask函数,

EXPORT void inittask(W stacd,VP exinf)

{

         usermain();

         tk_ext_sys();

}

tk_ext_sys()为系统管理状态管理函数中的退出内核的系统函数。

接下来关注usermain. C函数:

EXPORT    INT   usermain( void )

{

         ER ercd;

 

    ercd=TaskSample();

    tm_putstring((UB*)"Push any key to shutdown the micro Tenux.\n");

    tm_getchar(-1);

 

    return 0;

}

Usermain中调用了TaskSample()函数,TaskSample函数在文件taskSample中,再去看看tasksample函数,此函数分别通过tk_cre-tsk建立了三个任务,这三个任务的ID分别作为静态变量存在于文件TaskSample.c中。三个任务的属性分别为:TA_HLNG|TA_RNG0,通过查询内核规范得知,TA_HLNG:表示任务由高级语言编写。TA_RNG0:任务运行在保护级别0.

三个任务建立完成后,通过tk_sta_tsk()函数启动了任务B。结合这张图来理解程序


在试验程序中,一共有四个任务,分别为inittasktaskSampleAtaskSampleBtaskSampleC

main函数中,完成了对inittask的初始化并运行。

而其他三个任务的初始化分别在taskSample函数中。四个任务的优先级顺序为TaskA,TaskB,TaskC(以下简称A,B,C),inittask。

TaskSample函数完成了对任务A,B,C的初始化以及建立这三个任务。此时三个任务都处于dormant状态,当tk_sta_tsk(TaskID_B,5)函数执行后,B任务由DORMANT状态进入READY状态,再进一步进入RUNNING状态,

观察任务B的代码,任务B先启动了任务C,但是由于任务C的优先级不如任务B,任务C也只是从DORMANT进入了READY的状态。

之后任务B中开始了任务A,由于任务A的优先级是高于任务B的,所以任务B退出running,进入ready,任务Adormant进入ready,再进入running

在任务A中输出了一条A要睡觉的信息后,就通过tk_slp_tsk(1000)进入了wait,此时任务BC均处于ready状态,但是由于B的优先级高于C,所以开始继续运行B任务,此时B任务进入了running,直至运行至getch()函数,等待用户的输入,输入回车,任务B继续运行,输出一条要睡觉的信息后,进入了wait状态,而此时任务A和任务B均处于wait状态,只有优先级最低的任务C处于READY状态,所以任务C由此而运行。

此时,我已经大致了解了任务直接从建立到运行各个状态的转换。

如果在任务B中输入字符e,

 

如果在任务B中输入字符e,任务B通过tk_ter_tsk()函数执行termin  ate操作,将处于readywait状态的任务AB分别退出原来的状态,进入了dormant状态,之后再通过tk_del_tsk()函数,将任务A和任务B分别进入了NON-EXISTENT状态,也就是删除了任务。之后再通过tk_exd_tsk()函数,直接从running状态进入了NON-EXISTENT状态。

至此我已大致认识了不同任务之间的切换和,任务的建立以及任务的删除的相关基本操作。



以上是我结合悠龙提供的内核规范、讲义、实验教程分析的这个程序,不足和错误的地方请多多指教。


专家
2013-07-15 14:55:53    评分
5楼
先回复 然后再仔细看

专家
2013-07-15 14:59:29    评分
6楼
楼主 任务进入睡觉模式后 是把自身给删除了吗?还是仅仅去睡觉然后一直等待唤醒啊~~

菜鸟
2013-07-15 20:45:22    评分
7楼

我之前说的睡觉,只是事例代码中串口打印的信息,并且任务是通过tk_slp_tsk函数进入了wait状态。

在内核规范中,并没有睡觉这个状态,你应该说的是wait状态。wait状态是不会删除自身的。

tk_wup_tsk函数可以唤醒通过tk_slp_tsk进入wait状态的函数。

以下是内核规范关于tk_slp_tsk函数的说明。

[C 语言接口]
ER ercd = tk_slp_tsk ( TMO tmout ) ;
[参数]
TMO tmout 时限
[返回参数]
ER ercd 错误编码
[错误编码]
E_OK 正常完成
E_PAR 参数错误(tmout <= - 2)
E_RLWAI 等待状态被强制释放(在等待状态中接收到tk_rel_wai)
E_TMOUT 轮询失败或超时
E_CTX 上下文错误(系统调用发出时处于任务无关部分或禁止分派状态)
[描述]
使调用任务的状态从运行状态变成等待状态(等待tk_wup_tsk)。
如果调用任务在tmout 指定的时间到达之前接收到tk_wup_tsk 调用,则该系统调用正常完成。如果在
tk_wup_tsk 发放前出现超时,则返回错误编码E_TMOUT。
如果设置tmout = TMO_FEVR = (-1),则意味着无限制地等待。这时,任务将保持等待状态,直至
tk_wup_tsk 被发行。
[附加说明]
由于tk_slp_tsk 是一个可使调用任务进入等待状态的系统调用,因此,tk_slp_tsk 不能嵌套。但是,有
可能会有其他任务要为一个通过tk_slp_tsk 使之进入等待状态的任务发行tk_sus_tsk 调用。在这种情况下,
任务进入等待-挂起状态。
对于单纯的任务延迟,应当使用tk_dly_tsk,而不是tk_slp_tsk。通常,任务睡眠函数用于应用中,一
般不被中间件使用。其原因是通过使一个任务在两处或更多地方进入睡眠状态来实现同步会造成混乱,进
而引起误操作。例如,如果应用和中间件都使用睡眠来实现同步,则唤醒请求可能出现在应用中,而中间
件使任务处于睡眠状态。这时,应用或中间件都不可能进行正常工作。由于不能确定等待唤醒来自何处,


菜鸟
2013-07-15 20:55:28    评分
8楼

2013,07,15

今天按照uTenux的内核实验教程。做了一次实验二,实验本身很容易理解,就是关于信号量的使用。

实验步骤在PDF中讲解的很详细。

以下为我个人的学习记录。

按照实验的目的,只需要关注appusermain文件夹中的函数就可以。这里面有三个文件,本次实验所需要关注的部分在SemSample.c中。关于SemSample.c中函数的功能,在实验教程中也讲的很详细了。关于任务的初始化等内容可以参考实验一。

uTenux系统中,提供了5个关于信号量操作的函数。在本实验中也依次出现

tk_cre_sem

tk_del_sem

tk_wai_sem

tk_sig_sem

tk_ref_sem

这五个函数在悠龙提供的内核规范中文版中都可以查到。

 

和实验一不同的是,任务A进入wait状态的函数tk_slp_tsk函数的传入参数为 -1 。为此特地查了一下内核规范,发现-1 参数代表的是永恒睡眠,直至通过tk_wup_tsk函数来唤醒。继续执行tk_slp_tsk后面的函数。



菜鸟
2013-07-15 21:05:00    评分
9楼
怎么才能引用别人的发言啊。。。。我的智商好拙计

菜鸟
2013-07-15 21:05:39    评分
10楼
jobs,如何才能引用你的回复啊。。我的智商好拙计

共22条 1/3 1 2 3 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]