建立任务,OSTaskCreate()源码解析

建立任务,OSTaskCreate()源码解析想让uC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:OSTaskCreate()或OSTaskCreateExt()。OSTas

大家好,又见面了,我是你们的朋友全栈君。

想让uC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:OSTaskCreate() 或 OSTaskCreateExt()。OSTaskCreate()与uC/OS是向下兼容的,OSTaskCreateExt()是OSTaskCreate()的扩展版本,提供了一些附加的功能。用两个函数中的任何一个都可以建立任务。

   任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中被建立。在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。任务不能由中断服务程序(ISR)来建立。

OSTaskCreate()的代码如程序清单 L4.1所述。从中可以知道,OSTaskCreate()需要四个参数:

task是任务代码的指针,

pdata是当任务开始执行时传递给任务的参数的指针,

ptos是分配给任务的堆栈的栈顶指针(参看4.02,任务堆栈),

prio是分配给任务的优先级。

OSTaskCreate函数源码

  1. //建立一个新任务

  2. #if OS_TASK_CREATE_EN > 0 //允许生成OSTaskCreate()函数

  3. INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)

  4. {

  5. #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3

  6. OS_CPU_SR cpu_sr;

  7. #endif

  8. OS_STK *psp;
    //初始化任务堆栈指针变量,返回新的栈顶指针

  9. INT8U err;
    //定义(获得并定义初始化任务控制块)是否成功

  10.  
  11.  
  12. #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内

  13. if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法

  14. return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO

  15. }

  16. #endif

  17. OS_ENTER_CRITICAL();
    //关闭中断

  18. if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0

  19. OSTCBPrioTbl[prio] = (OS_TCB *)
    1; //保留这个优先级,将就绪态设为1

  20.  
  21. OS_EXIT_CRITICAL();
    //打开中断

  22. psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos,
    0); //初始化任务堆栈

  23. err = OS_TCBInit(prio, psp, (OS_STK *)
    0, 0, 0, (void *)0, 0); //获得并初始化任务控制块

  24. if (err == OS_NO_ERR) { //任务控制初始化成功

  25. OS_ENTER_CRITICAL();
    //关闭中断

  26. OSTaskCtr++;
    //任务计数器加1

  27. OS_EXIT_CRITICAL();
    //打开中断

  28. if (OSRunning == TRUE) { //检查是否有(某个)任务在运行

  29. OS_Sched();
    //任务调度,最高任务优先级运行

  30. }

  31. }
    else { //否则,任务初始化失败

  32. OS_ENTER_CRITICAL();
    //关闭中断

  33. OSTCBPrioTbl[prio] = (OS_TCB *)
    0; //放弃任务,设此任务就绪态为0

  34. OS_EXIT_CRITICAL();
    //打开中断

  35. }

  36. return (err); //返回(获得并定义初始化任务控制块是否成功)

  37. }

  38. OS_EXIT_CRITICAL();
    //打开中断

  39. return (OS_PRIO_EXIST); //返回(具有该优先级的任务已经存在)

  40. }

  41. #endif

OSTaskCreate函数源码解析

    OSTaskCreate()一开始先检测分配给任务的优先级是否有效[L4.1(1)]。任务的优先级必须在0到OS_LOWEST_PRIO之间。接着,OSTaskCreate()要确保在规定的优先级上还没有建立任务[L4.1(2)]。在使用UC/OS-Ⅱ时,每个任务都有特定的优先级。如果某个优先级是空闲的,UC/OS-Ⅱ通过放置一个非空指针在OSTCBPrioTbl[]中来保留该优先级[L4.1(3)]。这就使得OSTaskCreate()在设置任务数据结构的其他部分时能重新允许中断[L4.1(4)]。 

然后,OSTaskCreate()调用OSTaskStkInit()[L4.1(5)],它负责建立任务的堆栈。该函数是与处理器的硬件体系相关的函数,可以在OS_CPU_C.C文件中找到。有关实现OSTaskStkInit()的细节可参看第8章——移植UC/OS-Ⅱ。如果已经有人在你用的处理器上成功地移植了UC/OS-Ⅱ,而你又得到了他的代码,就不必考虑该函数的实现细节了。OSTaskStkInit()函数返回新的堆栈栈顶(psp),并被保存在任务的0S_TCB中。注意用户得将传递给OSTaskStkInit()函数的第四个参数opt置0,因为OSTaskCreate()与OSTaskCreateExt()不同,它不支持用户为任务的创建过程设置不同的选项,所以没有任何选项可以通过opt参数传递给OSTaskStkInit()。

UC/OS-Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增。用户在调用OSTaskCreate()的时候必须知道堆栈是递增的还是递减的(参看所用处理器的OS_CPU.H中的OS_STACK_GROWTH),因为用户必须得把堆栈的栈顶传递给OSTaskCreate(),而栈顶可能是堆栈的最高地址(堆栈从上往下递减),也可能是最低地址(堆栈从下往上长)。

一旦OSTaskStkInit()函数完成了建立堆栈的任务,OSTaskCreate()就调用OSTCBInit()[L4.1(6)],从空闲的OS_TCB池中获得并初始化一个OS_TCB。OSTCBInit()的代码如程序清单 L4.2所示,它存在于0S_CORE.C文件中而不是OS_TASK.C文件中。

OSTCBInit()函数首先从OS_TCB缓冲池中获得一个OS_TCB[L4.2(1)],如果OS_TCB池中有空闲的OS_TCB[L4.2(2)],它就被初始化[L4.2(3)]。注意一旦OS_TCB被分配,该任务的创建者就已经完全拥有它了,即使这时内核又创建了其它的任务,这些新任务也不可能对已分配的OS_TCB作任何操作,所以OSTCBInit()在这时就可以允许中断,并继续初始化OS_TCB的数据单元。

OSTaskCreateExt函数源码

 

  1. //建立一个新任务。与OSTaskCreate()不同的是,OSTaskCreateExt()允许用户设置更多的细节

  2. //内容。任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立,但中断处理

  3. //程序中不能建立新任务。一个任务必须为无限循环结构,且不能有返回点。

  4. #if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数

  5. INT8U OSTaskCreateExt (void (*task)(void *pd), //建立扩展任务(任务代码指针)

  6. void *pdata, //传递参数指针

  7. OS_STK *ptos,
    //分配任务堆栈栈顶指针

  8. INT8U prio,
    //分配任务优先级

  9. INT16U id,
    //(未来的)优先级标识(与优先级相同)

  10. OS_STK *pbos,
    //分配任务堆栈栈底指针

  11. INT32U stk_size,
    //指定堆栈的容量(检验用)

  12. void *pext, //指向用户附加的数据域的指针

  13. INT16U opt)
    //建立任务设定选项

  14. {

  15. #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3

  16. OS_CPU_SR cpu_sr;

  17. #endif

  18. OS_STK *psp;
    //初始化任务堆栈指针变量,返回新的栈顶指针

  19. INT8U err;
    //定义(获得定义初始化任务控制块)是否成功

  20.  
  21.  
  22. #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内

  23. if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法

  24. return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO

  25. }

  26. #endif

  27. OS_ENTER_CRITICAL();
    //关闭中断

  28. if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0

  29. OSTCBPrioTbl[prio] = (OS_TCB *)
    1; //保留这个优先级,将就绪态设为0

  30.  
  31. OS_EXIT_CRITICAL();
    //打开中断

  32.  
  33. //以下两为1堆栈才能清0

  34. if (((opt & OS_TASK_OPT_STK_CHK) != 0x0000) || //检验任务堆栈,CHK=1

  35. ((opt & OS_TASK_OPT_STK_CLR) !=
    0x0000)) { //任务建立时是否清0,CLR=1

  36. #if OS_STK_GROWTH == 1 //堆栈生长方向

  37. (
    void)memset(pbos, 0, stk_size * sizeof(OS_STK)); //从下向上递增

  38. #else

  39. (
    void)memset(ptos, 0, stk_size * sizeof(OS_STK)); //从下向下递减

  40. #endif

  41. }

  42.  
  43. psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, opt);
    //初始化任务堆栈

  44. err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt);
    //获得并初始化任务控制块

  45. if (err == OS_NO_ERR) { //任务控制初始化成功

  46. OS_ENTER_CRITICAL();
    //关闭中断

  47. OSTaskCtr++;
    //任务计数器加1

  48. OS_EXIT_CRITICAL();
    //打开中断

  49. if (OSRunning == TRUE) { //检查是否有(某个)任务在运行

  50. OS_Sched();
    //任务调度,最高任务优先级运行

  51. }

  52. }
    else { //否则,任务初始化失败

  53. OS_ENTER_CRITICAL();
    //关闭中断

  54. OSTCBPrioTbl[prio] = (OS_TCB *)
    0; //放弃任务,设此任务就绪态为0

  55. OS_EXIT_CRITICAL();
    //打开中断

  56. }

  57. return (err); //返回(获得并定义初始化任务控制块是否成功)

  58. }

  59. OS_EXIT_CRITICAL();
    //打开中断

  60. return (OS_PRIO_EXIST); //具有该优先级的任务已经存在

  61. }

  62. #endif


http://blog.csdn.net/liuhui_8989/article/details/8781407

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/155645.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • arm cortex-a57 cpu_处理器a73和a53

    arm cortex-a57 cpu_处理器a73和a53在如今这个电子产品泛滥的年代,仅仅靠品牌或是外观已经不足以辨别产品的优劣,其内置的处理器自然也就成为了分辨产品是否高端的标准之一。那么我们今天就不妨好好了解一下近几年来电子产品中较为主流的RAM处理器。  在这之前让我们先简单认识一下处理器的架构。所谓处理器架构是CPU厂商给属于同一系列的CPU产品定的一个规范,主要目的是为了区分不同类型CPU的重要标示。目前市面上的CPU指令集分类主要分有…

  • Android ListView几种Adapter用法简介「建议收藏」

    Android ListView几种Adapter用法简介「建议收藏」ArrayAdapter适合非常简单的数据显示,很方便,很简单。SimpleAdapter可以自定义Item布局,用于显示交简单的布局及控件,但布局内的控件如按钮等无法获取到焦点,当然也就无法获取到他们的点击事件。SimpleCursorAdapter与SimpleAdapter相似,只是他的数据源是Cursor类型而已。BaseAdpter子类最常用的ListView数据适配器,通过继承BaseAdpter可以较灵活的实现数据的绑定,同时通过使用View

  • 徜徉在宋词里的女子

    徜徉在宋词里的女子

  • C#导入Excel数据的方式(两种)

    C#导入Excel数据的方式(两种)方式一、导入数据到数据集对象,只支持Excel的标准格式,即不能合并单元格等等///<summary>///导入数据到数据集中///备注:此种方法只支持excel原文件///

  • java的serializable接口_javacloneable接口

    java的serializable接口_javacloneable接口Cloneable接口clone:它允许在堆中克隆出一块和原对象一样的对象,并将这个对象的地址赋予新的引用。Java中一个类要实现clone功能必须实现Cloneable接口,否则在调用clone()时会报CloneNotSupportedException异常。Java中所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clon

    2022年10月14日
  • python控制windows窗口,并输入数据_python执行windows命令

    python控制windows窗口,并输入数据_python执行windows命令这是一些用于设置多播接收器的Python代码.它在mac和linux上运行良好.importsocket,structADDR=’239.239.250.1’PORT=8001sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)s…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号