ISIX-RTOS - small operating system for ARM microcontrollers 1.2
|
00001 #include <isix/types.h> 00002 #include <isix/config.h> 00003 #include <isix/memory.h> 00004 #include <prv/scheduler.h> 00005 #include <isix/semaphore.h> 00006 #include <prv/semaphore.h> 00007 #include <string.h> 00008 #include <prv/multiple_objects.h> 00009 00010 #ifndef ISIX_DEBUG_SEMAPHORE 00011 #define ISIX_DEBUG_SEMAPHORE ISIX_DBG_OFF 00012 #endif 00013 00014 00015 #if ISIX_DEBUG_SEMAPHORE == ISIX_DBG_ON 00016 #include <isix/printk.h> 00017 #else 00018 #define isix_printk(...) 00019 #endif 00020 00021 00022 /*--------------------------------------------------------------*/ 00023 //Create semaphore 00024 sem_t* isix_sem_create_limited(sem_t *sem, int val, int limit_val) 00025 { 00026 if(limit_val<0) 00027 { 00028 return NULL; 00029 } 00030 if(sem==NULL) 00031 { 00032 sem = (sem_t*)isix_alloc(sizeof(sem_t)); 00033 if(sem==NULL) return NULL; 00034 } 00035 memset(sem,0,sizeof(sem_t)); 00036 sem->static_mem = sem!=NULL?true:false; 00037 sem->value = val; 00038 sem->limit_value = limit_val; 00039 //Set sem type 00040 sem->type = IHANDLE_T_SEM; 00041 list_init(&sem->sem_task); 00042 isix_printk("Create sem %08x val %d",sem,sem->value); 00043 return sem; 00044 } 00045 00046 /*--------------------------------------------------------------*/ 00047 //Wait for semaphore P() 00048 //TODO: priority inheritance 00049 int isix_sem_wait(sem_t *sem, tick_t timeout) 00050 { 00051 //If nothing to to - exit 00052 if(sem==NULL && timeout==0) return ISIX_EINVARG; 00053 //Lock scheduler 00054 isixp_enter_critical(); 00055 isix_printk("Operate on task %08x state %02x",isix_current_task,isix_current_task->state); 00056 if(sem && sem->value>0) 00057 { 00058 sem->value--; 00059 isix_printk("Decrement value %d",sem->value); 00060 isixp_exit_critical(); 00061 return ISIX_EOK; 00062 } 00063 //If any task remove task from ready list 00064 if(timeout || sem) 00065 { 00066 if(isix_current_task->state & TASK_READY) 00067 { 00068 isix_current_task->state &= ~(TASK_READY| TASK_RUNNING ); 00069 isixp_delete_task_from_ready_list(isix_current_task); 00070 isix_printk("Delete task from ready list"); 00071 } 00072 } 00073 else 00074 { 00075 isixp_exit_critical(); 00076 return ISIX_EINVARG; 00077 } 00078 //Sleep in semaphore 00079 if(timeout) 00080 { 00081 //Add to waiting list 00082 isixp_add_task_to_waiting_list(isix_current_task,timeout); 00083 isix_current_task->state |= TASK_SLEEPING; 00084 isix_printk("Wait after %d ticks",isix_current_task->jiffies); 00085 } 00086 if(sem) 00087 { 00088 if(isix_current_task->sem) 00089 { 00090 isix_printk("OOPS task assigned to not empty sem %08x",isix_current_task->sem); 00091 isix_bug(); 00092 } 00093 isixp_add_task_to_sem_list(&sem->sem_task,isix_current_task); 00094 isix_current_task->state |= TASK_WAITING; 00095 isix_current_task->sem = sem; 00096 isix_printk("Add task %08x to sem",isix_current_task); 00097 } 00098 isixp_exit_critical(); 00099 isix_yield(); 00100 isix_printk("task %08x after wakeup reason %d", isix_current_task, 00101 (isix_current_task->state&TASK_SEM_WKUP)?ISIX_EOK:ISIX_ETIMEOUT); 00102 return (isix_current_task->state&TASK_SEM_WKUP)?ISIX_EOK:ISIX_ETIMEOUT; 00103 } 00104 /*--------------------------------------------------------------*/ 00105 #ifdef ISIX_CONFIG_USE_MULTIOBJECTS 00106 //Wakeup from iterate over muliple objects 00107 static int isixp_wakeup_multiple( task_t *task_wake ) 00108 { 00109 isix_printk("task state %02x",task_wake->state); 00110 //Remove from time list 00111 if(task_wake->state & TASK_SLEEPING) 00112 { 00113 list_delete(&task_wake->inode); 00114 task_wake->state &= ~TASK_SLEEPING; 00115 isix_printk("Remove task %08x from time list",task_wake ); 00116 } 00117 task_wake->state &= ~TASK_WAITING_MULTIPLE; 00118 task_wake->state |= TASK_READY | TASK_MULTIPLE_WKUP; 00119 if(isixp_add_task_to_ready_list(task_wake)<0) 00120 { 00121 return ISIX_ENOMEM; 00122 } 00123 return ISIX_EOK; 00124 } 00125 #endif 00126 /*--------------------------------------------------------------*/ 00127 //Sem signal V() 00128 int isixp_sem_signal( sem_t *sem, bool isr ) 00129 { 00130 //If not sem not release it 00131 if(!sem) 00132 { 00133 isix_printk("No sem"); 00134 return ISIX_EINVARG; 00135 } 00136 00137 isixp_enter_critical(); 00138 if(list_isempty(&sem->sem_task)==true) 00139 { 00140 sem->value++; 00141 if(sem->limit_value > ISIX_SEM_ULIMITED) 00142 { 00143 if(sem->value > sem->limit_value) 00144 { 00145 isix_printk("Limit value to %d",sem->value); 00146 sem->value = sem->limit_value; 00147 } 00148 } 00149 isix_printk("Waiting list is empty incval to %d",sem->value); 00150 #ifdef ISIX_CONFIG_USE_MULTIOBJECTS 00151 //Only for multiple objs 00152 { 00153 int ret = isixp_wakeup_multiple_waiting_tasks( sem, isixp_wakeup_multiple ); 00154 if(ret>0) 00155 { 00156 if(ret<isix_current_task->prio && !isr) 00157 { 00158 isix_printk("Yield processor higer prio wktask %d main %d",ret,isix_current_task->prio); 00159 isixp_exit_critical(); 00160 isix_yield(); 00161 isixp_enter_critical(); 00162 } 00163 } 00164 else { isixp_exit_critical(); return ret; } 00165 } 00166 #endif 00167 isixp_exit_critical(); 00168 return ISIX_EOK; 00169 } 00170 //List is not empty wakeup high priority task 00171 task_t *task_wake = list_get_first(&sem->sem_task,inode_sem,task_t); 00172 isix_printk("Task to wakeup %08x",task_wake); 00173 //Remove from time list 00174 if(task_wake->state & TASK_SLEEPING) 00175 { 00176 list_delete(&task_wake->inode); 00177 task_wake->state &= ~TASK_SLEEPING; 00178 } 00179 //Task in waiting list is always in waking state 00180 //Reschedule is needed wakeup task have higer prio then current prio 00181 if(!task_wake->sem) 00182 { 00183 isix_printk("OOPS sem is empty when sem is required"); 00184 isix_bug(); 00185 } 00186 if(task_wake->sem != sem) 00187 { 00188 isix_printk("This task is not assigned to valid sem"); 00189 isix_bug(); 00190 } 00191 task_wake->state &= ~TASK_WAITING; 00192 task_wake->state |= TASK_READY | TASK_SEM_WKUP; 00193 task_wake->sem = NULL; 00194 list_delete(&task_wake->inode_sem); 00195 if(isixp_add_task_to_ready_list(task_wake)<0) 00196 { 00197 isixp_exit_critical(); 00198 return ISIX_ENOMEM; 00199 } 00200 if(task_wake->prio<isix_current_task->prio && !isr) 00201 { 00202 isix_printk("Yield processor higer prio"); 00203 isixp_exit_critical(); 00204 isix_yield(); 00205 return ISIX_EOK; 00206 } 00207 else 00208 { 00209 isixp_exit_critical(); 00210 return ISIX_EOK; 00211 } 00212 } 00213 00214 /*--------------------------------------------------------------*/ 00215 //Get semaphore from isr 00216 int isix_sem_get_isr(sem_t *sem) 00217 { 00218 if(!sem) return ISIX_EINVARG; 00219 int res = ISIX_EBUSY; 00220 isixp_enter_critical(); 00221 if(sem && sem->value>0) 00222 { 00223 sem->value--; 00224 res = ISIX_EOK; 00225 } 00226 isixp_exit_critical(); 00227 return res; 00228 } 00229 00230 /*--------------------------------------------------------------*/ 00231 //Sem value of semaphore 00232 int isix_sem_setval(sem_t *sem, int val) 00233 { 00234 if(!sem) return ISIX_EINVARG; 00235 //Semaphore is used 00236 isixp_enter_critical(); 00237 if(list_isempty(&sem->sem_task)==false) 00238 { 00239 isixp_exit_critical(); 00240 return ISIX_EBUSY; 00241 } 00242 sem->value = val; 00243 if(sem->limit_value > ISIX_SEM_ULIMITED) 00244 { 00245 if(sem->value > sem->limit_value) 00246 { 00247 isix_printk("Limit value to %d",sem->value); 00248 sem->value = sem->limit_value; 00249 } 00250 } 00251 isixp_exit_critical(); 00252 return ISIX_EOK; 00253 } 00254 00255 /*--------------------------------------------------------------*/ 00256 //Get value of semaphore 00257 int isix_sem_getval(sem_t *sem) 00258 { 00259 if(!sem) return ISIX_EINVARG; 00260 isixp_enter_critical(); 00261 int v = sem->value; 00262 isixp_exit_critical(); 00263 return v; 00264 } 00265 00266 /*--------------------------------------------------------------*/ 00267 //Sem destroy 00268 int isix_sem_destroy(sem_t *sem) 00269 { 00270 if(!sem) return ISIX_EINVARG; 00271 //Semaphore is used 00272 isixp_enter_critical(); 00273 if(list_isempty(&sem->sem_task)==false) 00274 { 00275 isixp_exit_critical(); 00276 return ISIX_EBUSY; 00277 } 00278 if(!sem->static_mem) isix_free(sem); 00279 isixp_exit_critical(); 00280 return ISIX_EOK; 00281 } 00282 00283 /*--------------------------------------------------------------*/ 00285 tick_t isix_ms2tick(unsigned long ms) 00286 { 00287 tick_t ticks = (ISIX_CONFIG_HZ * ms)/1000UL; 00288 if(ticks==0) ticks++; 00289 return ticks; 00290 } 00291 00292 /*--------------------------------------------------------------*/ 00294 int isix_wait(tick_t timeout) 00295 { 00296 if(isix_scheduler_running) 00297 { 00298 //If scheduler is running delay on semaphore 00299 return isix_sem_wait(NULL,timeout); 00300 } 00301 else 00302 { 00303 //If scheduler is not running delay on busy wait 00304 tick_t t1 = isix_get_jiffies(); 00305 if(t1+timeout>t1) 00306 { 00307 t1+= timeout; 00308 while(t1>isix_get_jiffies()) port_idle_cpu(); 00309 } 00310 else 00311 { 00312 t1+= timeout; 00313 while(t1<isix_get_jiffies()) port_idle_cpu(); 00314 } 00315 return ISIX_EOK; 00316 } 00317 } 00318 00319 /*--------------------------------------------------------------*/ 00320