POK(kernelpart)
|
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