Task的创建与调度
Nucleus的系统入口函数是
- VOID INC_Initialize(VOID *first_available_memory)
- {
- 。。。。。。。。
- /* Invoke the application-supplied initialization function. */
- Application_Initialize(first_available_memory);
- /* Indicate that initialization is finished. */
- INC_Initialize_State = INC_END_INITIALIZE;
- /* Start scheduling threads of execution. */
- TCT_Schedule();
- }
Application_Initialize(first_available_memory);这个函数是留给平台用来初始化系统框架和创建task用的。
Task的创建一般如下
- if ( NU_Create_Task (&TaskTable[Handle].TaskCB.TCB, Name, os_TaskEntry,
- Handle, (VOID *)NULL,
- (void*)(TaskTable[Handle].Stack+1), (ULONG) StackSize, (UCHAR) Priority,
- #ifndef _TARGET_
- 10,
- #else
- 0,
- #endif
- NU_PREEMPT, NU_NO_START) != NU_SUCCESS )
- #define NU_Resume_Task TCCE_Create_Task
最关键的实现是
- status = TCC_Create_Task(task_ptr, name, task_entry, argc, argv,
- stack_address, stack_size, priority, time_slice, preempt, auto_start);
- ……
- /* Move input task pointer into internal pointer. */
- task = (TC_TCB *) task_ptr;
- /* Move input task pointer into internal pointer. */
- task = (TC_TCB *) task_ptr;
- …
- 填充TC_TCB结构体..
- /* Build a stack frame for this task by calling TCT_Build_Task_Stack. */
- TCT_Build_Task_Stack(task);
- 这个函数是根据arm平台thumb模式下填充arm的15个寄存器。
- ; Build an initial stack frame as follows:
- ;
- ; (Lower Address) Stack Top -> 1 (Interrupt stack type)
- ; CPSR Saved CPSR
- ; r0 Saved r0
- ; r1 Saved r1
- ; r2 Saved r2
- ; r3 Saved r3
- ; r4 Saved r4
- ; r5 Saved r5
- ; r6 Saved r6
- ; r7 Saved r7
- ; r8 Saved r8
- ; r9 Saved r9
- ; r10 Saved r10
- ; r11 Saved r11
- ; r12 Saved r12
- ; sp Saved sp
- ; lr Saved lr
- ; (Higher Address) Stack Bottom-> pc Saved pc
- /* Initialize the signal information of the task. */
- task -> tc_signals = 0;
- task -> tc_enabled_signals = 0;
- task -> tc_signal_handler = 0;
- task -> tc_signal_active = NU_FALSE;
- /* Initialize additional kernel options data */
- #if (NU_SUPERV_USER_MODE == 1)
- task->tc_su_mode = 0; /* Initially in User mode */
- task->tc_module = 0; /* Not initially bound to a module */
- #endif
- 在初始化该task的timer
- /* Initialize the task timer. */
- task -> tc_timer_active = NU_FALSE;
- TMC_Init_Task_Timer(&(task -> tc_timer_control), (VOID *) task);
- /* Protect the list of created tasks. */
- TCT_Protect(&TCD_List_Protect);
- /* At this point the task is completely built. The ID can now be
- set and it can be linked into the created task list. */
- task -> tc_id = TC_TASK_ID;
- 将task放到相应的list中
- /* Link the task into the list of created tasks and increment the
- total number of tasks in the system. */
- CSC_Place_On_List(&TCD_Created_Tasks_List, &(task -> tc_created));
- TCD_Total_Tasks++;
- 如果创建参数是需要自动运行的,就通过resume来start task。
- .......
Nucleus的task调度
- ;VOID TCT_Schedule(VOID)
- .def _TCT_Schedule
- _TCT_Schedule
- …..
- ; Get the addresses of the HISR and Task to execute
- LDR r2,TCT_Execute_HISR
- //TCT_Execute_HISR是已经准备好需要运行的HISR
- LDR r3,TCT_Execute_Task
- //TCT_Execute_Task是已经准备好需要运行的Task
- .if NU_PROFILE_PLUS
- ; Check to see if there is a task to execute upon entering TCT_Schedule.
- ; If not, we start IDLE.
- //先查询是否有HISR需要运行,其运行是同task一样的流程
- LDR r0,[r2] ; Pickup highest priority HISR ptr
- CMP r0,#0 ; Is there a HISR active?
- BNE TCT_Schedule_Thread ; Found an HISR
- //如果没有HISR需运行,就查询task。
- LDR r0,[r3] ; Pickup highest priority Task ptr
- CMP r0,#0 ; Is there a task active?
- BNE TCT_Schedule_Thread ; If not, start IDLE.
- //如果也没有就开始loop,一直查询.
- STMDB sp!,{r2-r3} ; Save r2-r3
- BL __NU_Idle_Hook
- LDMIA sp!,{r2-r3} ; Restore r2-r3
- .endif
- .def TCT_Schedule_Loop
- TCT_Schedule_Loop
- ; Wait until a thread (task or HISR) is available to execute.
- ; When a thread is available, branch to TCT_Schedule_Thread.
- LDR r0,[r2] ; Pickup highest priority HISR ptr
- CMP r0,#0 ; Is there a HISR active?
- BNE TCT_Schedule_Thread ; Found a HISR
- LDR r0,[r3] ; Pickup highest priority Task ptr
- CMP r0,#0 ; Is there a task active?
TCT_Schedule_Thread中主要是调用TCT_Control_To_Thread
TCT_Control_To_Thread先判断该task的时间片是否为0,然后设置时间片状态。
- ; Pickup the thread's stack pointer and resume the thread.
- LDR sp,[r0, #TC_STACK_POINTER]
- ; Pop off the stack top to determine stack type
- LDR r1,[sp], #4
- ; Remove CPSR from stack and put in SPSR
- LDR r0,[sp], #4 ; Pop off the CPSR
- MSR SPSR,r0 ; Place it into the SPSR
- //以上偏移是根据创建时的各个位的定义
- ; Check if interrupt stack or solicited stack
- //r1此时存的为上次中断的类型
- CMP r1,#1 ; Compare stack type with 1
- BEQ TCT_Interrupt_Resume ; If equal to 1, interrupt stack frame
- ; Recover all solicited stack frame registers and return
- //将task堆栈中存的上次中断时arm的各个寄存器的值复位就恢复了task的运行,和被中断前一样
- LDMIA sp!,{r4-r12,pc}^ ; A solicited return is required.
- ; This type of return only
- ; Recovers r4-r12 & pc
- TCT_Interrupt_Resume
- ; Recover all registers and resume at point of interrupt
- LDMIA sp,{r0-pc}^