====== TNKernel : Tasks ====== ===== Introduction ===== In TNKernel, a task is a branch of the code that runs concurrently with another tasks from the programmer's point of view. At the physical level, tasks are actually executed using processor time sharing. Each task can be considered to be an independed program, which executes in its own context (processor registers, stack pointer, etc.). When the currently running task loses its claim for executing (by the issuing of a system call or interrupt), a context switch is performed. The current context (processor registers, stack pointer, etc.) is saved and the context of another task is restored. This mechanism in the TNKernel is called the "dispatcher". Generally, there are more than one executable task, and it is necessary to determine the order of the task switching (execution) by using some rules. "Scheduler" is a mechanism that controls the order of the task execution. TNKernel uses a priority-based scheduling based on a priority level assigned to the each task. The smaller the value of the priority, the higher the priority level. TNKernel uses a **16** levels of priority for PIC24/dsPIC port and 32 levels for original ARM version. Priorities **0** (highest) and **15**(31) (lowest) are reserved by the system for the internal using. The user may create tasks with priorities from **1** to **14**(30). In TNKernel, more than one task can have the same (identical) priority. ~~UP~~ ===== Task States ===== There are four task states in TNKernel: ; ''RUNNING'' : The task is currently executing ; ''READY'' : The task is ready to execute, but cannot do so because a task with higher priority (sometimes same priority) is already executing. A task may execute at any time once the processor becomes available. In TNKernel, both ''RUNNING'' and ''READY'' states are marked as ''RUNNABLE'' ; ''WAIT/SUSPEND'' : When a task is in the WAIT/SUSPEND state, the task cannot execute because the conditions necessary for its execution have not yet been met and the task is waiting for them. When a task enters the WAIT/SUSPEND state, the task's context is saved. When the task resumes execution from the WAIT/SUSPEND state, the task's context is restored. ''WAIT/SUSPEND'' actually have one of three types: {| class = "fpl" |- | ''WAITING'' | The task execution is blocked until some synchronization action occurs, such as timeout expiration, semaphore available, event occurring, etc. |- | ''SUSPENDED'' | The task is forced to be blocked (switched to the non-executing state) by another task or itself |- | ''WAITING_SUSPENDED'' | Both WAITING and SUSPENDED states co-exist. In TNKernel, if a task leaves a ''WAITING'' state, but a ''SUSPENDED'' state exists, the task is not switched to the ''READY/RUNNING'' state. Similarly, if a task leaves ''SUSPENDED'' state, but a ''WAITING'' state exists, the task is not switched to the ''READY/RUNNING'' state. A task is switched to ''READY/RUNNING'' state only if there are neither ''WAITING'' nor ''SUSPENDED'' states flagged on it. |} ; ''DORMANT'' : The task has been initialized and it is not yet executing or it has already exited. Newly created tasks always begin in this state. \\ One especial state when the task is not created/initialized yet is ''NON-EXISTENT''. The following picture describe the task states switching rules: {{ tnkernel:ref:task:tn_task_states_diagram.png }} The API fuctions that prompts for a state switsh is shown near the switch direction. For simply prefix ''tn_task_'' and prefix ''i'' (call from interrupt) is dropped. ~~UP~~ ===== Scheduling rules ===== In TNKernel, as long as the highest privilege task is running, no other task will execute unless the highest privilege task cannot execute (for instance, for being placed in the ''WAITING'' state). Among tasks with //different priorities//, the task with the highest priority is the highest privilege task and will execute. Among tasks of the //same priority//, the task that entered into the runnable (''RUNNING'' or ''READY'') state first is the highest privilege task and will execute. > Example: Task A has priority 1, tasks B, C, D, E have priority 3, tasks F,G have priority 4, task I has priority 5. If all tasks are in the READY state, this is the sequence of tasks executing : \\ > 1. Task A - highest priority (priority 1) > 2. Tasks B, C, D, E - in order of entering into runnable state for this priority (priority 3) > 3. Tasks F, G - in order of entering into runnable state for this priority (priority 4) > 4. Task I - lowest priority (priority 5) In TNKernel, tasks with the same priority may be scheduled in round robin fashion by getting a predetermined time slice for each task with this priority. ===== System Tasks ===== In TNKernel, the task (''timer_task'') with priority 0 (highest) is used for supporting the system tick timer functionality and the task (''idle_task'') with priority 15(31) (lowest) is used for performing statistics. TNKernel automatically creates these tasks at the system start. ===== Task Control Block ===== Each task has an associated task control block (TCB), defined as: typedef struct TN_TCB_S_STRUCT { TN_UWORD * task_stk; CDLL_QUEUE_S task_queue; CDLL_QUEUE_S timer_queue; CDLL_QUEUE_S block_queue; CDLL_QUEUE_S create_queue; CDLL_QUEUE_S mutex_queue; CDLL_QUEUE_S * pwait_queue; struct TN_TCB_S_STRUCT * blk_task; TN_UWORD * stk_start; TN_UWORD stk_size; void * task_func_addr; void * task_func_param; TN_UWORD base_priority; TN_UWORD priority; TN_UWORD id_task; TN_WORD task_state; TN_UWORD task_wait_reason; TN_WORD task_wait_rc; TN_UWORD tick_count; TN_UWORD tslice_count; TN_UWORD ewait_pattern; TN_UWORD ewait_mode; void * data_elem; TN_UWORD activate_count; TN_UWORD wakeup_count; TN_UWORD suspend_count; } TN_TCB_S; {| class = "fpl" |- | ''task_stk'' | Pointer to the task's top of stack |- | ''task_queue'' | Queue to include task in the ready/wait lists |- | ''timer_queue'' | Queue to include task in the timer(timeout,etc.) list |- | ''block_queue'' | Queue to include task in the blocked task list only used for mutexes priority ceiling protocol |- | ''create_queue'' | Queue is used to include task in create list only |- | ''mutex_queue'' | List of all mutexes locked by the tack |- | ''pwait_queue'' | Ptr to the object's (semaphor,event,etc.) wait list, the task is waiting for |- | ''blk_task'' | Store task blocking our task (for the mutexes priority ceiling protocol only) |- | ''stk_start'' | Base address of the task's stack space |- | ''stk_size'' | The task stack size (in sizeof (void*), not bytes) |- | ''task_func_addr'' | The task function pointer |- | ''task_func_param'' | The task function parameter pointer |- | ''base_priority'' | Task base priority |- | ''priority'' | Task current priority |- | ''id_task'' | ID for verification |- | ''task_state'' | Task state |- | ''task_wait_reason'' | Reason for the waiting |- | ''task_wait_rc'' | Waiting return code (reason why waiting finished) |- | ''tick_count'' | Remaining time until timeout |- | ''tslice_count'' | Time slice counter |- | ''ewait_pattern'' | Event wait pattern |- | ''ewait_mode'' | Event wait mode: _AND or _OR |- | ''data_elem'' | Location to store data queue entry, if the data queue is full |- | ''activate_count'' | Activation request count |- | ''wakeup_count'' | Wakeup request count |- | ''suspend_count'' | Suspension count - for statistic |} Task Control Block is available only when ''TN_DEBUG'' defined. Nevertheless direct access to Task Control Block is not recommend for the system safety. ~~UP~~ ===== Task API ===== TNKernel has the following API functions for control tasks: ^ Function ^ Description ^ | **Creata and delete task** || | \ \ [[en:tnkernel:ref:task:tn_task_create|tn_task_create()]] | Create task | | \ \ [[en:tnkernel:ref:task:tn_task_delete|tn_task_delete()]] | Delete task | | **Reset task** || | \ \ [[en:tnkernel:ref:task:tn_task_exit|tn_task_exit()]] | Exit from the current task | | \ \ [[en:tnkernel:ref:task:tn_task_terminate|tn_task_terminate()]] | Terminate task | | \ \ [[en:tnkernel:ref:task:tn_task_activate|tn_task_activate()]] | Activate task | | \ \ [[vtnkernel:ref:task:tn_task_iactivate|tn_task_iactivate()]] | Activate task from interrupt | | **Suspend and resume task** || | \ \ [[en:tnkernel:ref:task:tn_task_suspend|tn_task_suspend()]] | Suspend task | | \ \ [[en:tnkernel:ref:task:tn_task_isuspend|tn_task_isuspend()]] | Suspend task from interrupt | | \ \ [[en:tnkernel:ref:task:tn_task_resume|tn_task_resume()]] | Resume task | | \ \ [[en:tnkernel:ref:task:tn_task_iresume|tn_task_iresume()]] | Resume task from interrupt | | **Sleep and wakeup task** || | \ \ [[en:tnkernel:ref:task:tn_task_sleep|tn_task_sleep()]] | Sleep task | | \ \ [[en:tnkernel:ref:task:tn_task_wakeup|tn_task_wakeup()]] | Wakeup task | | \ \ [[en:tnkernel:ref:task:tn_task_iwakeup|tn_task_iwakeup()]] | Wakeup task from interrupt | | **Forced release from ''WAITING''** || | \ \ [[en:tnkernel:ref:task:tn_task_release_wait|tn_task_release_wait()]] | Forced release from ''WAITING'' state | | \ \ [[vtnkernel:ref:task:tn_task_irelease_wait|tn_task_irelease_wait()]] | Forced release from ''WAITING'' state in interrupt | | **Change task priority** || | \ \ [[en:tnkernel:ref:task:tn_task_change_priority|tn_task_change_priority()]] | Change task priority | | **Get task reference** || | \ \ [[en:tnkernel:ref:task:tn_task_reference|tn_task_reference()]] | Get task reference | | \ \ [[en:tnkernel:ref:task:tn_task_ireference|tn_task_ireference()]] | Get task reference from interrupt | ~~UP~~