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 00023 #if defined (POK_NEEDS_SCHED) || defined (POK_NEEDS_THREADS) 00024 00025 #include <types.h> 00026 #include <arch.h> 00027 00028 #include <core/time.h> 00029 #include <core/sched.h> 00030 #include <core/thread.h> 00031 00032 #ifdef POK_NEEDS_PARTITIONS 00033 #include <core/partition.h> 00034 #endif 00035 00036 #ifdef POK_NEEDS_MIDDLEWARE 00037 #include <middleware/port.h> 00038 #endif 00039 00040 #include <dependencies.h> 00041 00042 #include <core/debug.h> 00043 #include <core/instrumentation.h> 00044 #include <core/error.h> 00045 00046 extern pok_thread_t pok_threads[]; 00047 00048 #ifdef POK_NEEDS_PARTITIONS 00049 extern pok_partition_t pok_partitions[]; 00050 00054 uint8_t pok_current_partition; 00055 00056 void pok_sched_partition_switch(); 00057 #endif 00058 00059 #if defined (POK_NEEDS_PORTS_SAMPLING) || defined (POK_NEEDS_PORTS_QUEUEING) 00060 void pok_port_flushall (void); 00061 #endif 00062 00063 uint64_t pok_sched_slots[POK_CONFIG_SCHEDULING_NBSLOTS] 00064 = (uint64_t[]) POK_CONFIG_SCHEDULING_SLOTS; 00065 uint8_t pok_sched_slots_allocation[POK_CONFIG_SCHEDULING_NBSLOTS] 00066 = (uint8_t[]) POK_CONFIG_SCHEDULING_SLOTS_ALLOCATION; 00067 00068 pok_sched_t pok_global_sched; 00069 uint64_t pok_sched_next_deadline; 00070 uint64_t pok_sched_next_major_frame; 00071 uint8_t pok_sched_current_slot = 0; /* Which slot are we executing at this time ?*/ 00072 uint32_t current_thread = KERNEL_THREAD; 00073 00074 void pok_sched_thread_switch (void); 00075 00080 void pok_sched_init (void) 00081 { 00082 #ifdef POK_NEEDS_PARTITIONS 00083 #if defined (POK_NEEDS_ERROR_HANDLING) || defined (POK_NEEDS_DEBUG) 00084 /* 00085 * We check that the total time of time frame 00086 * corresponds to the sum of each slot 00087 */ 00088 uint64_t total_time; 00089 uint8_t slot; 00090 00091 total_time = 0; 00092 00093 for (slot = 0 ; slot < POK_CONFIG_SCHEDULING_NBSLOTS ; slot++) 00094 { 00095 total_time = total_time + pok_sched_slots[slot]; 00096 } 00097 00098 if (total_time != POK_CONFIG_SCHEDULING_MAJOR_FRAME) 00099 { 00100 #ifdef POK_NEEDS_DEBUG 00101 printf ("Major frame is not compliant with all time slots\n"); 00102 #endif 00103 #ifdef POK_NEEDS_ERROR_HANDLING 00104 pok_kernel_error (POK_ERROR_KIND_KERNEL_CONFIG); 00105 #endif 00106 } 00107 #endif 00108 #endif 00109 00110 pok_sched_current_slot = 0; 00111 pok_sched_next_major_frame = POK_CONFIG_SCHEDULING_MAJOR_FRAME; 00112 pok_sched_next_deadline = pok_sched_slots[0]; 00113 pok_current_partition = pok_sched_slots_allocation[0]; 00114 } 00115 00116 uint8_t pok_sched_get_priority_min (const pok_sched_t sched_type) 00117 { 00118 (void) sched_type; 00119 /* At this time, we only support one scheduler */ 00120 return 0; 00121 } 00122 00123 uint8_t pok_sched_get_priority_max (const pok_sched_t sched_type) 00124 { 00125 (void) sched_type; 00126 /* At this time, we only support one scheduler */ 00127 return 255; 00128 } 00129 00130 #ifdef POK_NEEDS_PARTITIONS 00131 uint8_t pok_elect_partition() 00132 { 00133 uint8_t next_partition = POK_SCHED_CURRENT_PARTITION; 00134 # if POK_CONFIG_NB_PARTITIONS > 1 00135 uint64_t now = POK_GETTICK(); 00136 00137 if (pok_sched_next_deadline <= now) 00138 { 00139 /* Here, we change the partition */ 00140 # if defined (POK_NEEDS_PORTS_SAMPLING) || defined (POK_NEEDS_PORTS_QUEUEING) 00141 if (pok_sched_next_major_frame <= now) 00142 { 00143 pok_sched_next_major_frame = pok_sched_next_major_frame + POK_CONFIG_SCHEDULING_MAJOR_FRAME; 00144 pok_port_flushall(); 00145 } 00146 # endif /* defined (POK_NEEDS_PORTS....) */ 00147 00148 pok_sched_current_slot = (pok_sched_current_slot + 1) % POK_CONFIG_SCHEDULING_NBSLOTS; 00149 pok_sched_next_deadline = pok_sched_next_deadline + pok_sched_slots[pok_sched_current_slot]; 00150 /* 00151 * FIXME : current debug session about exceptions-handled 00152 printf ("Switch from partition %d to partition %d\n", pok_current_partition, pok_sched_current_slot); 00153 printf ("old current thread = %d\n", POK_SCHED_CURRENT_THREAD); 00154 00155 printf ("new current thread = %d\n", pok_partitions[pok_sched_current_slot].current_thread); 00156 printf ("new prev current thread = %d\n", pok_partitions[pok_sched_current_slot].prev_thread); 00157 */ 00158 next_partition = pok_sched_slots_allocation[pok_sched_current_slot]; 00159 00160 #ifdef POK_NEEDS_SCHED_HFPPS 00161 if (pok_partitions[next_partition].payback > 0) // pay back! 00162 { 00163 // new deadline 00164 pok_sched_next_deadline -= pok_partitions[next_partition].payback; 00165 pok_partitions[next_partition].payback = 0; 00166 } 00167 #endif /* POK_NEEDS_SCHED_HFPPS */ 00168 00169 } 00170 # endif /* POK_CONFIG_NB_PARTITIONS > 1 */ 00171 00172 return next_partition; 00173 } 00174 #endif /* POK_NEEDS_PARTITIONS */ 00175 00176 #ifdef POK_NEEDS_PARTITIONS 00177 uint32_t pok_elect_thread(uint8_t new_partition_id) 00178 { 00179 uint64_t now = POK_GETTICK(); 00180 pok_partition_t* new_partition = &(pok_partitions[new_partition_id]); 00181 00182 00183 /* 00184 * We unlock all WAITING threads if the waiting time is passed 00185 */ 00186 uint8_t i; /* i is used to browse the partition. We support 00187 * only 255 partitions are max, so, we use an uin8_t 00188 * type 00189 */ 00190 pok_thread_t* thread; 00191 for (i = 0; i < new_partition->nthreads; i++) 00192 { 00193 thread = &(pok_threads[new_partition->thread_index_low + i]); 00194 00195 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING) 00196 if ((thread->state == POK_STATE_WAITING) && (thread->wakeup_time <= now)) 00197 { 00198 thread->state = POK_STATE_RUNNABLE; 00199 } 00200 #endif 00201 00202 if ((thread->state == POK_STATE_WAIT_NEXT_ACTIVATION) && (thread->next_activation <= now)) 00203 { 00204 thread->state = POK_STATE_RUNNABLE; 00205 thread->remaining_time_capacity = thread->time_capacity; 00206 thread->next_activation = thread->next_activation + thread->period; 00207 } 00208 } 00209 00210 /* 00211 * We elect the thread to be executed. 00212 */ 00213 uint32_t elected; 00214 switch (new_partition->mode) 00215 { 00216 case POK_PARTITION_MODE_INIT_COLD: 00217 case POK_PARTITION_MODE_INIT_WARM: 00218 #ifdef POK_NEEDS_ERROR_HANDLING 00219 if ((new_partition->thread_error != 0) && 00220 (pok_threads[new_partition->thread_error].state != POK_STATE_STOPPED)) 00221 { 00222 elected = new_partition->thread_error; 00223 } 00224 else 00225 { 00226 elected = new_partition->thread_main; 00227 } 00228 #endif 00229 00230 elected = new_partition->thread_main; 00231 break; 00232 00233 case POK_PARTITION_MODE_NORMAL: 00234 #ifdef POK_NEEDS_ERROR_HANDLING 00235 if ((new_partition->current_thread == new_partition->thread_error) && 00236 (pok_threads[new_partition->current_thread].state == POK_STATE_RUNNABLE)) 00237 { 00238 elected = new_partition->thread_error; 00239 break; 00240 } 00241 #endif 00242 if ( (POK_SCHED_CURRENT_THREAD != IDLE_THREAD) && 00243 (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main) 00244 #ifdef POK_NEEDS_ERROR_HANDLING 00245 && (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error) 00246 #endif 00247 ) 00248 { 00249 if (POK_CURRENT_THREAD.remaining_time_capacity > 0) 00250 { 00251 POK_CURRENT_THREAD.remaining_time_capacity = POK_CURRENT_THREAD.remaining_time_capacity - 1; 00252 } 00253 else 00254 { 00255 POK_CURRENT_THREAD.state = POK_STATE_WAIT_NEXT_ACTIVATION; 00256 } 00257 } 00258 elected = new_partition->sched_func (new_partition->thread_index_low, 00259 new_partition->thread_index_high, 00260 new_partition->prev_thread, 00261 new_partition->current_thread); 00262 #ifdef POK_NEEDS_INSTRUMENTATION 00263 if ( (elected != IDLE_THREAD) && (elected != new_partition->thread_main)) 00264 { 00265 pok_instrumentation_running_task (elected); 00266 } 00267 #endif 00268 00269 break; 00270 00271 default: 00272 elected = IDLE_THREAD; 00273 break; 00274 } 00275 00276 #ifdef POK_NEEDS_SCHED_HFPPS 00277 if (pok_threads[elected].payback > 0) // pay back! 00278 { 00279 pok_threads[elected].remaining_time_capacity -= pok_threads[elected].payback; 00280 pok_threads[elected].payback = 0; 00281 } 00282 #endif /* POK_NEEDS_SCHED_HFPPS */ 00283 00284 // computed next thread's deadline 00285 pok_threads[elected].end_time = now + pok_threads[elected].remaining_time_capacity; 00286 00287 return (elected); 00288 } 00289 #endif /* POK_NEEDS_PARTITIONS */ 00290 00291 #ifdef POK_NEEDS_PARTITIONS 00292 void pok_sched() 00293 { 00294 uint32_t elected_thread = 0; 00295 uint8_t elected_partition = POK_SCHED_CURRENT_PARTITION; 00296 00297 #ifdef POK_NEEDS_SCHED_HFPPS 00298 uint64_t now = POK_GETTICK(); 00299 elected_thread = current_thread; 00300 00301 /* if thread hasn't finished its job and its deadline is passed */ 00302 if (pok_threads[elected_thread].end_time <= now && pok_threads[elected_thread].remaining_time_capacity > 0) 00303 { 00304 /* updates thread and partition payback */ 00305 pok_threads[elected_thread].payback = pok_threads[elected_thread].remaining_time_capacity; 00306 pok_partitions[pok_current_partition].payback = pok_threads[elected_thread].remaining_time_capacity; 00307 /* computes next partition deadline */ 00308 pok_sched_next_deadline += pok_threads[elected_thread].remaining_time_capacity; 00309 } 00310 else /* overmegadirty */ 00311 #endif /* POK_NEEDS_SCHED_HFPPS */ 00312 { 00313 00314 elected_partition = pok_elect_partition(); 00315 elected_thread = pok_elect_thread(elected_partition); 00316 } 00317 00318 pok_current_partition = elected_partition; 00319 if(pok_partitions[pok_current_partition].current_thread != elected_thread) { 00320 if(pok_partitions[pok_current_partition].current_thread != IDLE_THREAD) { 00321 pok_partitions[pok_current_partition].prev_thread = pok_partitions[pok_current_partition].current_thread; 00322 } 00323 pok_partitions[pok_current_partition].current_thread = elected_thread; 00324 } 00325 pok_sched_context_switch(elected_thread); 00326 } 00327 #else 00328 void pok_sched_thread_switch () 00329 { 00330 int i; 00331 uint64_t now; 00332 uint32_t elected; 00333 00334 now = POK_GETTICK(); 00335 for (i = 0; i <= POK_CONFIG_NB_THREADS; ++i) 00336 { 00337 if ((pok_threads[i].state == POK_STATE_WAITING) && 00338 (pok_threads[i].wakeup_time <= now)) 00339 { 00340 pok_threads[i].state = POK_STATE_RUNNABLE; 00341 } 00342 } 00343 00344 elected = pok_sched_part_election (0, POK_CONFIG_NB_THREADS); 00345 /* 00346 * FIXME : current debug session about exceptions-handled 00347 printf ("switch to thread %d\n", elected); 00348 */ 00349 pok_sched_context_switch(elected); 00350 } 00351 #endif /* POK_NEEDS_PARTITIONS */ 00352 00353 /* 00354 * Context-switch function to switch from one thread to another 00355 * Rely on architecture-dependent functionnalities (must include arch.h) 00356 */ 00357 void pok_sched_context_switch (const uint32_t elected_id) 00358 { 00359 uint32_t *current_sp; 00360 uint32_t new_sp; 00361 00362 if (POK_SCHED_CURRENT_THREAD == elected_id) 00363 { 00364 return; 00365 } 00366 00367 current_sp = &POK_CURRENT_THREAD.sp; 00368 new_sp = pok_threads[elected_id].sp; 00369 /* 00370 * FIXME : current debug session about exceptions-handled 00371 printf("switch from thread %d, sp=0x%x\n",POK_SCHED_CURRENT_THREAD, current_sp); 00372 printf("switch to thread %d, sp=0x%x\n",elected_id, new_sp); 00373 */ 00374 pok_space_switch(POK_CURRENT_THREAD.partition, 00375 pok_threads[elected_id].partition); 00376 00377 current_thread = elected_id; 00378 00379 pok_context_switch(current_sp, new_sp); 00380 } 00381 00382 #ifdef POK_NEEDS_SCHED_RMS 00383 uint32_t pok_sched_part_rms (const uint32_t index_low, const uint32_t index_high,const uint32_t __attribute__((unused)) prev_thread,const uint32_t __attribute__((unused)) current_thread) 00384 { 00385 uint32_t res; 00386 #ifdef POK_NEEDS_DEBUG 00387 uint32_t from; 00388 from = prev_thread; 00389 #endif 00390 00391 res= index_low; 00392 00393 do 00394 { 00395 res++; 00396 if (res >= index_high) 00397 { 00398 res = index_low; 00399 } 00400 } 00401 while ((res != index_low) && 00402 (pok_threads[res].state != POK_STATE_RUNNABLE)); 00403 00404 if ((res == index_low) && (pok_threads[res].state != POK_STATE_RUNNABLE)) 00405 { 00406 res = IDLE_THREAD; 00407 } 00408 00409 #ifdef POK_NEEDS_DEBUG 00410 if ( res!= IDLE_THREAD) 00411 { 00412 printf("--- scheduling thread: %d {%d} --- ", res, 00413 pok_threads[res].period); 00414 from=index_low; 00415 while ( from <= index_high ) 00416 { 00417 if ( pok_threads[from].state==POK_STATE_RUNNABLE ) 00418 { 00419 printf(" %d {%d} ,",from,pok_threads[from].period); 00420 } 00421 from++; 00422 } 00423 printf(" are runnable\n"); 00424 } 00425 #endif 00426 00427 return res; 00428 } 00429 #endif /* POK_NEEDS_SCHED_RMS */ 00430 00431 00432 uint32_t pok_sched_part_rr (const uint32_t index_low, const uint32_t index_high,const uint32_t prev_thread,const uint32_t current_thread) 00433 { 00434 uint32_t res; 00435 uint32_t from; 00436 00437 if (current_thread == IDLE_THREAD) 00438 { 00439 res = prev_thread; 00440 } 00441 else 00442 { 00443 res = current_thread; 00444 } 00445 00446 from = res; 00447 00448 if ((pok_threads[current_thread].remaining_time_capacity > 0) && (pok_threads[current_thread].state == POK_STATE_RUNNABLE)) 00449 { 00450 return current_thread; 00451 } 00452 00453 do 00454 { 00455 res++; 00456 if (res > index_high) 00457 { 00458 res = index_low; 00459 } 00460 } 00461 while ((res != from) && (pok_threads[res].state != POK_STATE_RUNNABLE)); 00462 00463 if ((res == from) && (pok_threads[res].state != POK_STATE_RUNNABLE)) 00464 { 00465 res = IDLE_THREAD; 00466 } 00467 return res; 00468 } 00469 00470 00471 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING) 00472 void pok_sched_unlock_thread (const uint32_t thread_id) 00473 { 00474 pok_threads[thread_id].state = POK_STATE_RUNNABLE; 00475 } 00476 #endif 00477 00478 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING) 00479 void pok_sched_lock_current_thread (void) 00480 { 00481 pok_threads[current_thread].state = POK_STATE_LOCK; 00482 } 00483 00484 void pok_sched_lock_current_thread_timed (const uint64_t time) 00485 { 00486 pok_threads[current_thread].state = POK_STATE_WAITING; 00487 pok_threads[current_thread].wakeup_time = time; 00488 } 00489 #endif 00490 00491 #ifdef POK_NEEDS_SCHED_STOP_SELF 00492 void pok_sched_stop_self (void) 00493 { 00494 POK_CURRENT_THREAD.state = POK_STATE_STOPPED; 00495 pok_sched (); 00496 } 00497 #endif 00498 00499 void pok_sched_stop_thread (const uint32_t tid) 00500 { 00501 pok_threads[tid].state = POK_STATE_STOPPED; 00502 } 00503 00504 #ifdef POK_NEEDS_DEPRECIATED 00505 void pok_sched_lock_thread (const uint32_t thread_id) 00506 { 00507 pok_threads[thread_id].state = POK_STATE_LOCK; 00508 } 00509 #endif 00510 00511 pok_ret_t pok_sched_end_period () 00512 { 00513 POK_CURRENT_THREAD.state = POK_STATE_WAIT_NEXT_ACTIVATION; 00514 POK_CURRENT_THREAD.remaining_time_capacity = 0; 00515 pok_sched (); 00516 return POK_ERRNO_OK; 00517 } 00518 00519 #if defined (POK_NEEDS_PARTITIONS) && defined (POK_NEEDS_ERROR_HANDLING) 00520 void pok_sched_activate_error_thread (void) 00521 { 00522 uint32_t error_thread = pok_partitions[pok_current_partition].thread_error; 00523 if (error_thread != 0) 00524 { 00525 pok_threads[error_thread].remaining_time_capacity = 1000; 00526 pok_threads[error_thread].period = 100; 00527 pok_threads[error_thread].next_activation= 0; 00528 00529 pok_threads[error_thread].state = POK_STATE_RUNNABLE; 00530 pok_sched_context_switch (error_thread); 00531 } 00532 } 00533 #endif 00534 00535 #ifdef POK_NEEDS_PARTITIONS 00536 00537 uint32_t pok_sched_get_current(uint32_t *thread_id) 00538 { 00539 #if defined (POK_NEEDS_ERROR_HANDLING) 00540 if (pok_partitions[pok_current_partition].thread_error == 0) 00541 return POK_ERRNO_THREAD; 00542 #endif 00543 if (KERNEL_THREAD == POK_SCHED_CURRENT_THREAD 00544 || IDLE_THREAD == POK_SCHED_CURRENT_THREAD) 00545 { 00546 return POK_ERRNO_THREAD; 00547 } 00548 *thread_id=POK_SCHED_CURRENT_THREAD; 00549 return POK_ERRNO_OK; 00550 } 00551 #endif 00552 00553 #endif /* __POK_NEEDS_SCHED */