ISIX-RTOS - small operating system for ARM microcontrollers 1.2

semaphore.c

Go to the documentation of this file.
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 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines