/** * * @param attr */ void tnec_task_exit (TN_UWORD attr) { TN_UWORD tn_save_status_reg TN_UNUSED; /* for SR save */ TN_TCB_S *task; CDLL_QUEUE_S *que; TN_MUTEX_S *mutex; TN_UWORD *ptr_stack; if (tn_is_non_task_context()) return; tn_save_sr(); /* just for PIC24/dsPIC */ tn_disable_interrupt(); while (!is_queue_empty(&(tn_curr_run_task->mutex_queue))) { que = queue_remove_head(&(tn_curr_run_task->mutex_queue)); mutex = get_mutex_by_mutex_queue(que); do_unlock_mutex(mutex); } task = tn_curr_run_task; task_to_non_runnable(tn_curr_run_task); task_set_dormant_state(task); ptr_stack = tn_stack_init(task->task_func_addr, task->stk_start, task->stk_size, task->task_func_param ); task->task_stk = ptr_stack; if (task->activate_count > 0) { task->activate_count--; task_to_runnable(task); } else { /* Alex B. - delete task only if activate counter = 0 ! */ if (attr == TN_EXIT_AND_DELETE_TASK) { queue_remove_entry(&(task->create_queue)); tn_created_tasks_qty--; task->id_task = TN_ID_UNKNOWN; } } tn_switch_context_exit(tn_save_status_reg); /* Exit from task with restore saved SR*/ }
/** * * @param task * * @return TN_RETVAL */ TN_RETVAL tnec_task_iactivate (TN_TCB_S *task) { TN_UWORD tn_save_status_reg TN_UNUSED; TN_RETVAL rc; if (task == TN_NULL) return TERR_WRONG_PARAM; if (task->id_task != TN_ID_TASK) return TERR_NOEXS; if (tn_is_non_sys_int_context()) { return TERR_WCONTEXT; } tn_idisable_interrupt(); if (task->task_state == TSK_STATE_DORMANT) { task_to_runnable(task); if ((tn_next_task_to_run != tn_curr_run_task) && (tn_enable_switch_context != TN_FALSE)) { tn_context_switch_request = TN_TRUE; } tn_ienable_interrupt(); return TERR_NO_ERR; } else { if (task->activate_count == 0) { task->activate_count++; rc = TERR_NO_ERR; } else rc = TERR_OVERFLOW; } tn_ienable_interrupt(); return rc; }
//---------------------------------------------------------------------------- int tn_task_activate(TN_TCB * task) { TN_INTSAVE_DATA int rc; #if TN_CHECK_PARAM if(task == NULL) return TERR_WRONG_PARAM; if(task->id_task != TN_ID_TASK) return TERR_NOEXS; #endif TN_CHECK_NON_INT_CONTEXT tn_disable_interrupt(); if(task->task_state == TSK_STATE_DORMANT) { task_to_runnable(task); tn_enable_interrupt(); tn_switch_context(); return TERR_NO_ERR; } else { if(task->activate_count == 0) { task->activate_count++; rc = TERR_NO_ERR; } else rc = TERR_OVERFLOW; } tn_enable_interrupt(); return rc; }
//---------------------------------------------------------------------------- int tn_task_resume(TN_TCB * task) { TN_INTSAVE_DATA int rc; #if TN_CHECK_PARAM if(task == NULL) return TERR_WRONG_PARAM; if(task->id_task != TN_ID_TASK) return TERR_NOEXS; #endif TN_CHECK_NON_INT_CONTEXT tn_disable_interrupt(); if(!(task->task_state & TSK_STATE_SUSPEND)) rc = TERR_WSTATE; else { if(!(task->task_state & TSK_STATE_WAIT)) //- The task is not in the WAIT-SUSPEND state { task_to_runnable(task); tn_enable_interrupt(); tn_switch_context(); return TERR_NO_ERR; } else //-- Just remove TSK_STATE_SUSPEND from the task state { task->task_state &= ~TSK_STATE_SUSPEND; rc = TERR_NO_ERR; } } tn_enable_interrupt(); return rc; }
//---------------------------------------------------------------------------- int task_wait_complete(TN_TCB * task) //-- v. 2.6 { #ifdef USE_MUTEXES int fmutex; int curr_priority; TN_MUTEX * mutex; TN_TCB * mt_holder_task; CDLL_QUEUE * t_que; #endif int rc = FALSE; if(task == NULL) return 0; #ifdef USE_MUTEXES t_que = NULL; if(task->task_wait_reason == TSK_WAIT_REASON_MUTEX_I || task->task_wait_reason == TSK_WAIT_REASON_MUTEX_C) { fmutex = TRUE; t_que = task->pwait_queue; } else fmutex = FALSE; #endif task->pwait_queue = NULL; task->task_wait_rc = TERR_NO_ERR; if(task->tick_count != TN_WAIT_INFINITE) queue_remove_entry(&(task->timer_queue)); task->tick_count = TN_WAIT_INFINITE; if(!(task->task_state & TSK_STATE_SUSPEND)) { task_to_runnable(task); rc = TRUE; } else //-- remove WAIT state task->task_state = TSK_STATE_SUSPEND; #ifdef USE_MUTEXES if(fmutex) { mutex = get_mutex_by_wait_queque(t_que); mt_holder_task = mutex->holder; if(mt_holder_task != NULL) { //-- if task was blocked by another task and its pri was changed //-- - recalc current priority if(mt_holder_task->priority != mt_holder_task->base_priority && mt_holder_task->priority == task->priority) { curr_priority = find_max_blocked_priority(mutex, mt_holder_task->base_priority); set_current_priority(mt_holder_task, curr_priority); rc = TRUE; } } } #endif task->task_wait_reason = 0; //-- Clear wait reason return rc; }
//----------------------------------------------------------------------------- int tn_task_terminate(TN_TCB * task) { TN_INTSAVE_DATA int rc; /* see the structure purpose in tn_task_exit() */ struct // v.2.7 { #ifdef USE_MUTEXES CDLL_QUEUE * que; TN_MUTEX * mutex; #endif volatile int stack_exp[TN_PORT_STACK_EXPAND_AT_EXIT]; }data; #if TN_CHECK_PARAM if(task == NULL) return TERR_WRONG_PARAM; if(task->id_task != TN_ID_TASK) return TERR_NOEXS; #endif TN_CHECK_NON_INT_CONTEXT tn_disable_interrupt(); //-------------------------------------------------- rc = TERR_NO_ERR; if(task->task_state == TSK_STATE_DORMANT || tn_curr_run_task == task) rc = TERR_WCONTEXT; //-- Cannot terminate running task else { if(task->task_state == TSK_STATE_RUNNABLE) task_to_non_runnable(task); else if(task->task_state & TSK_STATE_WAIT) { //-- Free all queues, involved in the 'waiting' queue_remove_entry(&(task->task_queue)); //----------------------------------------- if(task->tick_count != TN_WAIT_INFINITE) queue_remove_entry(&(task->timer_queue)); } //-- Unlock all mutexes, locked by the task #ifdef USE_MUTEXES while(!is_queue_empty(&(task->mutex_queue))) { data.que = queue_remove_head(&(task->mutex_queue)); data.mutex = get_mutex_by_mutex_queque(data.que); do_unlock_mutex(data.mutex); } #endif task_set_dormant_state(task); //-- Pointer to task top of the stack when not running task->task_stk = tn_stack_init(task->task_func_addr, task->stk_start, task->task_func_param); if(task->activate_count > 0) //-- Cannot terminate { task->activate_count--; task_to_runnable(task); tn_enable_interrupt(); tn_switch_context(); return TERR_NO_ERR; } } tn_enable_interrupt(); return rc; }
//---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void tn_task_exit(int attr) { /* The structure is used to force GCC compiler properly locate and use 'stack_exp' - thanks to Angelo R. Di Filippo */ struct // v.2.7 { #ifdef USE_MUTEXES CDLL_QUEUE * que; TN_MUTEX * mutex; #endif TN_TCB * task; volatile int stack_exp[TN_PORT_STACK_EXPAND_AT_EXIT]; }data; TN_CHECK_NON_INT_CONTEXT_NORETVAL #ifdef TNKERNEL_PORT_MSP430X __disable_interrupt(); #else tn_cpu_save_sr(); //-- For ARM - disable interrupts without saving SPSR #endif //-------------------------------------------------- //-- Unlock all mutexes, locked by the task #ifdef USE_MUTEXES while(!is_queue_empty(&(tn_curr_run_task->mutex_queue))) { data.que = queue_remove_head(&(tn_curr_run_task->mutex_queue)); data.mutex = get_mutex_by_mutex_queque(data.que); do_unlock_mutex(data.mutex); } #endif data.task = tn_curr_run_task; task_to_non_runnable(tn_curr_run_task); task_set_dormant_state(data.task); //-- Pointer to task top of stack,when not running data.task->task_stk = tn_stack_init(data.task->task_func_addr, data.task->stk_start, data.task->task_func_param); if(data.task->activate_count > 0) //-- Cannot exit { data.task->activate_count--; task_to_runnable(data.task); } else // V 2.6 Thanks to Alex Borisov { if(attr == TN_EXIT_AND_DELETE_TASK) { queue_remove_entry(&(data.task->create_queue)); tn_created_tasks_qty--; data.task->id_task = 0; } } tn_switch_context_exit(); // interrupts will be enabled inside tn_switch_context_exit() }
//----------------------------------------------------------------------------- int tn_task_create(TN_TCB * task, //-- task TCB void (*task_func)(void *param), //-- task function int priority, //-- task priority unsigned int * task_stack_start, //-- task stack first addr in memory (bottom) int task_stack_size, //-- task stack size (in sizeof(void*),not bytes) void * param, //-- task function parameter int option) //-- Creation option { TN_INTSAVE_DATA int rc; unsigned int * ptr_stack; int i; //-- Light weight checking of system tasks recreation if((priority == 0 && ((option & TN_TASK_TIMER) == 0)) || (priority == TN_NUM_PRIORITY-1 && (option & TN_TASK_IDLE) == 0)) return TERR_WRONG_PARAM; if((priority < 0 || priority > TN_NUM_PRIORITY-1) || task_stack_size < TN_MIN_STACK_SIZE || task_func == NULL || task == NULL || task_stack_start == NULL || task->id_task != 0) //-- recreation return TERR_WRONG_PARAM; rc = TERR_NO_ERR; TN_CHECK_NON_INT_CONTEXT if(tn_system_state == TN_ST_STATE_RUNNING) tn_disable_interrupt(); //--- Init task TCB task->task_func_addr = (void*)task_func; task->task_func_param = param; task->stk_start = (unsigned int*)task_stack_start; //-- Base address of task stack space task->stk_size = task_stack_size; //-- Task stack size (in bytes) task->base_priority = priority; //-- Task base priority task->activate_count = 0; //-- Activation request count task->id_task = TN_ID_TASK; //-- Fill all task stack space by TN_FILL_STACK_VAL - only inside create_task for(ptr_stack = task->stk_start,i = 0;i < task->stk_size; i++) *ptr_stack-- = TN_FILL_STACK_VAL; task_set_dormant_state(task); //--- Init task stack ptr_stack = tn_stack_init(task->task_func_addr, task->stk_start, task->task_func_param); task->task_stk = ptr_stack; //-- Pointer to task top of stack, //-- when not running //-- Add task to created task queue queue_add_tail(&tn_create_queue,&(task->create_queue)); tn_created_tasks_qty++; if((option & TN_TASK_START_ON_CREATION) != 0) task_to_runnable(task); if(tn_system_state == TN_ST_STATE_RUNNING) tn_enable_interrupt(); return rc; }
//----------------------------------------------------------------------------- int tn_task_terminate(TN_TCB * task) { TN_INTSAVE_DATA int rc; unsigned int * ptr_stack; #ifdef USE_MUTEXES CDLL_QUEUE * que; TN_MUTEX * mutex; #endif volatile int stack_exp[TN_PORT_STACK_EXPAND_AT_EXIT]; #if TN_CHECK_PARAM if(task == NULL) return TERR_WRONG_PARAM; if(task->id_task != TN_ID_TASK) return TERR_NOEXS; #endif TN_CHECK_NON_INT_CONTEXT tn_disable_interrupt(); //-- To use stack_exp[] and avoid warning message stack_exp[0] = (int)tn_system_state; ptr_stack =(unsigned int *)stack_exp[0]; //-------------------------------------------------- rc = TERR_NO_ERR; if(task->task_state == TSK_STATE_DORMANT || tn_curr_run_task == task) rc = TERR_WCONTEXT; //-- Cannot terminate running task else { if(task->task_state == TSK_STATE_RUNNABLE) task_to_non_runnable(task); else if(task->task_state & TSK_STATE_WAIT) { //-- Free all queues, involved in the 'waiting' queue_remove_entry(&(task->task_queue)); //----------------------------------------- if(task->tick_count != TN_WAIT_INFINITE) queue_remove_entry(&(task->timer_queue)); } #if (TN_SUPPORT_FPU == 2) if (tn_fpu_owner_task == task) { tn_fpu_owner_task = NULL; } #endif //-- Unlock all mutexes, locked by the task #ifdef USE_MUTEXES while(!is_queue_empty(&(task->mutex_queue))) { que = queue_remove_head(&(task->mutex_queue)); mutex = get_mutex_by_mutex_queque(que); do_unlock_mutex(mutex); } #endif task_set_dormant_state(task); ptr_stack = tn_stack_init(task->task_func_addr, task->stk_start, task->task_func_param); task->task_stk = ptr_stack; //-- Pointer to task top of the stack //-- when not running if(task->activate_count > 0) //-- Cannot terminate { task->activate_count--; task_to_runnable(task); tn_enable_interrupt(); tn_switch_context(); return TERR_NO_ERR; } } tn_enable_interrupt(); return rc; }
//---------------------------------------------------------------------------- void tn_task_exit(int attr) { #ifdef USE_MUTEXES CDLL_QUEUE * que; TN_MUTEX * mutex; #endif TN_TCB * task; unsigned int * ptr_stack; volatile int stack_exp[TN_PORT_STACK_EXPAND_AT_EXIT]; TN_CHECK_NON_INT_CONTEXT_NORETVAL #ifdef TNKERNEL_PORT_MSP430X __disable_interrupt(); #else tn_cpu_save_sr(); //-- For ARM - disable interrupts without saving SPSR #endif //-- To use stack_exp[] and avoid warning message stack_exp[0] = (int)tn_system_state; ptr_stack =(unsigned int *)stack_exp[0]; //-------------------------------------------------- //-- Unlock all mutexes, locked by the task #ifdef USE_MUTEXES while(!is_queue_empty(&(tn_curr_run_task->mutex_queue))) { que = queue_remove_head(&(tn_curr_run_task->mutex_queue)); mutex = get_mutex_by_mutex_queque(que); do_unlock_mutex(mutex); } #endif task = tn_curr_run_task; task_to_non_runnable(tn_curr_run_task); task_set_dormant_state(task); ptr_stack = tn_stack_init(task->task_func_addr, task->stk_start, task->task_func_param); task->task_stk = ptr_stack; //-- Pointer to task top of stack,when not running if(task->activate_count > 0) //-- Cannot exit { task->activate_count--; task_to_runnable(task); } else // V 2.6 Thanks to Alex Borisov { if(attr == TN_EXIT_AND_DELETE_TASK) { queue_remove_entry(&(task->create_queue)); tn_created_tasks_qty--; task->id_task = 0; } } tn_switch_context_exit(); // interrupts will be enabled inside tn_switch_context_exit() }
/** * * @param timer_task_stack * @param timer_task_stack_size * @param idle_task_stack * @param idle_task_stack_size * @param app_in_cb * @param cpu_int_en * @param idle_user_cb */ void TN_NORETURN tnec_start_system(TN_UWORD *timer_task_stack, TN_UWORD timer_task_stack_size, TN_UWORD *idle_task_stack, TN_UWORD idle_task_stack_size, void (*app_in_cb)(void), void (*cpu_int_en)(void), void (*idle_user_cb)(void) ) { TN_WORD i; /* ToDo - initialize the sys log (if enabled) */ for (i = 0; i < TN_NUM_PRIORITY; i++) { queue_reset(&(tn_ready_list[i])); tn_tslice_ticks[i] = NO_TIME_SLICE; } queue_reset(&tn_create_queue); tn_created_tasks_qty = 0; tn_system_state = TN_ST_STATE_NOT_RUN; tn_enable_switch_context = TN_TRUE; tn_ready_to_run_bmp = 0; tn_context_switch_request = TN_FALSE; tn_sys_context = TN_CONTEXT_TASK; tn_next_task_to_run = TN_NULL; tn_curr_run_task = TN_NULL; queue_reset(&tn_locked_mutexes_list); queue_reset(&tn_blocked_tasks_list); queue_reset(&tn_wait_timeout_list); tnec_task_create((TN_TCB_S*)&tn_timer_task, tn_timer_task_func, 0, timer_task_stack, timer_task_stack_size, TN_NULL, TN_TASK_TIMER ); tnec_task_create((TN_TCB_S*)&tn_idle_task, tn_idle_task_func, (TN_NUM_PRIORITY - 1), idle_task_stack, idle_task_stack_size, TN_NULL, TN_TASK_IDLE ); task_to_runnable(&tn_idle_task); task_to_runnable(&tn_timer_task); tn_curr_run_task = &tn_idle_task; appl_init_callback = app_in_cb; cpu_interrupt_enbl_callback = cpu_int_en; idle_user_func_callback = idle_user_cb; tn_start_exe(); for(;;); /* for (;;);*/ }
/** * * @param task * * @return TN_RETVAL */ TN_RETVAL tnnc_task_terminate (TN_TCB_S *task) { TN_UWORD tn_save_status_reg TN_UNUSED; /* for SR save */ TN_RETVAL rc; TN_UWORD *ptr_stack; CDLL_QUEUE_S *que; TN_MUTEX_S *mutex; /* Not check parameter error if (task == TN_NULL) return TERR_WRONG_PARAM; */ if (task->id_task != TN_ID_TASK) return TERR_NOEXS; if (tn_is_non_task_context()) { return TERR_WCONTEXT; } tn_disable_interrupt(); rc = TERR_NO_ERR; if ((task->task_state == TSK_STATE_DORMANT) || (tn_curr_run_task == task)) { rc = TERR_WCONTEXT; } else { if (task->task_state == TSK_STATE_RUNNABLE) { task_to_non_runnable(task); } else if (task->task_state & TSK_STATE_WAIT) { queue_remove_entry(&(task->task_queue)); if (queue_contains_entry(&tn_blocked_tasks_list, &(task->block_queue))) { queue_remove_entry(&(task->block_queue)); } if (task->tick_count != TN_WAIT_INFINITE) { queue_remove_entry(&(task->timer_queue)); } } while (!is_queue_empty(&(task->mutex_queue))) { que = queue_remove_head(&(task->mutex_queue)); mutex = get_mutex_by_mutex_queue(que); do_unlock_mutex(mutex); } task_set_dormant_state(task); ptr_stack = tn_stack_init(task->task_func_addr, task->stk_start, task->stk_size, task->task_func_param ); task->task_stk = ptr_stack; if (task->activate_count > 0) { task->activate_count--; task_to_runnable(task); tn_enable_interrupt(); if ((tn_next_task_to_run != tn_curr_run_task) && (tn_enable_switch_context != TN_FALSE)) { tn_switch_context(); } return TERR_NO_ERR; } } tn_enable_interrupt(); return rc; }
//---------------------------------------------------------------------------- // TN main function (never return) //---------------------------------------------------------------------------- void tn_start_system(void) { int i; //-- Clear/set all globals (vars, lists, etc) for(i=0;i < TN_NUM_PRIORITY;i++) { queue_reset(&(tn_ready_list[i])); tn_tslice_ticks[i] = NO_TIME_SLICE; } queue_reset(&tn_create_queue); tn_created_tasks_qty = 0; tn_system_state = TN_ST_STATE_NOT_RUN; tn_ready_to_run_bmp = 0; tn_idle_count = 0; tn_curr_performance = 0; tn_next_task_to_run = NULL; tn_curr_run_task = NULL; //-- System tasks queue_reset(&tn_wait_timeout_list); //--- Timer task tn_task_create((TN_TCB*)&tn_timer_task, //-- task TCB tn_timer_task_func, //-- task function 0, //-- task priority &(tn_timer_task_stack //-- task stack first addr in memory [TN_TIMER_STACK_SIZE-1]), TN_TIMER_STACK_SIZE, //-- task stack size (in int,not bytes) NULL, //-- task function parameter TN_TASK_TIMER); //-- Creation option //--- Idle task tn_task_create((TN_TCB*)&tn_idle_task, //-- task TCB tn_idle_task_func, //-- task function TN_NUM_PRIORITY-1, //-- task priority &(tn_idle_task_stack //-- task stack first addr in memory [TN_IDLE_STACK_SIZE-1]), TN_IDLE_STACK_SIZE, //-- task stack size (in int,not bytes) NULL, //-- task function parameter TN_TASK_IDLE); //-- Creation option //-- Activate timer & idle tasks tn_next_task_to_run = &tn_idle_task; //-- Just for the task_to_runnable() proper op task_to_runnable(&tn_idle_task); task_to_runnable(&tn_timer_task); tn_curr_run_task = &tn_idle_task; //-- otherwise it is NULL //-- Run OS - first context switch tn_start_exe(); }