POK(kernelpart)
/home/jaouen/pok_official/pok/trunk/kernel/core/sched.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 
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 */