/************************************************************************************************* * 功能:线程运行监理函数,线程的运行都以它为基础 * * 参数:(1) pThread 线程地址 * * 返回:无 * * 说明:这里处理线程的非法退出问题 * * 说明:函数名的前缀'x'(eXtreme)表示本函数需要处理临界区代码 * *************************************************************************************************/ static void xSuperviseThread(TThread* pThread) { TState state; TError error; TReg32 imask; /* 调用用户ASR线程主函数,这类函数的特点是解挂后一次性执行,然后立刻挂起,等待下次调用。 虽然Irq和Timer守护线程也是中断服务线程,但不是做为ASR在此处理。 这两个函数自己处理挂起问题 */ if ((pThread->Property &THREAD_PROP_RUNASR)) { while (eTrue) { /* 执行线程函数 */ pThread->Entry(pThread->Argument); /* 线程运行结束后直接挂起,等待再次被执行 */ CpuEnterCritical(&imask); state = uThreadSetUnready(pThread, eThreadSuspended, 0U, &error); if (state == eFailure) { uKernelVariable.Diagnosis |= KERNEL_DIAG_THREAD_ERROR; pThread->Diagnosis |= THREAD_DIAG_INVALID_STATE; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } CpuLeaveCritical(imask); } } /* 处理RUN TO COMPLETION 线程退出问题, 防止退出后处理器执行到非法(未知)指令 */ else if (pThread->Property &THREAD_PROP_RUN2COMPLETION) { /* 执行线程函数 */ pThread->Entry(pThread->Argument); /* 线程运行结束后直接挂起,等待后继处理 */ CpuEnterCritical(&imask); state = uThreadSetUnready(pThread, eThreadDormant, 0U, &error); if (state == eFailure) { uKernelVariable.Diagnosis |= KERNEL_DIAG_THREAD_ERROR; pThread->Diagnosis |= THREAD_DIAG_INVALID_STATE; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } CpuLeaveCritical(imask); } else { /* 执行用户线程函数 */ pThread->Entry(pThread->Argument); /* 防止RUNFOREVER线程不小心退出导致非法指令等死机的问题 */ uKernelVariable.Diagnosis |= KERNEL_DIAG_THREAD_ERROR; pThread->Diagnosis |= THREAD_DIAG_INVALID_EXIT; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } }
/************************************************************************************************* * 功能:将线程放入资源阻塞队列 * * 参数:(1) pQueue 线程队列结构地址 * * (2) pThread 线程结构地址 * * (3) ticks 资源等待时限 * * 返回:无 * * 说明:对于线程进出相关队列的策略根据队列策略特性来进行 * *************************************************************************************************/ void uIpcBlockThread(TIpcContext* pContext, TIpcQueue* pQueue, TTimeTick ticks) { TThread* pThread; KNL_ASSERT((uKernelVariable.State != eIntrState), ""); /* 将线程放入内核线程辅助队列 */ pThread = (TThread*)(pContext->Owner); /* 只有处于就绪状态的线程才可以被阻塞 */ if (pThread->Status != eThreadRunning) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } uThreadLeaveQueue(uKernelVariable.ThreadReadyQueue, pThread); uThreadEnterQueue(uKernelVariable.ThreadAuxiliaryQueue, pThread, eQuePosTail); pThread->Status = eThreadBlocked; /* 将线程放入阻塞队列 */ EnterBlockedQueue(pQueue, pContext); /* 如果需要就初始化并且打开线程用于访问资源的时限定时器 */ #if (TCLC_TIMER_ENABLE && TCLC_IPC_TIMER_ENABLE) if ((pContext->Option & IPC_OPT_TIMED) && (ticks > 0U)) { /* 重新配置并启动线程定时器 */ uTimerConfig(&(pThread->Timer), eIpcTimer, ticks); uTimerStart(&(pThread->Timer), 0U); } #else ticks = ticks; #endif }
/************************************************************************************************* * 功能:初始化用户定时器守护线程 * * 参数:无 * * 返回:无 * * 说明: * *************************************************************************************************/ void uTimerCreateDaemon(void) { /* 检查内核是否处于初始状态 */ if(uKernelVariable.State != eOriginState) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } /* 初始化内核定时器服务线程 */ uThreadCreate(&TimerDaemonThread, eThreadSuspended, THREAD_PROP_PRIORITY_FIXED|\ THREAD_PROP_CLEAN_STACK|\ THREAD_PROP_DAEMON, TIMER_DAEMON_ACAPI, TimerDaemonEntry, (TArgument)(0U), (void*)TimerDaemonStack, (TBase32)TCLC_TIMER_DAEMON_STACK_BYTES, (TPriority)TCLC_TIMER_DAEMON_PRIORITY, (TTimeTick)TCLC_TIMER_DAEMON_SLICE); /* 初始化相关的内核变量 */ uKernelVariable.TimerDaemon = &TimerDaemonThread; }
/************************************************************************************************* * 功能:计算就绪线程队列中的最高优先级函数 * * 参数:无 * * 返回:HiRP (Highest Ready Priority) * * 说明: * *************************************************************************************************/ void uThreadCalcHiRP(TPriority* priority) { /* 如果就绪优先级不存在则说明内核发生致命错误 */ if (ThreadReadyQueue.PriorityMask == (TBitMask)0) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } *priority = CpuCalcHiPRIO(ThreadReadyQueue.PriorityMask); }
/* * 1 当前线程离开队列即代表它放弃本轮运行,再次进入队列时,时间片需要重新计算, * 在队列中的位置也规定一定是在队尾 * 2 导致当前线程不是最高就绪优先级的原因有 * 1 别的优先级更高的线程进入就绪队列 * 2 当前线程自己离开队列 * 3 别的线程的优先级被提高 * 4 当前线程的优先级被拉低 * 5 当前线程Yiled * 6 时间片中断中,当前线程被轮转 * 3 在cortex处理器上, 有这样一种可能: * 当前线程释放了处理器,但在PendSV中断得到响应之前,又有其它高优先级中断发生, * 在高级isr中又把当前线程置为就绪, * 1 并且当前线程仍然是最高就绪优先级, * 2 并且当前线程仍然在最高就绪线程队列的队列头。 * 此时需要考虑取消PENDSV的操作,避免当前线程和自己切换 */ void uThreadSchedule(void) { TPriority priority; /* 如果就绪优先级不存在则说明内核发生致命错误 */ if (ThreadReadyQueue.PriorityMask == (TBitMask)0) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } /* 查找最高就绪优先级,获得后继线程,如果后继线程指针为空则说明内核发生致命错误 */ CalcThreadHiRP(&priority); uKernelVariable.NomineeThread = (TThread*)((ThreadReadyQueue.Handle[priority])->Owner); if (uKernelVariable.NomineeThread == (TThread*)0) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } /* * 完成线程的优先级抢占或者时间片轮转; * 或者完成线程调度(我们在这里区分"抢占"和"调度"的含义) */ if (uKernelVariable.NomineeThread != uKernelVariable.CurrentThread) { #if (TCLC_THREAD_STACK_CHECK_ENABLE) CheckThreadStack(uKernelVariable.NomineeThread); #endif uKernelVariable.NomineeThread->Status = eThreadRunning; if (uKernelVariable.CurrentThread->Status == eThreadRunning) { uKernelVariable.CurrentThread->Status = eThreadReady; } CpuConfirmThreadSwitch(); } else { CpuCancelThreadSwitch(); uKernelVariable.CurrentThread->Status = eThreadRunning; } }
/************************************************************************************************* * 功能:定时器模块初始化 * * 参数:无 * * 返回:无 * * 说明: * *************************************************************************************************/ void uTimerModuleInit(void) { /* 检查内核是否处于初始状态 */ if(uKernelVariable.State != eOriginState) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } memset(&TimerList, 0, sizeof(TimerList)); /* 初始化相关的内核变量 */ uKernelVariable.TimerList = &TimerList; }
/************************************************************************************************* * 功能:初始化内核线程管理模块 * * 参数:无 * * 返回:无 * * 说明:内核中的线程队列主要有一下几种: * * (1) 线程就绪队列,用于存储所有就绪线程(包括运行的线程)。内核中只有一个就绪队列 * * (2) 线程辅助队列, 所有初始化状态、延时状态和休眠状态的线程都存储在这个队列中。 * * 同样内核中只有一个休眠队列 * * (3) IPC对象的线程阻塞队列 * *************************************************************************************************/ void uThreadModuleInit(void) { /* 检查内核是否处于初始状态 */ if (uKernelVariable.State != eOriginState) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } memset(&ThreadReadyQueue, 0, sizeof(ThreadReadyQueue)); memset(&ThreadAuxiliaryQueue, 0, sizeof(ThreadAuxiliaryQueue)); uKernelVariable.ThreadReadyQueue = &ThreadReadyQueue; uKernelVariable.ThreadAuxiliaryQueue = &ThreadAuxiliaryQueue; }
/************************************************************************************************* * 功能:告警和检查线程栈溢出问题 * * 参数:(1) pThread 线程地址 * * 返回:无 * * 说明: * *************************************************************************************************/ static void CheckThreadStack(TThread* pThread) { if ((pThread->StackTop < pThread->StackBarrier) || (*(TBase32*)(pThread->StackBarrier) != TCLC_THREAD_STACK_BARRIER_VALUE)) { uKernelVariable.Diagnosis |= KERNEL_DIAG_THREAD_ERROR; pThread->Diagnosis |= THREAD_DIAG_STACK_OVERFLOW; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } if (pThread->StackTop < pThread->StackAlarm) { pThread->Diagnosis |= THREAD_DIAG_STACK_ALARM; } }
/************************************************************************************************* * 功能:定时器模块初始化 * * 参数:无 * * 返回:无 * * 说明: * *************************************************************************************************/ void uIrqModuleInit(void) { /* 检查内核是否处于初始状态 */ if(uKernelVariable.State != eOriginState) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } memset(IrqMapTable, 0, sizeof(IrqMapTable)); memset(IrqVectorTable, 0, sizeof(IrqVectorTable)); #if (TCLC_IRQ_DAEMON_ENABLE) memset(&IrqReqList, 0, sizeof(IrqReqList)); #endif /* 初始化相关的内核变量 */ uKernelVariable.IrqMapTable = IrqMapTable; uKernelVariable.IrqVectorTable = IrqVectorTable; }
void uThreadSuspendSelf(void) { /* 操作目标是当前线程 */ TThread* pThread = uKernelVariable.CurrentThread; /* 将当前线程挂起,如果内核此时禁止线程调度,那么当前线程不能被操作 */ if (uKernelVariable.Schedulable == eTrue) { uThreadLeaveQueue(&ThreadReadyQueue, pThread); uThreadEnterQueue(&ThreadAuxiliaryQueue, pThread, eQuePosTail); pThread->Status = eThreadSuspended; uThreadSchedule(); } else { uKernelVariable.Diagnosis |= KERNEL_DIAG_SCHED_ERROR; pThread->Diagnosis |= THREAD_DIAG_NORMAL; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } }
/************************************************************************************************* * 功能:线程运行监理函数,线程的运行都以它为基础 * * 参数:(1) pThread 线程地址 * * 返回:无 * * 说明:函数名的前缀'x'(eXtreme)表示本函数需要处理临界区代码 * *************************************************************************************************/ static void xSuperviseThread(TThread* pThread) { TReg32 imask; KNL_ASSERT((pThread == uKernelVariable.CurrentThread), ""); #if (TCLC_IRQ_ENABLE) if (pThread->Property &THREAD_PROP_ASR) { while (eTrue) { /* * 调用用户ASR线程主函数,这类函数的特点是唤醒执行后, * 会被系统自动挂起,等待下次唤醒。 */ pThread->Entry(pThread->Argument); /* * 当ASR之行结束后,准备挂起时,此时ISR可能会又一次进入尝试唤醒ASR, * 不巧此时ASR为运行状态。为了避免ASR丢失下轮的唤醒请求,在这里略纠结 * 的添加了检查 */ CpuEnterCritical(&imask); if (pThread->SyncValue == 0U) { uThreadSuspendSelf(); } else { pThread->SyncValue = 0U; } CpuLeaveCritical(imask); } } #endif /* 普通线程需要注意用户不小心退出导致非法指令等死机的问题 */ pThread->Entry(pThread->Argument); uKernelVariable.Diagnosis |= KERNEL_DIAG_THREAD_ERROR; pThread->Diagnosis |= THREAD_DIAG_INVALID_EXIT; uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); }
/************************************************************************************************* * 功能:唤醒IPC阻塞队列中指定的线程 * * 参数:(1) pThread 线程地址 * * (2) state 线程资源访问返回结果 * * (3) error 详细调用结果 * * (4) pHiRP 是否因唤醒更高优先级而导致需要进行线程调度的标记 * * 返回:无 * * 说明: * *************************************************************************************************/ void uIpcUnblockThread(TIpcContext* pContext, TState state, TError error, TBool* pHiRP) { TThread* pThread; TQueuePos pos = eQuePosTail; TThreadStatus newStatus = eThreadReady; /* * 将线程从IPC资源的阻塞队列中移出,加入到内核线程就绪队列, * 如果当前线程刚刚被阻塞到阻塞队列中,但还未发生线程切换, * 而在此时被ISR打断并且ISR又将当前线程唤醒,则当前线程也不必返回就绪队列头 */ pThread = (TThread*)(pContext->Owner); /* 只有处于阻塞状态的线程才可以被解除阻塞 */ if (pThread->Status != eThreadBlocked) { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } /* * 操作线程,完成线程队列和状态转换,注意只有中断处理时, * 当前线程才会处在内核线程辅助队列里(因为还没来得及线程切换) * 当前线程返回就绪队列时,一定要回到相应的队列头 * 当线程进出就绪队列时,不需要处理线程的时钟节拍数 */ uThreadLeaveQueue(uKernelVariable.ThreadAuxiliaryQueue, pThread); if (pThread == uKernelVariable.CurrentThread) { pos = eQuePosHead; newStatus = eThreadRunning; } uThreadEnterQueue(uKernelVariable.ThreadReadyQueue, pThread, pos); pThread->Status = newStatus; /* 将线程从阻塞队列移出 */ LeaveBlockedQueue(pContext->Queue, pContext); /* 设置线程访问资源的结果和错误代码 */ *(pContext->State) = state; *(pContext->Error) = error; /* 如果线程是以时限方式访问资源则取消该线程的时限定时器 */ #if ((TCLC_IPC_TIMER_ENABLE) && (TCLC_TIMER_ENABLE)) if ((pContext->Option & IPC_OPT_TIMED) && (error != IPC_ERR_TIMEO)) { KNL_ASSERT((pThread->Timer.Type == eIpcTimer), ""); uTimerStop(&(pThread->Timer)); } #endif /* 设置线程调度请求标记,此标记只在线程环境下有效。 在ISR里,当前线程可能在任何队列里, 跟当前线程相比较优先级也是无意义的 */ /* * 在线程环境下,如果当前线程的优先级已经不再是线程就绪队列的最高优先级, * 并且内核此时并没有关闭线程调度,那么就需要进行一次线程抢占 */ if (pThread->Priority < uKernelVariable.CurrentThread->Priority) { *pHiRP = eTrue; } }
/************************************************************************************************* * 功能:内核定时器执行处理函数 * * 参数:(1) pTimer 定时器 * * 返回:无 * * 说明: (1)线程延时的时候,线程被放入内核线程延时队列中 * * (2)线程以时限方式访问资源的时候,如果得不到资源会被放入资源的线程阻塞队列 * * 这里虽然有线程队列操作但是不进行调度,是因为这个函数是在中断中调用的, * * 在最后一层中断返回后,会尝试进行一次线程切换,所以在这里做切换的话是白白浪费时间 * *************************************************************************************************/ static void DispatchTimer(TTimer* pTimer) { TThread* pThread; #if ((TCLC_IPC_ENABLE) && (TCLC_IPC_TIMER_ENABLE)) TBool HiRP = eFalse; #endif /* 如果定时器是线程延时类型的定时器 */ if (pTimer->Type == eThreadTimer) { /* 将定时器从活动队列中移出,将定时器放到休眠队列里 */ uObjListRemoveNode(pTimer->ObjNode.Handle, &(pTimer->ObjNode)); uObjListAddNode(&(TimerList.DormantHandle), &(pTimer->ObjNode), eQuePosHead); pTimer->Status = eTimerDormant; /* 如果定时器所在的线程处于延时状态则把线程放入内核线程活动队列 */ pThread = (TThread*)(pTimer->Owner); KNL_ASSERT((pThread->Status == eThreadDelayed), ""); uThreadLeaveQueue(uKernelVariable.ThreadAuxiliaryQueue, pThread); uThreadEnterQueue(uKernelVariable.ThreadReadyQueue, pThread, eQuePosTail); /* 当线程离开就绪队列时,已经放弃它的本轮执行,哪怕时间片并未耗尽。 当线程再次进入就绪队列时,需要恢复线程的时钟节拍数, 重新计算其分享处理器时间的能力 */ pThread->Ticks = pThread->BaseTicks; pThread->Status = eThreadReady; } /* 如果定时器是用户定时器类型 */ else if (pTimer->Type == eUserTimer) { #if (TCLC_TIMER_DAEMON_ENABLE) /* 紧急的定时器直接在ISR里处理回调事务; 否则将定时器放入内核定时器期满列表,最后由定时器守护线程处理 */ if (pTimer->Property & TIMER_PROP_URGENT) { pTimer->Routine(pTimer->Argument); ResetTimer(pTimer); } else { uObjListRemoveNode(pTimer->ObjNode.Handle, &(pTimer->ObjNode)); uObjListAddNode(&(TimerList.ExpiredHandle), &(pTimer->ObjNode), eQuePosTail); pTimer->Status = eTimerExpired; } #else /* 在ISR里直接处理定时器回调事务 */ pTimer->Routine(pTimer->Argument); ResetTimer(pTimer); #endif } #if ((TCLC_IPC_ENABLE) && (TCLC_IPC_TIMER_ENABLE)) /* 如果定时器是线程阻塞类型的定时器(时限方式访问资源)则将线程从阻塞队列中唤醒 */ else if (pTimer->Type == eIpcTimer) { /* 将定时器从活动队列中移出,将定时器放到休眠队列里 */ uObjListRemoveNode(pTimer->ObjNode.Handle, &(pTimer->ObjNode)); uObjListAddNode(&(TimerList.DormantHandle), &(pTimer->ObjNode), eQuePosHead); pTimer->Status = eTimerDormant; /* IPC代码确保不会再次停止timer */ pThread = (TThread*)(pTimer->Owner); KNL_ASSERT((pThread->Status == eThreadBlocked), ""); uIpcUnblockThread(&(pThread->IpcContext), eFailure, IPC_ERR_TIMEO, &HiRP); } #endif else { uDebugPanic("", __FILE__, __FUNCTION__, __LINE__); } }