查看: 2038|回复: 0

【连载】嵌入式OS入门笔记-以RTX为案例(四):初探进程

[复制链接]
  • TA的每日心情
    慵懒
    2014-8-14 15:38
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-8-16 01:41:58 | 显示全部楼层 |阅读模式
    分享到:
    进程是一个运行中的程序。在RTX中,一个task就是一个进程。
            1.理论
                进程,英文称呼很多Process, Task等等,一般通用操作系统称Process的比较多,各种称呼涵义稍微有不一样。一般而言,进程是对一个运行单元的抽象,主要包括内存(code,data,heap和stack),CPU状态(PC,SP和寄存器值等)与其他OS管理相关的内容。进程是一个运行中的程序。在RTX中,一个task就是一个进程。

                一般我们有一个进程控制块(Process control block,PCB),用于记录进程的相关信息。在RTX上,这个控制块叫做task control block(TCB),是一个结构体,其中的成员记录了关于该task的信息,其定义在rt_TypeDef.h中:

            [cpp][/cpp]
            view plaincopyprint?
             
    • typedef struct OS_TCB {       
    • /* General part: identical for all implementations. */       
    • U8 cb_type; /* Control Block Type */       
    • U8 state; /* Task state */       
    • U8 prio; /* Execution priority */       
    • U8 task_id; /* Task ID value for optimized TCB access */       
    • struct OS_TCB *p_lnk; /* Link pointer for ready/sem. wait list */       
    • struct OS_TCB *p_rlnk; /* Link pointer for sem./mbx lst backwards */       
    • struct OS_TCB *p_dlnk; /* Link pointer for delay list */       
    • struct OS_TCB *p_blnk; /* Link pointer for delay list backwards */       
    • U16 delta_time; /* Time until time out */       
    • U16 interval_time; /* Time interval for periodic waits */       
    • U16 events; /* Event flags */       
    • U16 waits; /* Wait flags */       
    • void **msg; /* Direct message passing when task waits */       
    • struct OS_MUCB *p_mlnk; /* Link pointer for mutex owner list */       
    • U8 prio_base; /* Base priority */       
    • U8 ret_val; /* Return value upon completion of a wait */       
    • /* Hardware dependant part: specific for CM processor */       
    • U8 ret_upd; /* Updated return value */       
    • U16 priv_stack; /* Private stack size, 0= system assigned */       
    • U32 tsk_stack; /* Current task Stack pointer (R13) */       
    • U32 *stack; /* Pointer to Task Stack memory block */       
    • /* Task entry point used for uVision debugger */       
    • FUNCP ptask; /* Task entry address */       
    • } *P_TCB;
    typedef struct OS_TCB {/* General part: identical for all implementations.                        */U8     cb_type;                 /* Control Block Type                      */U8     state;                   /* Task state                              */U8     prio;                    /* Execution priority                      */U8     task_id;                 /* Task ID value for optimized TCB access  */struct OS_TCB *p_lnk;           /* Link pointer for ready/sem. wait list   */struct OS_TCB *p_rlnk;          /* Link pointer for sem./mbx lst backwards */struct OS_TCB *p_dlnk;          /* Link pointer for delay list             */struct OS_TCB *p_blnk;          /* Link pointer for delay list backwards   */U16    delta_time;              /* Time until time out                     */U16    interval_time;           /* Time interval for periodic waits        */U16    events;                  /* Event flags                             */U16    waits;                   /* Wait flags                              */void   **msg;                   /* Direct message passing when task waits  */struct OS_MUCB *p_mlnk;         /* Link pointer for mutex owner list       */U8     prio_base;               /* Base priority                           */U8     ret_val;                 /* Return value upon completion of a wait  ** Hardware dependant part: specific for CM processor                      */U8     ret_upd;                 /* Updated return value                    */U16    priv_stack;              /* Private stack size, 0= system assigned  */U32    tsk_stack;               /* Current task Stack pointer (R13)        */U32    *stack;                  /* Pointer to Task Stack memory block      ** Task entry point used for uVision debugger                              */FUNCP  ptask;                   /* Task entry address                      */} *P_TCB;
            还是比较一目了然。
            一个进程会有它自己的周期,会处在不同的进程状态(state,见上面的state成员),不同的状态有不同的意味,不同的状态间可以相互转换。
            在RTX中,task的状态是在rt_Task.h中定义的,一共有10种:
            [cpp][/cpp]
            view plaincopyprint?
             
    • /* Values for 'state' */       
    • #define INACTIVE 0       
    • #define READY 1       
    • #define RUNNING 2       
    • #define WAIT_DLY 3       
    • #define WAIT_ITV 4       
    • #define WAIT_OR 5       
    • #define WAIT_AND 6       
    • #define WAIT_SEM 7       
    • #define WAIT_MBX 8       
    • #define WAIT_MUT 9
            /* Values for 'state'   */

            #define INACTIVE        0

            #define READY           1

            #define RUNNING         2

            #define WAIT_DLY        3

            #define WAIT_ITV        4

            #define WAIT_OR         5

            #define WAIT_AND        6

            #define WAIT_SEM        7

            #define WAIT_MBX        8

            #define WAIT_MUT        9

                简单说来,可以分为4大类,inactive(进程被清理),ready(就绪),running(执行)和waiting(等待)。状态3至9都可以归为等待状态,区别在于他们等待的东西不同,从等待状态触发到就绪状态的条件不同。

                进程的创建和消灭都是主要都牵涉到内存分配,排程器的安排,TCB的处理等等,需要具体的OS具体的分析,我们这里贴一下RTX进程创建的源代码:

            [cpp][/cpp]
            view plaincopyprint?
             
    • OS_TID rt_tsk_create (FUNCP task, U32 prio_stksz, void *stk, void *argv) {       
    • /* Start a new task declared with "task". */       
    • P_TCB task_context;       
    • U32 i;       
    • /* Priority 0 is reserved for idle task! */       
    • if ((prio_stksz & 0xFF) == 0) {       
    • prio_stksz += 1;       
    • }       
    • task_context = rt_alloc_box (mp_tcb);       
    • if (task_context == NULL) {       
    • return (0);       
    • }       
    • /* If "size != 0" use a private user provided stack. */       
    • task_context->stack = stk;       
    • task_context->priv_stack = prio_stksz >> 8;       
    • /* Pass parameter 'argv' to 'rt_init_context' */       
    • task_context->msg = argv;       
    • /* For 'size == 0' system allocates the user stack from the memory pool. */       
    • rt_init_context (task_context, prio_stksz & 0xFF, task);       
    • /* Find a free entry in 'os_active_TCB' table. */       
    • i = rt_get_TID ();       
    • os_active_TCB[i-1] = task_context;       
    • task_context->task_id = i;       
    • DBG_TASK_NOTIFY(task_context, __TRUE);       
    • rt_dispatch (task_context);       
    • os_tsk.run->ret_val = i;       
    • return ((OS_TID)i);       
    • }
    OS_TID rt_tsk_create (FUNCP task, U32 prio_stksz, void *stk, void *argv) {/* Start a new task declared with "task". */P_TCB task_context;U32 i;/* Priority 0 is reserved for idle task! */if ((prio_stksz & 0xFF) == 0) {prio_stksz += 1;}task_context = rt_alloc_box (mp_tcb);if (task_context == NULL) {return (0);}/* If "size != 0" use a private user provided stack. */task_context->stack      = stk;task_context->priv_stack = prio_stksz >> 8;/* Pass parameter 'argv' to 'rt_init_context' */task_context->msg = argv;/* For 'size == 0' system allocates the user stack from the memory pool. */rt_init_context (task_context, prio_stksz & 0xFF, task);/* Find a free entry in 'os_active_TCB' table. */i = rt_get_TID ();os_active_TCB[i-1] = task_context;task_context->task_id = i;DBG_TASK_NOTIFY(task_context, __TRUE);rt_dispatch (task_context);os_tsk.run->ret_val = i;return ((OS_TID)i);}
            基本就是填TCB,分配内存空间,确定优先级和排程相关设置,这里就不深入分析。消灭进程的源代码也是类似的。
            2.进程相关的基本操作
            之前讲到,进程在RTX里的基本形式是:
            [cpp][/cpp]
            view plaincopyprint?
             
    • __task void task(void){       
    • for(;;){       
    • //...       
    • }       
    • }
             

    OS_TID taskID1;OS_TID taskID2;__task void init (void) {    //Necessary Initialization    //...    //Create a task    taskID1 = os_tsk_create(task1, 0);    taskID2 = os_tsk_create(task2, 0);        os_tsk_delete_self (); // Delete the init(self) task}int main(void){    //Necessary Initialization    //...        os_sys_init(init);}

                进程相关操作就是RTX提供的围绕这样一个task的一些基本操作,例如创建,消灭等等。

                从应用角度来说,了解以下进程基本操作就足够了:

            1.创建

            最主要的是这个:

            os_tsk_create(task_name,priority);

            把函数名填入,和进程的优先度,优先度后面的笔记会介绍。

            如果留心看源代码,其实源代码的create操作要求一共4个参数(FUNCP task, U32 prio_stksz, void *stk, void *argv)。我们最基本的这个创建函数并没有接受后两个参数。如果实在有需要,有以下另外三个相关的操作:

            os_tsk_create_ex(task_name,priority,para);

            这个是用于传递一个初始参数para给相关进程的。例如你有一个LED_On的进程,而你有4个LED,你只有在创建进程时才能决定,你点亮的是哪个LED,那么就可以用这个操作,通过传递参数来决定具体要亮哪个LED。

            os_tsk_create_user(task_name,priority,&stack,sizeof(stack));

            这个是用来给进程创建自定义stack的。需要传递stack的地址和大小。

            os_tsk_create_user_ex(task_name,priority,&stack,sizeof(stack),para);

            这个明显就是上面两个的结合。

            以上这些创建操作,返回类型都是OS_TID,进程ID,实际值从0到255。 所以可以先声明一个该类型的值,然后创建进程时让其返回该值。

            2.消灭

            os_tsk_delete(taskID);

            填入你要消灭的进程的进程ID,TID。

            如果要消灭进程本身,用:

            os_tsk_delete_self();

            注意,RTX的消灭进程并不清理互斥锁或者信号灯的占有的。所以在消灭一个进程前,确定进程释放了所有资源。内存资源会被这两个操作释放,所以不用担心。

            3.杂项

            如果想要知道当前进程的ID,使用以下操作:

            os_get_TID();

            还有一个非常重要的:

            os_sys_init(first_task);

            这个操作初始化整个RTX,如果不在main中执行这一操作,一切都是空谈。该操作会创建第一个进程,也就是first_task。

            一般而言,进程可以创造别的进程,也可以消灭别的进程。但进程只能够消灭本身,而不能创造本身。所以就需要有一个操作去创建第一个进程,然后别的进程可由这个第一个进程去创造。

            3.一个完整的例子

            一下是一个从初始化,到创建第一个进程,到第一个进程创建别的进程,最后消灭自己的一个例子:

            [cpp][/cpp]
            view plaincopyprint?

             
    • OS_TID taskID1;       
    • OS_TID taskID2;       
    • __task void init (void) {       
    • //Necessary Initialization       
    • //...       
    • //Create a task       
    • taskID1 = os_tsk_create(task1, 0);       
    • taskID2 = os_tsk_create(task2, 0);       
    • os_tsk_delete_self (); // Delete the init(self) task       
    • }       
    • int main(void)       
    • {       
    • //Necessary Initialization       
    • //...       
    • os_sys_init(init);       
    • }
    OS_TID taskID1;OS_TID taskID2;__task void init (void) {    //Necessary Initialization    //...    //Create a task    taskID1 = os_tsk_create(task1, 0);    taskID2 = os_tsk_create(task2, 0);        os_tsk_delete_self (); // Delete the init(self) task}int main(void){    //Necessary Initialization    //...        os_sys_init(init);}
                这个简单的例子足够应付最基本使用RTX的需求了。

            关于RTX的排程,优先度,内存分配和一些OS原语,在后面的笔记会记录。
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 01:02 , Processed in 0.137247 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.