【 ucos

    科技2022-07-21  101

    1. 修改任务优先级,OSTaskChangePrio()

    /* ********************************************************************************************************* * CHANGE PRIORITY OF A TASK(修改任务优先级) * * Description: This function allows you to change the priority of a task dynamically. Note that the new * priority MUST be available.(这个函数允许你动态的修改任务的优先级,注意,新的优先级必须是有效的) * * Arguments : oldp is the old priority(旧的优先级) * * newp is the new priority(新的优先级) * * Returns : OS_ERR_NONE is the call was successful * 正确执行 * OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed * (i.e. >= OS_LOWEST_PRIO) * 如果你赋予的优先级比系统所允许的优先级还要高 * OS_ERR_PRIO_EXIST if the new priority already exist. * 如果新的优先级已经存在 * OS_ERR_PRIO there is no task with the specified OLD priority (i.e. the OLD task does * not exist. * 旧优先级的任务并不存在 * OS_ERR_TASK_NOT_EXIST if the task is assigned to a Mutex PIP. * 新的优先级已经被优先级反转所占用 ********************************************************************************************************* */ //修改任务优先级 #if OS_TASK_CHANGE_PRIO_EN > 0u INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio) { //#define OS_EVENT_EN (((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) || (OS_SEM_EN > 0u) || (OS_MUTEX_EN > 0u)) #if (OS_EVENT_EN)//如果允许定义事件,则定义一个指向ECB的指针 OS_EVENT *pevent; //#define OS_EVENT_MULTI_EN 1u /* Include code for OSEventPendMulti() */ #if (OS_EVENT_MULTI_EN > 0u) OS_EVENT **pevents; #endif #endif OS_TCB *ptcb;//指向TCB的指针 INT8U y_new; INT8U x_new; INT8U y_old; OS_PRIO bity_new; OS_PRIO bitx_new; OS_PRIO bity_old; OS_PRIO bitx_old; #if OS_CRITICAL_METHOD == 3u OS_CPU_SR cpu_sr = 0u; /* Storage for CPU status register */ #endif #if OS_ARG_CHK_EN > 0u //是否允许参数检查 if (oldprio >= OS_LOWEST_PRIO) { if (oldprio != OS_PRIO_SELF) { //#define OS_PRIO_SELF 0xFFu /* Indicate SELF priority */ return (OS_ERR_PRIO_INVALID); } } if (newprio >= OS_LOWEST_PRIO) { return (OS_ERR_PRIO_INVALID); } #endif OS_ENTER_CRITICAL();//关中断 if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) { /* New priority must not already exist */ OS_EXIT_CRITICAL();//开中断 return (OS_ERR_PRIO_EXIST); } if (oldprio == OS_PRIO_SELF) { /* See if changing self */ oldprio = OSTCBCur->OSTCBPrio; /* Yes, get priority */ }//OS_EXT OS_TCB *OSTCBCur; /* Pointer to currently running TCB */ //ucos_ii.h中定义了外部变量,直接引用即可 ptcb = OSTCBPrioTbl[oldprio];//在优先级表中获取对应的优先级的TCB指针 if (ptcb == (OS_TCB *)0) { /* Does task to change exist? */ OS_EXIT_CRITICAL(); /* No, can't change its priority! */ return (OS_ERR_PRIO); } if (ptcb == OS_TCB_RESERVED) { /* Is task assigned to Mutex */ //OS_TCB_RESERVED 用于优先级反转时反转的优先级 OS_EXIT_CRITICAL(); /* No, can't change its priority! */ return (OS_ERR_TASK_NOT_EXIST); } #if OS_LOWEST_PRIO <= 63u //旧版的ucos_ii有64个任务 //左移三位获得优先级高三位,强转成8位 y_new = (INT8U)(newprio >> 3u); /* Yes, compute new TCB fields */ //与00000111B逐位相与获得低三位,强转成8位 x_new = (INT8U)(newprio & 0x07u); #else //较新版的ucos_ii中有256个任务,为8位 //左移4位获得高4位,强转成8位,与00001111逐位相与获得低四位 y_new = (INT8U)((INT8U)(newprio >> 4u) & 0x0Fu); //与00001111逐位相与获得低四位 x_new = (INT8U)(newprio & 0x0Fu); #endif //在就绪组/表中所对应的位置 /* #if OS_LOWEST_PRIO <= 63u typedef INT8U OS_PRIO; #else typedef INT16U OS_PRIO; #endif */ //如果获取的高三位,说明1左移最多可以左移7位,即,就绪表为INT8U //如果获取的高四位,说明1左移最多可以左移15位,即,就绪表为INT16U bity_new = (OS_PRIO)(1uL << y_new); bitx_new = (OS_PRIO)(1uL << x_new); OSTCBPrioTbl[oldprio] = (OS_TCB *)0; /* Remove TCB from old priority */ OSTCBPrioTbl[newprio] = ptcb; /* Place pointer to TCB @ new priority */ y_old = ptcb->OSTCBY; bity_old = ptcb->OSTCBBitY; bitx_old = ptcb->OSTCBBitX; //修改就绪组/表,使任务取消就绪状态 if ((OSRdyTbl[y_old] & bitx_old) != 0u) { /* If task is ready make it not */ OSRdyTbl[y_old] &= (OS_PRIO)~bitx_old; if (OSRdyTbl[y_old] == 0u) { OSRdyGrp &= (OS_PRIO)~bity_old; }//取消原有就绪状态,此处比较巧妙,先修改就绪表,再修改就绪组 OSRdyGrp |= bity_new; /* Make new priority ready to run */ OSRdyTbl[y_new] |= bitx_new; OS_TRACE_TASK_READY(ptcb); } //如果TCB在等待事件的话,修改事件等待组/表 #if (OS_EVENT_EN) pevent = ptcb->OSTCBEventPtr; if (pevent != (OS_EVENT *)0) { pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old; /* Remove old task prio from wait list */ if (pevent->OSEventTbl[y_old] == 0u) { pevent->OSEventGrp &= (OS_PRIO)~bity_old; } pevent->OSEventGrp |= bity_new; /* Add new task prio to wait list */ pevent->OSEventTbl[y_new] |= bitx_new; } #if (OS_EVENT_MULTI_EN > 0u) if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { //pevents是一个二级指针,相当于二维数组的二级指针 pevents = ptcb->OSTCBEventMultiPtr; //获得某一维的一级指针 pevent = *pevents; while (pevent != (OS_EVENT *)0) { pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old; /* Remove old task prio from wait lists */ if (pevent->OSEventTbl[y_old] == 0u) { pevent->OSEventGrp &= (OS_PRIO)~bity_old; } pevent->OSEventGrp |= bity_new; /* Add new task prio to wait lists */ pevent->OSEventTbl[y_new] |= bitx_new; pevents++;//转向下一维 pevent = *pevents; } } #endif #endif //修改TCB为新设置的值 ptcb->OSTCBPrio = newprio; /* Set new task priority */ ptcb->OSTCBY = y_new; ptcb->OSTCBX = x_new; ptcb->OSTCBBitY = bity_new; ptcb->OSTCBBitX = bitx_new; OS_EXIT_CRITICAL();//开中断 if (OSRunning == OS_TRUE) { OS_Sched(); /* Find new highest priority task */ }//如果系统正在运行,执行一次调度 return (OS_ERR_NONE); } #endif

    2.1 创建任务,OSTaskCreate()

    /* ********************************************************************************************************* * 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.(此功能用于让uC / OS-II管理任务的执行。 可以在开始多任务之前创建任务,也可以通过正在运行的任务创建任务。 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; * } * } * //是指向可选数据区域的指针,当任务首次执行时,该数据区域可用于将参数传递给任务。 在涉及任务的地方,它认为它已被调用并传递了参数“ p_arg” * 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. * //是指向任务堆栈栈顶的指针。如果配置常量OS_STK_GROWTH被设置为1,那么这个堆栈就被认为是向下增长的(从高址向低址)。因此,‘pstk’会指向堆栈最高的有效地址。如果OS_STK_GROWTH被设置为0,‘ptsk’会指向堆栈最低的有效地址,并且堆栈的增长方向是向上增长的 * 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_ERR_NONE if the function was successful. * //函数正常执行 * OS_ERR_PRIO_EXIST if the task priority already exist * //优先级已经存在 * (each task MUST have a unique priority). * OS_ERR_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. * //ISR中禁止创建任务 * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you tried to create a task after safety critical * operation started. * //如果您在安全关键操作开始后尝试创建任务。 ********************************************************************************************************* */ #if OS_TASK_CREATE_EN > 0u //允许任务创建 INT8U OSTaskCreate (void (*task)(void *p_arg),//函数指针,指向函数的指针,也就是说任务的代码是一个函数 void *p_arg,//函数的参数 OS_STK *ptos,//堆栈的栈顶 INT8U prio)//任务的优先级 { OS_STK *psp;//指向任务堆栈的指针 INT8U err;//返回的状态码 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #ifdef OS_SAFETY_CRITICAL_IEC61508 if (OSSafetyCriticalStartFlag == OS_TRUE) { OS_SAFETY_CRITICAL_EXCEPTION(); return (OS_ERR_ILLEGAL_CREATE_RUN_TIME); } #endif #if OS_ARG_CHK_EN > 0u //是否允许参数检查 if (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */ return (OS_ERR_PRIO_INVALID); //创建的任务的优先级大于最低优先级,优先级无效 } #endif OS_ENTER_CRITICAL();//关中断 if (OSIntNesting > 0u) { /* Make sure we don't create the task from within an ISR */ //ISR中禁止创建任务,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_RESERVED;/* Reserve the priority to prevent others from doing ... */ /* ... the same thing until task is created. */ OS_EXIT_CRITICAL();//及时的退出临界区,开中断 psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* Initialize the task's stack */ err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u); if (err == OS_ERR_NONE) { OS_TRACE_TASK_CREATE(OSTCBPrioTbl[prio]); if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */ OS_Sched(); } } else { OS_TRACE_TASK_CREATE_FAILED(OSTCBPrioTbl[prio]); OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */ OS_EXIT_CRITICAL(); } return (err); } OS_EXIT_CRITICAL(); return (OS_ERR_PRIO_EXIST); } #endif

    这里涉及到了两个函数:

    OSTaskStkInit()在os_cpu_c.c文件中

    /* ********************************************************************************************************* * 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. *(这个函数既可以被OSTaskCreate()调用也可以被OSTaskCreateExt()调用,来在任务被创建之前初始化堆栈,这个函数高度依赖于处理器) * Arguments : task Pointer to the task code. * //任务代码的指针 * p_arg Pointer to a user supplied data area that will be passed to the task * when the task first executes. * //指向用户提供的数据区域的指针,该数据区域将在任务首次执行时传递给任务。 * ptos Pointer to the top of stack. It is assumed that 'ptos' points to the * highest valid address on the stack. * //指向任务堆栈的栈顶,假设‘ptos’指向了堆栈有效地址的最高地址 * opt Options used to alter the behavior of OSTaskStkInit(). * (see uCOS_II.H for OS_TASK_OPT_???). * //用来修改OSTaskStkInit()的行为 * 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. * //只要以正确的顺序将处理器寄存器放置在堆栈上,就始终返回新堆栈顶部的位置。 ********************************************************************************************************* */ OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt) { OS_TASK_STK *p_stk; /* Load stack pointer */ p_stk = (OS_TASK_STK *)((char *)ptos - sizeof(OS_TASK_STK)); //因为始终假设ptos指向了栈顶,所以将ptos强转成指向1字节的指针,然后减去任务堆栈的size,使ptos指向堆栈的栈底 //即ptos此时指向了任务堆栈这个结构体的首地址 //OS_STK 为CPU_INT32U(unsigned int)类型,因为这个源代码是适配win32的,所以此时可以认为ptos仅仅是指向unsigned int类型的指针,最后强转成了OS_TASK_STK 类型 p_stk->TaskArgPtr = p_arg; p_stk->TaskOpt = opt; p_stk->Task = task; p_stk->ThreadHandle = NULL; p_stk->ThreadID = 0u; p_stk->TaskState = STATE_NONE; p_stk->SignalPtr = NULL; p_stk->InitSignalPtr = NULL; p_stk->Terminate = DEF_FALSE; p_stk->OSTCBPtr = NULL; return ((OS_STK *)p_stk); //虽然指针各种强转,但是指针真正指向的地址是不会变的,因为指针始终是4个字节,强转类型,只不过决定了指针在读取内容的时候一次读取的字节数 }

    OS_TCBInit()在os_core.c文件中

    /* ********************************************************************************************************* * INITIALIZE TCB(初始化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()). *(此函数是uC/OS-II的内部函数,当一个任务被创建的时候用来初始化TCB) * 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. * //是指向任务堆栈顶部的指针,假设已将CPU寄存器放置在堆栈中。 请注意,栈顶对应于OS_STK_GROWTH设置为1的“高”内存位置,如果OS_STK_GROWTH设置为0则对应的“低”内存位置。请注意,栈增长是特定于CPU的。 * pbos is a pointer to the bottom of stack. A NULL pointer is passed if called by * 'OSTaskCreate()'. * //是指向任务堆栈栈底的指针,当使用OSTaskCreate()的时候传递的是空值 * id is the task's ID (0..65535) * //是此任务的ID * 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()'. * //是堆栈的大小,(是以堆栈单元来说的)如果堆栈单元是INT8U的话,那么这个堆栈就包含了stk_size个字节,如果堆栈单元是INT32U的话,那么堆栈的大小就是4*stk_size个字节大小,堆栈单元由#define常数OS_STK建立,该常数特定于CPU。如果使用OSTaskCreate()来创建任务,那么这个参数为0 * 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(). * //是用户提供的指向内存区域的指针,用来扩展TCB,这个地方允许你存储浮点寄存器的内容,MMU寄存器的内容,或者任何你认为在上下文切换的时候有用的东西。你甚至可以为每个任务取一个名字,然后用这个扩展块来存储这个名字。在OSTaskCreate()中,这个值为空值。 * opt options as passed to 'OSTaskCreateExt()' or, * 0 if called from 'OSTaskCreate()'. * * Returns : OS_ERR_NONE if the call was successful//调用成功 * OS_ERR_TASK_NO_MORE_TCB if there are no more free TCBs to be allocated and thus, the task * cannot be created. * //没有额外的TCB * Note : This function is INTERNAL to uC/OS-II and your application should not call it. * //这个函数是uC/OS-II的内部函数,你的应用程序不能够调用它 ********************************************************************************************************* */ 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 == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #if OS_TASK_REG_TBL_SIZE > 0u INT8U i; #endif #if OS_TASK_CREATE_EXT_EN > 0u //是否允许使用扩展块 #if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) INT8U j; #endif #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->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ ptcb->OSTCBDly = 0u; /* Task is not delayed */ #if OS_TASK_CREATE_EXT_EN > 0u 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 > 0u //是否允许删除任务 ptcb->OSTCBDelReq = OS_ERR_NONE; #endif //区分系统是最大允许多少任务 #if OS_LOWEST_PRIO <= 63u /* Pre-compute X, Y */ ptcb->OSTCBY = (INT8U)(prio >> 3u); ptcb->OSTCBX = (INT8U)(prio & 0x07u); #else /* Pre-compute X, Y */ ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu); ptcb->OSTCBX = (INT8U) (prio & 0x0Fu); #endif /* Pre-compute BitX and BitY */ ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); //是否允许使用事件 #if (OS_EVENT_EN) ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Task is not pending on an event */ #if (OS_EVENT_MULTI_EN > 0u) ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0; /* Task is not pending on any events */ #endif #endif //是否允许使用事件标志组 #if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) && (OS_TASK_DEL_EN > 0u) ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag */ #endif //是否允许使用信箱 #if (OS_MBOX_EN > 0u) || ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) ptcb->OSTCBMsg = (void *)0; /* No message received */ #endif #if OS_TASK_PROFILE_EN > 0u ptcb->OSTCBCtxSwCtr = 0uL; /* Initialize profiling variables */ ptcb->OSTCBCyclesStart = 0uL; ptcb->OSTCBCyclesTot = 0uL; ptcb->OSTCBStkBase = (OS_STK *)0; ptcb->OSTCBStkUsed = 0uL; #endif //是否允许使用任务名字 #if OS_TASK_NAME_EN > 0u ptcb->OSTCBTaskName = (INT8U *)(void *)"?"; #endif #if OS_TASK_REG_TBL_SIZE > 0u /* Initialize the task variables */ for (i = 0u; i < OS_TASK_REG_TBL_SIZE; i++) { ptcb->OSTCBRegTbl[i] = 0u; } #endif OSTCBInitHook(ptcb); //TCB初始化完毕后的钩子函数 OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio] = ptcb;//设置优先级列表 OS_EXIT_CRITICAL(); OSTaskCreateHook(ptcb); /* Call user defined hook */ //任务创建完成后的钩子函数 #if OS_TASK_CREATE_EXT_EN > 0u #if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) for (j = 0u; j < OS_TLS_TBL_SIZE; j++) { ptcb->OSTCBTLSTbl[j] = (OS_TLS)0; } OS_TLS_TaskCreate(ptcb); /* Call TLS hook */ #endif #endif OS_ENTER_CRITICAL(); //插入到就绪链表,就绪链表为双向链表,ucos中所有的链表操作都是从表头进行插入 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_TRACE_TASK_READY(ptcb); OS_EXIT_CRITICAL(); return (OS_ERR_NONE); } OS_EXIT_CRITICAL(); return (OS_ERR_TASK_NO_MORE_TCB); }
    Processed: 0.010, SQL: 8