POK(kernelpart)
/home/jaouen/pok_official/pok/trunk/kernel/core/lockobj.c
Go to the documentation of this file.
00001 /*
00002  *                               POK header
00003  * 
00004  * The following file is a part of the POK project. Any modification should
00005  * made according to the POK licence. You CANNOT use this file or a part of
00006  * this file is this part of a file for your own project
00007  *
00008  * For more information on the POK licence, please see our LICENCE FILE
00009  *
00010  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
00011  *
00012  *                                      Copyright (c) 2007-2009 POK team 
00013  *
00014  * Created by julien on Thu Jan 15 23:34:13 2009 
00015  */
00016 
00028 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING)
00029 
00030 #include <arch.h>
00031 #include <errno.h>
00032 #include <types.h>
00033 #include <core/sched.h>
00034 #include <core/time.h>
00035 #include <core/partition.h>
00036 #include <core/thread.h>
00037 #include <core/lockobj.h>
00038 #include <libc.h>
00039 
00040 pok_lockobj_t           pok_partitions_lockobjs[POK_CONFIG_NB_LOCKOBJECTS+1];
00041 
00045 pok_ret_t pok_lockobj_init ()
00046 {
00047 #if POK_CONFIG_NB_LOCKOBJECTS > 0
00048    uint8_t i;
00049 
00050 #ifdef POK_NEEDS_PARTITIONS
00051 #ifdef POK_NEEDS_ERROR_HANDLING
00052    uint32_t total_lockobjects;
00053 
00054    total_lockobjects = 0;
00055 
00056    for ( i = 0 ; i < POK_CONFIG_NB_PARTITIONS ; i++)
00057    {
00058       total_lockobjects = total_lockobjects + pok_partitions[i].nlockobjs;
00059    }
00060    
00061    if (total_lockobjects != POK_CONFIG_NB_LOCKOBJECTS)
00062    {
00063       pok_kernel_error (POK_ERROR_KIND_KERNEL_CONFIG);
00064    }
00065 #endif
00066 #endif
00067 
00068    for ( i = 0 ; i < POK_CONFIG_NB_LOCKOBJECTS ; i++)
00069    {
00070       pok_partitions_lockobjs[i].spin        = 0;
00071       pok_partitions_lockobjs[i].is_locked   = FALSE;
00072       pok_partitions_lockobjs[i].initialized = FALSE;
00073    }
00074 #endif
00075    return POK_ERRNO_OK;
00076 }
00077 
00078 
00079 pok_ret_t pok_lockobj_create (pok_lockobj_t* obj, const pok_lockobj_attr_t* attr)
00080 {
00081    uint32_t tmp;
00082 
00083    /* Check the policy of the lockobj */
00084    if ((attr->locking_policy != POK_LOCKOBJ_POLICY_STANDARD) && (attr->locking_policy != POK_LOCKOBJ_POLICY_PIP) && (attr->locking_policy != POK_LOCKOBJ_POLICY_PCP))
00085    {
00086       return POK_ERRNO_LOCKOBJ_POLICY;
00087    }
00088    
00089    /* Check the kind of the locjobj, must have a declared kind
00090     * If not, of course, we reject the creation.
00091     */
00092    if ((attr->kind != POK_LOCKOBJ_KIND_MUTEX) && (attr->kind != POK_LOCKOBJ_KIND_SEMAPHORE) && (attr->kind != POK_LOCKOBJ_KIND_EVENT))
00093    {
00094       return POK_ERRNO_LOCKOBJ_KIND;
00095    }
00096 
00097    for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++ )
00098    {
00099       obj->thread_state [tmp] = LOCKOBJ_STATE_UNLOCK;
00100    }
00101  
00102    obj->queueing_policy = attr->queueing_policy;
00103    obj->locking_policy  = attr->locking_policy;
00104    obj->kind            = attr->kind;
00105    obj->initialized     = TRUE;
00106 
00107    if (attr->kind == POK_LOCKOBJ_KIND_SEMAPHORE)
00108    {
00109       obj->current_value = attr->initial_value;
00110       obj->max_value     = attr->max_value;
00111       
00112       if (obj->current_value == 0)
00113       {
00114          obj->is_locked = TRUE;
00115       }
00116    }
00117 
00118    return POK_ERRNO_OK;
00119 }
00120 
00121 #ifdef POK_NEEDS_LOCKOBJECTS
00122 pok_ret_t pok_lockobj_partition_create (pok_lockobj_id_t* id, const pok_lockobj_attr_t* attr)
00123 {
00124    uint8_t i;
00125    uint8_t pid;
00126    uint8_t mid;
00127    pok_ret_t ret;
00128    uint8_t lower_bound = 0;
00129    uint8_t upper_bound = 0;
00130    bool_t  found = FALSE;
00131 
00132    if (  (POK_CURRENT_PARTITION.mode != POK_PARTITION_MODE_INIT_COLD) &&
00133          (POK_CURRENT_PARTITION.mode != POK_PARTITION_MODE_INIT_WARM))
00134    {
00135       return POK_ERRNO_MODE;
00136    }
00137    
00138    pid = POK_SCHED_CURRENT_PARTITION;
00139 
00140    lower_bound = pok_partitions[pid].lockobj_index_low;
00141    upper_bound = pok_partitions[pid].lockobj_index_high;
00142 
00143    /*
00144     * Find a lockobject for the partition
00145     */
00146    mid = lower_bound;
00147    while (mid < upper_bound)
00148    {
00149       if (pok_partitions_lockobjs[mid].initialized == FALSE)
00150       {
00151          found = TRUE; /* Yeeepeee, we found a free lockobj for this partition */
00152          break;
00153       }
00154       mid++;
00155    }
00156 
00157    if (found == FALSE)
00158    {
00159       return POK_ERRNO_LOCKOBJ_UNAVAILABLE;
00160    }
00161 
00162    *id = mid;
00163 
00164    ret = pok_lockobj_create (&pok_partitions_lockobjs[mid], attr);
00165 
00166    if (ret != POK_ERRNO_OK)
00167    {
00168       return ret;
00169    }
00170 
00171    for (i = 0 ; i < POK_CONFIG_NB_THREADS ; i++)
00172    {
00173       pok_partitions_lockobjs[mid].thread_state[i] = LOCKOBJ_STATE_UNLOCK;
00174    }
00175 
00176    return POK_ERRNO_OK;
00177 }
00178 #endif
00179 
00180 pok_ret_t pok_lockobj_eventwait (pok_lockobj_t* obj, const uint64_t timeout)
00181 {
00182    pok_ret_t ret;
00183 
00184    SPIN_LOCK (obj->eventspin);
00185 
00186    if (obj->initialized == FALSE)
00187    {
00188       return POK_ERRNO_LOCKOBJ_NOTREADY;
00189    }
00190 
00191    if (obj->kind != POK_LOCKOBJ_KIND_EVENT)
00192    {
00193       return POK_ERRNO_EINVAL;
00194    }
00195 
00196    if (pok_lockobj_unlock (obj, NULL))
00197    {
00198       SPIN_UNLOCK (obj->eventspin);
00199       return POK_ERRNO_UNAVAILABLE;
00200    }
00201 
00202    obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_WAITEVENT;
00203 
00204    if (timeout > 0)
00205    {
00206       pok_sched_lock_current_thread_timed (timeout);
00207    }
00208    else
00209    {
00210       pok_sched_lock_current_thread ();
00211    }
00212 
00213    SPIN_UNLOCK (obj->eventspin);
00214    pok_sched ();
00215    obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
00216 
00217    ret = pok_lockobj_lock (obj, NULL);
00218 
00219    if (ret != POK_ERRNO_OK)
00220    {
00221       SPIN_UNLOCK (obj->eventspin);
00222       return ret;
00223    }
00224 
00225    /* Here, we come back after we wait*/
00226    if ((timeout != 0 ) && (POK_GETTICK() >= timeout))
00227    {
00228       ret = POK_ERRNO_TIMEOUT;
00229    }
00230    else
00231    {
00232       ret = POK_ERRNO_OK;
00233    }
00234 
00235    SPIN_UNLOCK (obj->eventspin);
00236 
00237    return ret;
00238 }
00239 
00240 pok_ret_t pok_lockobj_eventsignal (pok_lockobj_t* obj)
00241 {
00242    SPIN_LOCK (obj->eventspin);
00243    uint32_t tmp;
00244 
00245    for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++)
00246    {
00247       if (tmp == POK_SCHED_CURRENT_THREAD)
00248          continue;
00249       
00250       if (obj->thread_state[tmp] == LOCKOBJ_STATE_WAITEVENT)
00251       {
00252          pok_sched_unlock_thread (tmp);
00253          SPIN_UNLOCK (obj->eventspin);
00254          return POK_ERRNO_OK;
00255       }
00256  
00257    }
00258    SPIN_UNLOCK (obj->eventspin);
00259    return POK_ERRNO_NOTFOUND;
00260 }
00261 
00262 pok_ret_t pok_lockobj_eventbroadcast (pok_lockobj_t* obj)
00263 {
00264    uint32_t tmp;
00265    SPIN_LOCK (obj->eventspin);
00266 
00267    for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++)
00268    {
00269       if (tmp == POK_SCHED_CURRENT_THREAD)
00270          continue;
00271       
00272       if (obj->thread_state[tmp] == LOCKOBJ_STATE_WAITEVENT)
00273       {
00274          pok_sched_unlock_thread (tmp);
00275       }
00276  
00277    }
00278 
00279    SPIN_UNLOCK (obj->eventspin);
00280 
00281    return POK_ERRNO_OK;
00282 }
00283 
00284 
00285 pok_ret_t pok_lockobj_lock (pok_lockobj_t* obj, const pok_lockobj_lockattr_t* attr)
00286 {
00287    uint64_t timeout = 0;
00288 
00289    if (obj->initialized == FALSE)
00290    {
00291       return POK_ERRNO_LOCKOBJ_NOTREADY;
00292    }
00293    
00294    SPIN_LOCK (obj->spin);
00295 
00296    if ( (obj->is_locked == FALSE ) && (obj->thread_state[POK_SCHED_CURRENT_THREAD] == LOCKOBJ_STATE_UNLOCK ))
00297    {
00298       obj->is_locked = TRUE;
00299       SPIN_UNLOCK (obj->spin);
00300    }
00301    else
00302    {
00303       /*
00304        * attr->time corresponds to the timeout for the waiting object
00305        */
00306       if ((attr != NULL) && (attr->time > 0))
00307       {
00308          timeout = attr->time;
00309       }
00310 
00311       while ( (obj->is_locked == TRUE ) || (obj->thread_state[POK_SCHED_CURRENT_THREAD] == LOCKOBJ_STATE_LOCK)) 
00312       {
00313          obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_LOCK;
00314 
00315          if (timeout > 0)
00316          {
00317             pok_sched_lock_current_thread_timed (timeout);
00318             if (POK_GETTICK() >= timeout)
00319             {
00320                obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
00321                return POK_ERRNO_TIMEOUT;
00322             }
00323          }
00324          else
00325          {
00326             pok_sched_lock_current_thread ();
00327          }
00328          
00329          SPIN_UNLOCK (obj->spin);
00330          pok_sched();     /* reschedule baby, reschedule !! */
00331       }
00332       
00333       switch (obj->kind)
00334       {
00335          case POK_LOCKOBJ_KIND_SEMAPHORE:
00336          {
00337             obj->current_value--;
00338             if (obj->current_value == 0)
00339             {
00340                obj->is_locked = TRUE;
00341             }
00342             break;
00343          }
00344          
00345          case POK_LOCKOBJ_KIND_MUTEX:
00346          {
00347             obj->is_locked = TRUE;
00348             break;
00349          }
00350          
00351          default:
00352          {
00353             obj->is_locked = TRUE;
00354             break;
00355          }
00356       }
00357       pok_sched_unlock_thread (POK_SCHED_CURRENT_THREAD);
00358    }
00359 
00360    return POK_ERRNO_OK;
00361 }
00362 
00363 
00364 pok_ret_t pok_lockobj_unlock (pok_lockobj_t* obj, const pok_lockobj_lockattr_t* attr)
00365 {
00366    uint32_t res;
00367 
00368    (void) attr;         /* unused at this time */
00369    
00370    if (obj->initialized == FALSE)
00371    {
00372       return POK_ERRNO_LOCKOBJ_NOTREADY;
00373    }
00374    
00375    res = 0;
00376    SPIN_LOCK (obj->spin);
00377 
00378    switch (obj->kind)
00379    {
00380       case POK_LOCKOBJ_KIND_SEMAPHORE:
00381       {
00382          if (obj->current_value < obj->max_value)
00383          {
00384             obj->current_value++;
00385          }
00386          obj->is_locked = FALSE;
00387          break;
00388       }
00389       
00390       case POK_LOCKOBJ_KIND_MUTEX:
00391       {
00392          obj->is_locked = FALSE;
00393          break;
00394       }
00395       
00396       default:
00397       {
00398          obj->is_locked = FALSE;
00399          break;
00400       }
00401    }  
00402    
00403    res = POK_SCHED_CURRENT_THREAD;
00404    res = (res + 1) % (POK_CONFIG_NB_THREADS);
00405 
00406    do
00407    { 
00408       if (obj->thread_state[res] == LOCKOBJ_STATE_LOCK)
00409       { 
00410          obj->thread_state[res] = LOCKOBJ_STATE_UNLOCK;
00411          pok_sched_unlock_thread (res);
00412          break;
00413       }  
00414       res = (res + 1) % (POK_CONFIG_NB_THREADS);
00415    }
00416    while ((res != POK_SCHED_CURRENT_THREAD));
00417 
00418    obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
00419    SPIN_UNLOCK (obj->spin);
00420 
00421    return POK_ERRNO_OK;
00422 }
00423 
00424 #ifdef POK_NEEDS_LOCKOBJECTS
00425 pok_ret_t pok_lockobj_partition_wrapper (const pok_lockobj_id_t id, const pok_lockobj_lockattr_t* attr)
00426 {
00427    /* First, we check that the locked object belongs to the partition
00428     * If not, we return an error
00429     */
00430    pok_ret_t ret;
00431 
00432    if (id < pok_partitions[POK_SCHED_CURRENT_PARTITION].lockobj_index_low)
00433    {
00434       return POK_ERRNO_EINVAL;
00435    }
00436    
00437    if ( id >= pok_partitions[POK_SCHED_CURRENT_PARTITION].lockobj_index_high)
00438    {
00439       return POK_ERRNO_EINVAL;
00440    }
00441 
00442    if (pok_partitions_lockobjs[id].kind != attr->obj_kind)
00443    {
00444       return POK_ERRNO_EINVAL;
00445    }
00446 
00447    switch (attr->operation)
00448    {
00449       case LOCKOBJ_OPERATION_LOCK:
00450          ret = pok_lockobj_lock (&pok_partitions_lockobjs[id], attr);
00451          return ret;
00452          break;
00453 
00454       case LOCKOBJ_OPERATION_UNLOCK:
00455          {
00456             ret = pok_lockobj_unlock (&pok_partitions_lockobjs[id], attr);
00457             return ret;
00458             break;
00459          }
00460 
00461       case LOCKOBJ_OPERATION_WAIT:
00462          {
00463             ret = pok_lockobj_eventwait (&pok_partitions_lockobjs[id], attr->time);
00464             return ret;
00465             break;
00466          }
00467 
00468       case LOCKOBJ_OPERATION_SIGNAL:
00469          {
00470             ret = pok_lockobj_eventsignal (&pok_partitions_lockobjs[id]);
00471             break;
00472          }
00473 
00474       case LOCKOBJ_OPERATION_BROADCAST:
00475          {
00476             ret = pok_lockobj_eventbroadcast (&pok_partitions_lockobjs[id]);
00477             break;
00478          }
00479 
00480       default:
00481          return POK_ERRNO_EINVAL;
00482    }
00483    return POK_ERRNO_EINVAL;
00484 }
00485 #endif
00486 
00487 #endif
00488