创建任务的函数是系统的基础,系统使用的几乎所有任务都是用这个函数创建的,这不同于linux使用fork函数从权级为0的进程开始创建子进程,基本上是动态的,而μc的任务数据如栈是静态初始化在全局数据段的,在创建的时候与任务关联起来
- /*
- *********************************************************************************************************
- * CREATE A TASK
- *
- * Description: This function is used to have uC/OS-II manage the execution of a task. Tasks can either
- * be created prior to the start of multitasking or by a running task. A task cannot be
- * created by an ISR.
- *
- * Arguments : task is a pointer to the task's code
- *
- * p_arg is a pointer to an optional data area which can be used to pass parameters to
- * the task when the task first executes. Where the task is concerned it thinks
- * it was invoked and passed the argument 'p_arg' as follows:
- *
- * void Task (void *p_arg)
- * {
- * for (;;) {
- * Task code;
- * }
- * }
- *
- * ptos is a pointer to the task's top of stack. If the configuration constant
- * OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high
- * memory to low memory). 'pstk' will thus point to the highest (valid) memory
- * location of the stack. If OS_STK_GROWTH is set to 0, 'pstk' will point to the
- * lowest memory location of the stack and the stack will grow with increasing
- * memory locations.
- *
- * prio is the task's priority. A unique priority MUST be assigned to each task and the
- * lower the number, the higher the priority.
- *
- * Returns : OS_NO_ERR if the function was successful.
- * OS_PRIO_EXIT if the task priority already exist
- * (each task MUST have a unique priority).
- * OS_PRIO_INVALID if the priority you specify is higher that the maximum allowed
- * (i.e. >= OS_LOWEST_PRIO)
- * OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR.
- *********************************************************************************************************
- */
- #if OS_TASK_CREATE_EN > 0
- INT8U OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio)
- {
- OS_STK *psp;
- INT8U err;
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- #if OS_ARG_CHK_EN > 0
- if (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */
- return (OS_PRIO_INVALID);
- }
- #endif
- OS_ENTER_CRITICAL();
- if (OSIntNesting > 0) { /* Make sure we don't create the task from within an ISR */
- OS_EXIT_CRITICAL();
- return (OS_ERR_TASK_CREATE_ISR);
- }
- if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority */
- OSTCBPrioTbl[prio] = (OS_TCB *)1; /* Reserve the priority to prevent others from doing ... */
- /* ... the same thing until task is created. */
- OS_EXIT_CRITICAL();
- psp = OSTaskStkInit(task, p_arg, ptos, 0); /* Initialize the task's stack */
- err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);
- if (err == OS_NO_ERR) {
- if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */
- OS_Sched();
- }
- } else {
- OS_ENTER_CRITICAL();
- OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */
- OS_EXIT_CRITICAL();
- }
- return (err);
- }
- OS_EXIT_CRITICAL();
- return (OS_PRIO_EXIST);
- }
- #endif
初始化阶段,初始化一个元素栈指针,一个err变量,中断相关CPU状态变量
检查阶段,检查优先级是不是超出LOW的范围或者idle的范围
执行阶段,
关中断,检查是否中断嵌套,是否在中断中执行,
检查相应的优先级的TCB是否存在,如果不存在,即OSTCBPrioTbl[prio] == (OS_TCB *)0
那么执行OSTCBPrioTbl[prio] = (OS_TCB *)1
开中断
初始化栈函数 psp = OSTaskStkInit(task, p_arg, ptos, 0);
- /*
- *********************************************************************************************************
- * INITIALIZE A TASK'S STACK
- *
- * Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
- * stack frame of the task being created. This function is highly processor specific.
- *
- * Arguments : task is a pointer to the task code
- *
- * p_arg is a pointer to a user supplied data area that will be passed to the task
- * when the task first executes.
- *
- * ptos is a pointer to the top of stack. It is assumed that 'ptos' points to
- * a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then
- * 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if
- * OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
- * of the stack.
- *
- * opt specifies options that can be used to alter the behavior of OSTaskStkInit().
- * (see uCOS_II.H for OS_TASK_OPT_???).
- *
- * Returns : Always returns the location of the new top-of-stack' once the processor registers have
- * been placed on the stack in the proper order.
- *
- * Note(s) : 1) Interrupts are enabled when your task starts executing.
- * 2) All tasks run in SVC mode.
- *********************************************************************************************************
- */
- OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
- {
- OS_STK *stk;
- opt = opt; /* 'opt' is not used, prevent warning */
-
- stk = ptos; /* Load stack pointer */
-
- *(stk) = (OS_STK)task; /* Entry Point */
- *(--stk) = (INT32U)0; /* LR */
- *(--stk) = (INT32U)0; /* R12 */
- *(--stk) = (INT32U)0; /* R11 */
- *(--stk) = (INT32U)0; /* R10 */
- *(--stk) = (INT32U)0; /* R9 */
- *(--stk) = (INT32U)0; /* R8 */
- *(--stk) = (INT32U)0; /* R7 */
- *(--stk) = (INT32U)0; /* R6 */
- *(--stk) = (INT32U)0; /* R5 */
- *(--stk) = (INT32U)0; /* R4 */
- *(--stk) = (INT32U)0; /* R3 */
- *(--stk) = (INT32U)0; /* R2 */
- *(--stk) = (INT32U)0; /* R1 */
- *(--stk) = (INT32U)p_arg; /* R0 : argument */
- *(--stk) = (INT32U)0x00000013L; /* CPSR (SVC mode, Enable both IRQ and FIQ interrupts) */
-
- return (stk);
- }
这个函数有四个参数,第一个参数是指向task代码的指针
第二个参数是指向参数的指针,将参数指针存放在R0的位置*(--stk) = (INT32U)p_arg;
第三个参数,是指向栈顶的指针,ARM是从高地址到低地址栈,结构是从最高地址开始,向下存放数据
第四个参数,是不使用的opt选项参数,在uCOS_II.H中有OS_TASK_OPT_???相关的介绍
这些设置好的数据,应该是用来保存任务切换时的cpu寄存器的数据,也就是说这个初始化和栈的使用都是和选用的cpu相关的,那么在调度的时候也会不同!
将栈初始化好之后返回栈指向可使用地址的指针
然后是创建TCB的函数,这个函数应该是创建一个task最重要的一步,一个TCB对应一个prio对应一个task,TCB中保存着task所有的信息
- /*
- *********************************************************************************************************
- * INITIALIZE TCB
- *
- * Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when
- * a task is created (see OSTaskCreate() and OSTaskCreateExt()).
- *
- * Arguments : prio is the priority of the task being created
- *
- * ptos is a pointer to the task's top-of-stack assuming that the CPU registers
- * have been placed on the stack. Note that the top-of-stack corresponds to a
- * 'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory
- * location if OS_STK_GROWTH is set to 0. Note that stack growth is CPU
- * specific.
- *
- * pbos is a pointer to the bottom of stack. A NULL pointer is passed if called by
- * 'OSTaskCreate()'.
- *
- * id is the task's ID (0..65535)
- *
- * stk_size is the size of the stack (in 'stack units'). If the stack units are INT8Us
- * then, 'stk_size' contains the number of bytes for the stack. If the stack
- * units are INT32Us then, the stack contains '4 * stk_size' bytes. The stack
- * units are established by the #define constant OS_STK which is CPU
- * specific. 'stk_size' is 0 if called by 'OSTaskCreate()'.
- *
- * pext is a pointer to a user supplied memory area that is used to extend the task
- * control block. This allows you to store the contents of floating-point
- * registers, MMU registers or anything else you could find useful during a
- * context switch. You can even assign a name to each task and store this name
- * in this TCB extension. A NULL pointer is passed if called by OSTaskCreate().
- *
- * opt options as passed to 'OSTaskCreateExt()' or,
- * 0 if called from 'OSTaskCreate()'.
- *
- * Returns : OS_NO_ERR if the call was successful
- * OS_NO_MORE_TCB if there are no more free TCBs to be allocated and thus, the task cannot
- * be created.
- *
- * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
- *********************************************************************************************************
- */
- INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
- {
- OS_TCB *ptcb;
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- OS_ENTER_CRITICAL();
- ptcb = OSTCBFreeList; /* Get a free TCB from the free TCB list */
- if (ptcb != (OS_TCB *)0) {
- OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list */
- OS_EXIT_CRITICAL();
- ptcb->OSTCBStkPtr = ptos; /* Load Stack pointer in TCB */
- ptcb->OSTCBPrio = prio; /* Load task priority into TCB */
- ptcb->OSTCBStat = OS_STAT_RDY; /* Task is ready to run */
- ptcb->OSTCBPendTO = OS_FALSE; /* Clear the Pend timeout flag */
- ptcb->OSTCBDly = 0; /* Task is not delayed */
- #if OS_TASK_CREATE_EXT_EN > 0
- ptcb->OSTCBExtPtr = pext; /* Store pointer to TCB extension */
- ptcb->OSTCBStkSize = stk_size; /* Store stack size */
- ptcb->OSTCBStkBottom = pbos; /* Store pointer to bottom of stack */
- ptcb->OSTCBOpt = opt; /* Store task options */
- ptcb->OSTCBId = id; /* Store task ID */
- #else
- pext = pext; /* Prevent compiler warning if not used */
- stk_size = stk_size;
- pbos = pbos;
- opt = opt;
- id = id;
- #endif
- #if OS_TASK_DEL_EN > 0
- ptcb->OSTCBDelReq = OS_NO_ERR;
- #endif
- #if OS_LOWEST_PRIO <= 63
- ptcb->OSTCBY = (INT8U)(prio >> 3); /* Pre-compute X, Y, BitX and BitY */
- ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
- ptcb->OSTCBX = (INT8U)(prio & 0x07);
- ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
- #else
- ptcb->OSTCBY = (INT8U)((prio >> 4) & 0xFF);/* Pre-compute X, Y, BitX and BitY */
- ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY);
- ptcb->OSTCBX = (INT8U)(prio & 0x0F);
- ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX);
- #endif
- #if OS_EVENT_EN
- ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Task is not pending on an event */
- #endif
- #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
- ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag */
- #endif
- #if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
- ptcb->OSTCBMsg = (void *)0; /* No message received */
- #endif
- #if OS_TASK_PROFILE_EN > 0
- ptcb->OSTCBCtxSwCtr = 0L; /* Initialize profiling variables */
- ptcb->OSTCBCyclesStart = 0L;
- ptcb->OSTCBCyclesTot = 0L;
- ptcb->OSTCBStkBase = (OS_STK *)0;
- ptcb->OSTCBStkUsed = 0L;
- #endif
- #if OS_TASK_NAME_SIZE > 1
- ptcb->OSTCBTaskName[0] = '?'; /* Unknown name at task creation */
- ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;
- #endif
- #if OS_VERSION >= 204
- OSTCBInitHook(ptcb);
- #endif
- OSTaskCreateHook(ptcb); /* Call user defined hook */
- OS_ENTER_CRITICAL();
- OSTCBPrioTbl[prio] = ptcb;
- ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */
- ptcb->OSTCBPrev = (OS_TCB *)0;
- if (OSTCBList != (OS_TCB *)0) {
- OSTCBList->OSTCBPrev = ptcb;
- }
- OSTCBList = ptcb;
- OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- OSTaskCtr++; /* Increment the #tasks counter */
- OS_EXIT_CRITICAL();
- return (OS_NO_ERR);
- }
- OS_EXIT_CRITICAL();
- return (OS_NO_MORE_TCB);
- }
我们来详细的看看这一部分代码:
第一步
关中断
ptcb = OSTCBFreeList; 从系统里面取得一个没有使用的TCB块
如果获取成功,OSTCBFreeList = ptcb->OSTCBNext;
开中断
初始化栈地址,优先级,运行状态,等待状态,Delay等待时间,
如果使能Ext,那么还有附加数据指针,栈大小,栈底指针,TCB选项,TCBID的初始化
如果没有使能Ext那么这些变量都作为局部变量不使用
初始化就绪表比较使用到的,XYbitX和bitY变量,用来快速查找就绪表
ptcb->OSTCBY = (INT8U)(prio >> 3); /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
ptcb->OSTCBX = (INT8U)(prio & 0x07);
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
初始化事件关联 ptcb->OSTCBEventPtr = (OS_EVENT *)0;
ptcb->OSTCBFlagNode初始化flag
ptcb->OSTCBMsg初始化消息邮箱 队列
初始化分析数据
关中断,将初始化好的TCB赋值给OSTCBPrioTbl[prio],这个列表中存放的是已经建立好的TCB指针,注意是指针数组,
OS_EXT OS_TCB *OSTCBCur; /* Pointer to currently running TCB */
OS_EXT OS_TCB *OSTCBFreeList; /* Pointer to list of free TCBs */
OS_EXT OS_TCB *OSTCBHighRdy; /* Pointer to highest priority TCB R-to-R */
OS_EXT OS_TCB *OSTCBList;/* Pointer to doubly linked list of TCBs */
OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];/* Table of pointers to created TCBs*/
OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];/* Table of TCBs */
这是几种TCB的链表和数组,注意,只有最后一个OSTCBTbl数组才是真正的元素为TCB的数组,其他的都是指针和指针数组,都是指向这个数组的元素的指针构成的数据!
将当前的TCB加入双量表OSTCBList的表尾,next指向NULL
将就绪表的相应位置为就绪
taskctr自加
开中断
返回OS_NO_ERR
从TCB初始化函数跳出来返回任务建立函数
如果建立返回值为OS_NO_ERR且running标志位为true,开始调度
如果不是,建立失败返回err变量
明天看调度函数!
阅读(2343) | 评论(0) | 转发(0) |