vs2008_ucos\uCOSII_port\os_cpu_c.c[part2] 移植ucosii在VS2008--part3
/***************************************************************************************************
* IDLE TASK HOOK
* Description: This function is called by the idle task. This hook has been added to allow you to do
* such things as STOP the CPU to conserve power.
* Arguments : none
* Note(s) : 1) Interrupts are enabled during this call.
***************************************************************************************************/
#if (OS_CPU_HOOKS_EN > 0) && (OS_VERSION >= 251)
void OSTaskIdleHook (void)
{
#if (OS_APP_HOOKS_EN > 0)
App_TaskIdleHook();
#endif
Sleep(1); /* Reduce CPU utilization. */
}
#endif
/***************************************************************************************************
* STATISTIC TASK HOOK
*
* Description: This function is called every second by uC/OS-II's statistics task. This allows your
* application to add functionality to the statistics task.
* Arguments : none
***************************************************************************************************/
#if (OS_CPU_HOOKS_EN > 0)
void OSTaskStatHook (void)
{
#if (OS_APP_HOOKS_EN > 0)
App_TaskStatHook();
#endif
}
#endif
/***************************************************************************************************
* 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 the
* highest valid address on 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.
***************************************************************************************************/
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_TASK_STK *pstack;
/* Load stack pointer */
pstack = (OS_TASK_STK *)((char*)ptos - sizeof(OS_TASK_STK));
pstack->TaskArgPtr = p_arg;
pstack->TaskOpt = opt;
pstack->Task = task;
pstack->ThreadHandle = NULL;
pstack->ThreadID = 0;
pstack->TaskState = STATE_NONE;
pstack->SignalPtr = NULL;
return ((void *)pstack);
}
/***************************************************************************************************
* TASK SWITCH HOOK
* Description: This function is called when a task switch is performed. This allows you to perform other
* operations during a context switch.
* Arguments : none
* Note(s) : 1) Interrupts are disabled during this call.
* 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the TCB of the task that
* will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the
* task being switched out (i.e. the preempted task).
***************************************************************************************************/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
void OSTaskSwHook (void)
{
#if (OS_APP_HOOKS_EN > 0)
App_TaskSwHook();
#endif
}
#endif
/***************************************************************************************************
* OS_TCBInit() HOOK
* Description: This function is called by OS_TCBInit() after setting up most of the TCB.
* Arguments : ptcb is a pointer to the TCB of the task being created.
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
* 2) Kernel objects must have unique names. Otherwise, a duplicate handle will be given for
* consecutive created objects. A GetLastError() ERROR_ALREADY_EXISTS can be checked when
* this case happens.
***************************************************************************************************/
#if (OS_CPU_HOOKS_EN > 0) && (OS_VERSION > 203)
void OSTCBInitHook (OS_TCB *ptcb)
{
OS_TASK_STK *pstack;
#if (OS_APP_HOOKS_EN > 0)
App_TCBInitHook(ptcb);
#else
(void)ptcb; /* Prevent compiler warning */
#endif
pstack = (OS_TASK_STK *)ptcb->OSTCBStkPtr;
pstack->SignalPtr = CreateEvent(NULL, FALSE, FALSE, NULL); /* See Note #2. */
if (pstack->SignalPtr == NULL) {
#if (OS_MSG_TRACE > 0)
OSPrintf("Task[%3.1d] cannot allocate signal event.\n", (CPU_INT16S)ptcb->OSTCBId);
#endif
return;
}
pstack->ThreadHandle = CreateThread(NULL, 0, OSTaskW32, ptcb, CREATE_SUSPENDED, &pstack->ThreadID);
if (pstack->ThreadHandle == NULL) {
#if (OS_MSG_TRACE > 0)
OSPrintf("Task[%3.1d] failed to be created.\n", (CPU_INT16S)ptcb->OSTCBId);
#endif
return;
}
pstack->TaskState = STATE_CREATED;
#if (OS_MSG_TRACE > 0)
OSPrintf("Task[%3.1d] created, Thread ID %5.0d\n", (CPU_INT16S)ptcb->OSTCBId, pstack->ThreadID);
#endif
if (SetThreadAffinityMask(pstack->ThreadHandle, 1) == 0) {
#if (OS_MSG_TRACE > 0)
OSPrintf("Error: SetThreadAffinityMask [Thread ID %5.0d] failed.\n", pstack->ThreadID);
#endif
}
}
#endif
/***************************************************************************************************
* TICK HOOK
* Description: This function is called every tick.
* Arguments : none
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
***************************************************************************************************/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)
void OSTimeTickHook (void)
{
#if (OS_APP_HOOKS_EN > 0)
App_TimeTickHook();
#endif
#if (OS_VERSION >= 281) && (OS_TMR_EN > 0)
OSTmrCtr++;
if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) {
OSTmrCtr = 0;
OSTmrSignal();
}
#endif
}
#endif
/***************************************************************************************************
* START HIGHEST PRIORITY TASK READY-TO-RUN
* Description: This function is called by OSStart() to start the highest priority task that was created
* by your application before calling OSStart().
* Arguments : none
* Note(s) : 1) OSStartHighRdy() MUST:
* a) Call OSTaskSwHook() then,
* b) Set OSRunning to TRUE,
* c) Switch to the highest priority task.
***************************************************************************************************/
void OSStartHighRdy (void)
{
OS_TASK_STK *pstack;
OS_TCB *ptcb;
INT8U prio;
INT8U ret;
OSTaskSwHook();
OSRunning = 1;
ResumeThread(OSTick_Thread); /* Start OSTick Thread. */
pstack = (OS_TASK_STK *)OSTCBHighRdy->OSTCBStkPtr; /* OSTCBCur = OSTCBHighRdy; */
/* OSPrioCur = OSPrioHighRdy; */
ResumeThread(pstack->ThreadHandle);
while (pstack->TaskState == STATE_CREATED) { /* Wait until task is ready to run. */
SwitchToThread();
}
SetEvent(pstack->SignalPtr);
WaitForSingleObject(OSTick_Thread, INFINITE); /* Wait until Tick thread has terminated. */
#if (TIMER_METHOD == WIN32_MM_TMR)
timeKillEvent(OSTick_TimerId);
timeEndPeriod(OSTick_TimerCap.wPeriodMin);
CloseHandle(OSTick_SignalPtr);
#endif
CloseHandle(OSTick_Thread);
CloseHandle(OSTerminate_SignalPtr);
#if (OS_MSG_TRACE > 0)
OSPrintf("\nDeleting uC/OS-II tasks...\n");
#endif
/* Delete all created tasks/threads. */
ptcb = OSTCBList;
while (ptcb != (OS_TCB *)0) {
if (ptcb != OS_TCB_RESERVED) {
#if (OS_MSG_TRACE > 0)
OSPrintf("Task[%3.1d] '%s' ", (CPU_INT16S)ptcb->OSTCBId, ptcb->OSTCBTaskName);
#endif
prio = ptcb->OSTCBPrio;
if (prio == OS_TASK_IDLE_PRIO) {
OSTaskDelHook(ptcb);
ret = OS_ERR_NONE;
ptcb = ptcb->OSTCBNext;
} else {
ptcb = ptcb->OSTCBNext;
ret = OSTaskDel(prio);
}
#if (OS_MSG_TRACE > 0)
if (ret == OS_ERR_NONE) {
OSPrintf("Deleted.\n");
} else {
OSPrintf("Failed to delete (%d).\n", ret);
}
#endif
} else {
ptcb = ptcb->OSTCBNext;
}
}
#if (CRITICAL_METHOD == WIN32_MUTEX)
CloseHandle(OSMutex);
#elif (CRITICAL_METHOD == WIN32_CRITICAL_SECTION)
DeleteCriticalSection(&OSCriticalSection);
#endif
#if (OS_MSG_TRACE > 0)
// OSDebuggerBreak();
#endif
}
/***************************************************************************************************
* CRITICAL SECTION FUNCTIONS
*
* Description : These functions are used to enter and exit critical sections.
*
* Argument(s) : none
***************************************************************************************************/
void OSCriticalEnter (void)
{
#if (CRITICAL_METHOD == WIN32_MUTEX)
DWORD ret;
#if (OS_MSG_TRACE > 0)
DWORD last_err;
LPTSTR pmsg;
OS_TCB *ptcb;
#endif
ret = WaitForSingleObject(OSMutex, INFINITE);
switch (ret) {
case WAIT_OBJECT_0:
default:
break;
#if (OS_MSG_TRACE > 0)
case WAIT_ABANDONED:
ptcb = OSTCBCur;
OSPrintf("Task[%3.1d] '%s' Enter Critical Section failed: Mutex abandoned by owning thread.\n", (CPU_INT16S)ptcb->OSTCBId, ptcb->OSTCBTaskName);
break;
case WAIT_TIMEOUT:
ptcb = OSTCBCur;
OSPrintf("Task[%3.1d] '%s' Enter Critical Section failed: Time-out interval elapsed.\n", (CPU_INT16S)ptcb->OSTCBId, ptcb->OSTCBTaskName);
break;
case WAIT_FAILED:
last_err = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
last_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&pmsg,
0,
NULL);
ptcb = OSTCBCur;
OSPrintf("Task[%3.1d] '%s' Enter Critical Section failed: %s.\n", (CPU_INT16S)ptcb->OSTCBId, ptcb->OSTCBTaskName, pmsg);
LocalFree(pmsg);
break;
#endif
}
#elif (CRITICAL_METHOD == WIN32_CRITICAL_SECTION)
EnterCriticalSection(&OSCriticalSection);
#endif
}
void OSCriticalExit (void)
{
#if (CRITICAL_METHOD == WIN32_MUTEX)
#if (OS_MSG_TRACE > 0)
DWORD last_err;
LPTSTR pmsg;
OS_TCB *ptcb;
#endif
if (ReleaseMutex(OSMutex) == 0) {
#if (OS_MSG_TRACE > 0)
last_err = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
last_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&pmsg,
0,
NULL);
ptcb = OSTCBCur;
OSPrintf("Task[%3.1d] '%s' Exit Critical Section failed: %s.\n", (CPU_INT16S)ptcb->OSTCBId, ptcb->OSTCBTaskName, pmsg);
LocalFree(pmsg);
#endif
}
#elif (CRITICAL_METHOD == WIN32_CRITICAL_SECTION)
LeaveCriticalSection(&OSCriticalSection);
#endif
}
/***************************************************************************************************
* TASK LEVEL CONTEXT SWITCH
* Description: This function is called when a task makes a higher priority task ready-to-run.
* Arguments : none
* Note(s) : 1) Upon entry,
* OSTCBCur points to the OS_TCB of the task to suspend
* OSTCBHighRdy points to the OS_TCB of the task to resume
* 2) OSCtxSw() MUST:
* a) Save processor registers then,
* b) Save current task's stack pointer into the current task's OS_TCB,
* c) Call OSTaskSwHook(),
* d) Set OSTCBCur = OSTCBHighRdy,
* e) Set OSPrioCur = OSPrioHighRdy,
* f) Switch to the highest priority task.
*
* pseudo-code:
* void OSCtxSw (void)
* {
* Save processor registers;
*
* OSTCBCur->OSTCBStkPtr = SP;
*
* OSTaskSwHook();
*
* OSTCBCur = OSTCBHighRdy;
* OSPrioCur = OSPrioHighRdy;
*
* Restore processor registers from (OSTCBHighRdy->OSTCBStkPtr);
* }
***************************************************************************************************/
void OSCtxSw (void)
{
OS_TASK_STK *pstack;
OS_TASK_STK *pstack_new;
#if (OS_MSG_TRACE > 0)
OS_TCB *ptcb_cur;
OS_TCB *ptcb_new;
ptcb_cur = OSTCBCur;
ptcb_new = OSTCBHighRdy;
#endif
pstack = (OS_TASK_STK *)OSTCBCur->OSTCBStkPtr;
OSTaskSwHook();
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
pstack->TaskState = STATE_SUSPENDED;
pstack_new = (OS_TASK_STK *)OSTCBHighRdy->OSTCBStkPtr;
switch (pstack_new->TaskState) {
case STATE_CREATED: /* TaskState updated to STATE_SUSPENDED once thread runs. */
ResumeThread(pstack_new->ThreadHandle);
while (pstack_new->TaskState == STATE_CREATED) { /* Wait until new task is ready to run. */
SwitchToThread();
}
/* Intentional fall through to STATE_SUSPENDED. */
case STATE_SUSPENDED:
pstack_new->TaskState = STATE_RUNNING;
SetEvent(pstack_new->SignalPtr);
OSCriticalExit();
WaitForSingleObject(pstack->SignalPtr, INFINITE);
break;
case STATE_INTERRUPTED:
pstack_new->TaskState = STATE_RUNNING;
ResumeThread(pstack_new->ThreadHandle);
OSCriticalExit();
WaitForSingleObject(pstack->SignalPtr, INFINITE);
break;
#if (OS_MSG_TRACE > 0)
case STATE_NONE:
OSPrintf("[OSCtxSw] Error: Invalid state STATE_NONE\nCur Task[%3.1d] Thread ID %5.0d: '%s'\nNew Task[%3.1d] Thread ID %5.0d: '%s'\n\n",
(CPU_INT16S)ptcb_cur->OSTCBId,
pstack->ThreadID,
ptcb_cur->OSTCBTaskName,
(CPU_INT16S)ptcb_new->OSTCBId,
pstack_new->ThreadID,
ptcb_new->OSTCBTaskName);
break;
case STATE_RUNNING:
OSPrintf("[OSCtxSw] Error: Invalid state STATE_RUNNING\nCur Task[%3.1d] Thread ID %5.0d: '%s'\nNew Task[%3.1d] Thread ID %5.0d: '%s'\n\n",
(CPU_INT16S)ptcb_cur->OSTCBId,
pstack->ThreadID,
ptcb_cur->OSTCBTaskName,
(CPU_INT16S)ptcb_new->OSTCBId,
pstack_new->ThreadID,
ptcb_new->OSTCBTaskName);
break;
case STATE_TERMINATING:
OSPrintf("[OSCtxSw] Error: Invalid state STATE_TERMINATING\nCur Task[%3.1d] Thread ID %5.0d: '%s'\nNew Task[%3.1d] Thread ID %5.0d: '%s'\n\n",
(CPU_INT16S)ptcb_cur->OSTCBId,
pstack->ThreadID,
ptcb_cur->OSTCBTaskName,
(CPU_INT16S)ptcb_new->OSTCBId,
pstack_new->ThreadID,
ptcb_new->OSTCBTaskName);
break;
case STATE_TERMINATED:
OSPrintf("[OSCtxSw] Error: Invalid state STATE_TERMINATED\nCur Task[%3.1d] Thread ID %5.0d: '%s'\nNew Task[%3.1d] Thread ID %5.0d: '%s'\n\n",
(CPU_INT16S)ptcb_cur->OSTCBId,
pstack->ThreadID,
ptcb_cur->OSTCBTaskName,
(CPU_INT16S)ptcb_new->OSTCBId,
pstack_new->ThreadID,
ptcb_new->OSTCBTaskName);
break;
#endif
default:
break;
}
OSCriticalEnter();
}