ISIX-RTOS - small operating system for ARM microcontrollers 1.2
|
00001 #include <isix/config.h> 00002 #include <isix/types.h> 00003 #include <prv/scheduler.h> 00004 #include <isix/task.h> 00005 #include <isix/memory.h> 00006 #include <prv/semaphore.h> 00007 #include <prv/multiple_objects.h> 00008 #include <string.h> 00009 00010 #ifndef ISIX_DEBUG_TASK 00011 #define ISIX_DEBUG_TASK ISIX_DBG_OFF 00012 #endif 00013 00014 00015 #if ISIX_DEBUG_TASK == ISIX_DBG_ON 00016 #include <isix/printk.h> 00017 #else 00018 #define isix_printk(...) 00019 #endif 00020 00021 /*-----------------------------------------------------------------------*/ 00022 //Align Mask 00023 #define ALIGN_MASK 0x03 00024 //Align Bytes 00025 #define ALIGN_BYTES 4 00026 //Magic value for stack checking 00027 #define MAGIC_FILL_VALUE 0x55 00028 /*-----------------------------------------------------------------------*/ 00029 /* Create task function */ 00030 task_t* isix_task_create(task_func_ptr_t task_func, void *func_param, unsigned long stack_depth, prio_t priority) 00031 { 00032 isix_printk("TaskCreate: Create task with prio %d",priority); 00033 if(isix_get_min_priority()< priority ) 00034 { 00035 return NULL; 00036 } 00037 //If stack length is small error 00038 if(stack_depth<ISIX_PORT_SCHED_MIN_STACK_DEPTH) return NULL; 00039 //Alignement 00040 if(stack_depth & ALIGN_MASK) 00041 { 00042 stack_depth += ALIGN_BYTES - (stack_depth & ALIGN_MASK); 00043 } 00044 //Allocate task_t structure 00045 task_t *task = (task_t*)isix_alloc(sizeof(task_t)); 00046 isix_printk("Alloc task struct %08x",task); 00047 //No free memory 00048 if(task==NULL) return NULL; 00049 //Zero task structure 00050 memset(task,0,sizeof(task_t)); 00051 //Try Allocate stack for task 00052 task->init_stack = isix_alloc(stack_depth); 00053 isix_printk("Alloc stack mem %08x",task->init_stack); 00054 if(task->init_stack==NULL) 00055 { 00056 //Free allocated stack memory 00057 isix_free(task); 00058 return NULL; 00059 } 00060 #ifdef ISIX_CONFIG_STACK_GROWTH 00061 task->top_stack = (unsigned long*)(((char*)task->init_stack) + stack_depth - sizeof(long)); 00062 #else 00063 task->top_stack = task->init_stack; 00064 #endif 00065 #if ISIX_CONFIG_TASK_STACK_CHECK==ISIX_ON 00066 memset(task->init_stack,MAGIC_FILL_VALUE,stack_depth); 00067 #endif 00068 isix_printk("Top stack SP=%08x",task->top_stack); 00069 //Assign task priority 00070 task->prio = priority; 00071 //Task is ready 00072 task->state = TASK_READY; 00073 //Create initial task stack context 00074 task->top_stack = isixp_task_init_stack(task->top_stack,task_func,func_param); 00075 //Lock scheduler 00076 isixp_enter_critical(); 00077 //Add task to ready list 00078 if(isixp_add_task_to_ready_list(task)<0) 00079 { 00080 //Free allocated innode 00081 isix_printk("Add task to ready list failed."); 00082 isix_free(task->top_stack); 00083 isix_free(task); 00084 isixp_exit_critical(); 00085 return NULL; 00086 } 00087 if(isix_scheduler_running==false) 00088 { 00089 //Scheduler not running assign task 00090 if(isix_current_task==NULL) isix_current_task = task; 00091 else if(isix_current_task->prio>task->prio) isix_current_task = task; 00092 } 00093 isixp_exit_critical(); 00094 if(isix_current_task->prio>task->prio && isix_scheduler_running==true) 00095 { 00096 //New task have higer priority then current task 00097 isix_printk("Call scheduler new prio %d > old prio %d",task->prio,isix_current_task->prio); 00098 isix_yield(); 00099 } 00100 return task; 00101 } 00102 00103 /*-----------------------------------------------------------------------*/ 00104 /*Change task priority function 00105 * task - task pointer structure if NULL current prio change 00106 * new_prio - new priority */ 00107 int isixp_task_change_prio(task_t *task,prio_t new_prio,bool yield) 00108 { 00109 if(isix_get_min_priority()< new_prio ) 00110 { 00111 return ISIX_ENOPRIO; 00112 } 00113 isixp_enter_critical(); 00114 task_t *taskc = task?task:isix_current_task; 00115 //Save task prio 00116 prio_t prio = taskc->prio; 00117 if(prio==new_prio) 00118 { 00119 isixp_exit_critical(); 00120 return ISIX_EOK; 00121 } 00122 bool yield_req = false; 00123 if(taskc->state & TASK_READY) 00124 { 00125 isix_printk("Change prio of ready task"); 00126 isixp_delete_task_from_ready_list(taskc); 00127 //Assign new prio 00128 taskc->prio = new_prio; 00129 //Add task to ready list 00130 if(isixp_add_task_to_ready_list(taskc)<0) 00131 { 00132 isixp_exit_critical(); 00133 return ISIX_ENOMEM; 00134 } 00135 if(new_prio<prio && !(isix_current_task->state&TASK_RUNNING) ) yield_req = true; 00136 } 00137 else if(taskc->state & TASK_WAITING) 00138 { 00139 isix_printk("Change prio of task waiting on sem"); 00140 list_delete(&taskc->inode_sem); 00141 //Assign new prio 00142 taskc->prio = new_prio; 00143 isixp_add_task_to_sem_list(&taskc->sem->sem_task,taskc); 00144 } 00145 isixp_exit_critical(); 00146 //Yield processor 00147 if(yield_req && yield) 00148 { 00149 isix_printk("CPUYield request"); 00150 isix_yield(); 00151 } 00152 isix_printk("New prio %d\n",new_prio); 00153 return ISIX_EOK; 00154 } 00155 00156 /*-----------------------------------------------------------------------*/ 00157 //Delete task pointed by struct task 00158 int isix_task_delete(task_t *task) 00159 { 00160 isixp_enter_critical(); 00161 task_t *taskd = task?task:isix_current_task; 00162 isix_printk("Task: %08x(SP %08x) to delete",task,taskd->init_stack); 00163 if(taskd->state & TASK_READY) 00164 { 00165 //Task is ready remove from read 00166 isixp_delete_task_from_ready_list(taskd); 00167 isix_printk("Remove from ready list\n"); 00168 } 00169 else if(taskd->state & TASK_SLEEPING) 00170 { 00171 //Task sleeping remove from sleeping 00172 list_delete(&taskd->inode); 00173 isix_printk("Remove from sleeping list"); 00174 } 00175 //Task waiting for sem remove from waiting list 00176 if(taskd->state & TASK_WAITING) 00177 { 00178 list_delete(&taskd->inode_sem); 00179 taskd->sem = NULL; 00180 isix_printk("Remove from sem list"); 00181 } 00182 #if ISIX_CONFIG_USE_MULTIOBJECTS 00183 if( taskd->state & TASK_WAITING_MULTIPLE ) 00184 { 00185 isixp_delete_from_multiple_wait_list( taskd ); 00186 isix_printk("Remove item from multiple list"); 00187 } 00188 #endif 00189 //Add task to delete list 00190 taskd->state = TASK_DEAD; 00191 isixp_add_task_to_delete_list(taskd); 00192 if(task==NULL || task==isix_current_task) 00193 { 00194 isixp_exit_critical(); 00195 isix_printk("Current task yield req"); 00196 isix_yield(); 00197 return ISIX_EOK; 00198 } 00199 else 00200 { 00201 isixp_exit_critical(); 00202 return ISIX_EOK; 00203 } 00204 } 00205 00206 /*-----------------------------------------------------------------------*/ 00207 //Get current thread handler 00208 task_t * isix_task_self(void) 00209 { 00210 task_t *t = isix_current_task; 00211 return t; 00212 } 00213 00214 /*-----------------------------------------------------------------------*/ 00215 //Stack check for fill value 00216 #if ISIX_CONFIG_TASK_STACK_CHECK == ISIX_ON 00217 00218 #ifndef ISIX_CONFIG_STACK_GROWTH 00219 #error isix_free_stack_space() for grown stack not implemented yet 00220 #endif 00221 00222 size_t isix_free_stack_space(const task_t *task) 00223 { 00224 size_t usage=0; 00225 unsigned char *bStack = (unsigned char*)task->init_stack; 00226 while(*bStack==MAGIC_FILL_VALUE) 00227 { 00228 bStack++; 00229 usage++; 00230 } 00231 return usage; 00232 } 00233 #endif 00234 /*-----------------------------------------------------------------------*/