POK(kernelpart)
sched.c
Go to the documentation of this file.
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Thu Jan 15 23:34:13 2009
15  */
16 
23 #if defined (POK_NEEDS_SCHED) || defined (POK_NEEDS_THREADS)
24 
25 #include <types.h>
26 #include <arch.h>
27 
28 #include <core/time.h>
29 #include <core/sched.h>
30 #include <core/thread.h>
31 
32 #ifdef POK_NEEDS_PARTITIONS
33 #include <core/partition.h>
34 #endif
35 
36 #ifdef POK_NEEDS_MIDDLEWARE
37 #include <middleware/port.h>
38 #endif
39 
40 #include <dependencies.h>
41 
42 #include <core/debug.h>
43 #include <core/instrumentation.h>
44 #include <core/error.h>
45 
46 extern pok_thread_t pok_threads[];
47 
48 #ifdef POK_NEEDS_PARTITIONS
49 extern pok_partition_t pok_partitions[];
50 
54 uint8_t pok_current_partition;
55 
56 void pok_sched_partition_switch();
57 #endif
58 
59 #if defined (POK_NEEDS_PORTS_SAMPLING) || defined (POK_NEEDS_PORTS_QUEUEING)
60 void pok_port_flushall (void);
61 #endif
62 
63 uint64_t pok_sched_slots[POK_CONFIG_SCHEDULING_NBSLOTS]
64  = (uint64_t[]) POK_CONFIG_SCHEDULING_SLOTS;
65 uint8_t pok_sched_slots_allocation[POK_CONFIG_SCHEDULING_NBSLOTS]
66  = (uint8_t[]) POK_CONFIG_SCHEDULING_SLOTS_ALLOCATION;
67 
68 uint32_t prev_current_thread;
69 pok_sched_t pok_global_sched;
70 uint64_t pok_sched_next_deadline;
71 uint64_t pok_sched_next_major_frame;
72 uint8_t pok_sched_current_slot = 0; /* Which slot are we executing at this time ?*/
73 uint32_t current_thread = KERNEL_THREAD;
74 
75 void pok_sched_thread_switch (void);
76 
81 void pok_sched_init (void)
82 {
83 #ifdef POK_NEEDS_PARTITIONS
84 #if defined (POK_NEEDS_ERROR_HANDLING) || defined (POK_NEEDS_DEBUG)
85  /*
86  * We check that the total time of time frame
87  * corresponds to the sum of each slot
88  */
89  uint64_t total_time;
90  uint8_t slot;
91 
92  total_time = 0;
93 
94  for (slot = 0 ; slot < POK_CONFIG_SCHEDULING_NBSLOTS ; slot++)
95  {
96  total_time = total_time + pok_sched_slots[slot];
97  }
98 
99  if (total_time != POK_CONFIG_SCHEDULING_MAJOR_FRAME)
100  {
101 #ifdef POK_NEEDS_DEBUG
102  printf ("Major frame is not compliant with all time slots\n");
103 #endif
104 #ifdef POK_NEEDS_ERROR_HANDLING
105  pok_kernel_error (POK_ERROR_KIND_KERNEL_CONFIG);
106 #endif
107  }
108 #endif
109 #endif
110 
111  pok_sched_current_slot = 0;
112  pok_sched_next_major_frame = POK_CONFIG_SCHEDULING_MAJOR_FRAME;
113  pok_sched_next_deadline = pok_sched_slots[0];
114  pok_current_partition = pok_sched_slots_allocation[0];
115 }
116 
117 uint8_t pok_sched_get_priority_min (const pok_sched_t sched_type)
118 {
119  (void) sched_type;
120  /* At this time, we only support one scheduler */
121  return 0;
122 }
123 
124 uint8_t pok_sched_get_priority_max (const pok_sched_t sched_type)
125 {
126  (void) sched_type;
127  /* At this time, we only support one scheduler */
128  return 255;
129 }
130 
131 #ifdef POK_NEEDS_PARTITIONS
132 pok_partition_t* pok_elect_partition()
133 {
134 # if POK_CONFIG_NB_PARTITIONS > 1
135  uint64_t now = POK_GETTICK();
136 
137  if (pok_sched_next_deadline <= now)
138  {
139  /* Here, we change the partition */
140 # if defined (POK_NEEDS_PORTS_SAMPLING) || defined (POK_NEEDS_PORTS_QUEUEING)
141  if (pok_sched_next_major_frame <= now)
142  {
143  pok_sched_next_major_frame = pok_sched_next_major_frame + POK_CONFIG_SCHEDULING_MAJOR_FRAME;
144  pok_port_flushall();
145  }
146 # endif /* defined (POK_NEEDS_PORTS....) */
147 
148  pok_sched_current_slot = (pok_sched_current_slot + 1) % POK_CONFIG_SCHEDULING_NBSLOTS;
149  pok_sched_next_deadline = pok_sched_next_deadline + pok_sched_slots[pok_sched_current_slot];
150 /*
151  * FIXME : current debug session about exceptions-handled
152  printf ("Switch from partition %d to partition %d\n", pok_current_partition, pok_sched_current_slot);
153  printf ("old current thread = %d\n", POK_SCHED_CURRENT_THREAD);
154  printf ("old prev current thread = %d\n", prev_current_thread);
155 
156  printf ("new current thread = %d\n", pok_partitions[pok_sched_current_slot].current_thread);
157  printf ("new prev current thread = %d\n", pok_partitions[pok_sched_current_slot].prev_current_thread);
158  */
159  pok_partitions[pok_current_partition].prev_current_thread = prev_current_thread;
160  pok_partitions[pok_current_partition].current_thread = POK_SCHED_CURRENT_THREAD;
161 
162  pok_current_partition = pok_sched_slots_allocation[pok_sched_current_slot];
163 
164  prev_current_thread = pok_partitions[pok_current_partition].prev_current_thread;
165  current_thread = pok_partitions[pok_current_partition].current_thread;
166 
167 #ifdef POK_NEEDS_SCHED_HFPPS
168  if (pok_partitions[pok_current_partition].payback > 0) // pay back!
169  {
170  // new deadline
171  pok_sched_next_deadline -= pok_partitions[pok_current_partition].payback;
172  pok_partitions[pok_current_partition].payback = 0;
173  }
174 #endif /* POK_NEEDS_SCHED_HFPPS */
175 
176  }
177 # endif /* POK_CONFIG_NB_PARTITIONS > 1 */
178 
179  return (&(pok_partitions[pok_current_partition]));
180 }
181 #endif /* POK_NEEDS_PARTITIONS */
182 
183 #ifdef POK_NEEDS_PARTITIONS
184 uint32_t pok_elect_thread(pok_partition_t* current_partition)
185 {
186  uint64_t now = POK_GETTICK();
187 
188 
189  /*
190  * We unlock all WAITING threads if the waiting time is passed
191  */
192  uint8_t i; /* i is used to browse the partition. We support
193  * only 255 partitions are max, so, we use an uin8_t
194  * type
195  */
196  pok_thread_t* thread;
197  for (i = 0; i < pok_partitions[pok_current_partition].nthreads; i++)
198  {
199  thread = &(pok_threads[current_partition->thread_index_low + i]);
200 
201 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING)
202  if ((thread->state == POK_STATE_WAITING) && (thread->wakeup_time <= now))
203  {
204  thread->state = POK_STATE_RUNNABLE;
205  }
206 #endif
207 
208  if ((thread->state == POK_STATE_WAIT_NEXT_ACTIVATION) && (thread->next_activation <= now))
209  {
210  thread->state = POK_STATE_RUNNABLE;
211  thread->remaining_time_capacity = thread->time_capacity;
212  thread->next_activation = thread->period + POK_GETTICK();
213  }
214  }
215 
216  /*
217  * We elect the thread to be executed.
218  */
219  uint32_t elected;
220  switch (current_partition->mode)
221  {
222  case POK_PARTITION_MODE_INIT_COLD:
223  case POK_PARTITION_MODE_INIT_WARM:
224 #ifdef POK_NEEDS_ERROR_HANDLING
225  if ((current_partition->thread_error != 0) &&
226  (pok_threads[current_partition->thread_error].state != POK_STATE_STOPPED))
227  {
228  elected = current_partition->thread_error;
229  }
230  else
231  {
232  elected = current_partition->thread_main;
233  }
234 #endif
235 
236  elected = current_partition->thread_main;
237  break;
238 
239  case POK_PARTITION_MODE_NORMAL:
240 #ifdef POK_NEEDS_ERROR_HANDLING
241  if ((POK_SCHED_CURRENT_THREAD == POK_CURRENT_PARTITION.thread_error) &&
242  (POK_CURRENT_THREAD.state == POK_STATE_RUNNABLE))
243  {
244  elected = POK_CURRENT_PARTITION.thread_error;
245  POK_CURRENT_PARTITION.current_thread = elected;
246  break;
247  }
248 #endif
249  if ( (POK_SCHED_CURRENT_THREAD != IDLE_THREAD) &&
250  (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main)
251 #ifdef POK_NEEDS_ERROR_HANDLING
252  && (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)
253 #endif
254  )
255  {
256  if (POK_CURRENT_THREAD.remaining_time_capacity > 0)
257  {
258  POK_CURRENT_THREAD.remaining_time_capacity = POK_CURRENT_THREAD.remaining_time_capacity - 1;
259  }
260  else
261  {
262  POK_CURRENT_THREAD.state = POK_STATE_WAIT_NEXT_ACTIVATION;
263  }
264  }
265  elected = POK_CURRENT_PARTITION.sched_func (current_partition->thread_index_low,
266  current_partition->thread_index_high);
267 #ifdef POK_NEEDS_INSTRUMENTATION
268  if ( (elected != IDLE_THREAD) && (elected != POK_CURRENT_PARTITION.thread_main))
269  {
270  pok_instrumentation_running_task (elected);
271  }
272 #endif
273  POK_CURRENT_PARTITION.current_thread = elected;
274 
275  break;
276 
277  default:
278  elected = IDLE_THREAD;
279  break;
280  }
281 
282 #ifdef POK_NEEDS_SCHED_HFPPS
283  if (pok_threads[elected].payback > 0) // pay back!
284  {
285  pok_threads[elected].remaining_time_capacity -= pok_threads[elected].payback;
286  pok_threads[elected].payback = 0;
287  }
288 #endif /* POK_NEEDS_SCHED_HFPPS */
289 
290  // computed next thread's deadline
291  pok_threads[elected].end_time = now + pok_threads[elected].remaining_time_capacity;
292 
293  return (elected);
294 }
295 #endif /* POK_NEEDS_PARTITIONS */
296 
297 #ifdef POK_NEEDS_PARTITIONS
298 void pok_sched()
299 {
300  uint32_t elected_thread = 0;
301 
302 #ifdef POK_NEEDS_SCHED_HFPPS
303  uint64_t now = POK_GETTICK();
304  elected_thread = current_thread;
305 
306  /* if thread hasn't finished its job and its deadline is passed */
307  if (pok_threads[elected_thread].end_time <= now && pok_threads[elected_thread].remaining_time_capacity > 0)
308  {
309  /* updates thread and partition payback */
310  pok_threads[elected_thread].payback = pok_threads[elected_thread].remaining_time_capacity;
311  pok_partitions[pok_current_partition].payback = pok_threads[elected_thread].remaining_time_capacity;
312  /* computes next partition deadline */
313  pok_sched_next_deadline += pok_threads[elected_thread].remaining_time_capacity;
314  }
315  else /* overmegadirty */
316 #endif /* POK_NEEDS_SCHED_HFPPS */
317  {
318  pok_partition_t* elected_partition = pok_elect_partition();
319  elected_thread = pok_elect_thread(elected_partition);
320  }
321 
322  pok_sched_context_switch(elected_thread);
323 }
324 #else
325 void pok_sched_thread_switch ()
326 {
327  int i;
328  uint64_t now;
329  uint32_t elected;
330 
331  now = POK_GETTICK();
332  for (i = 0; i <= POK_CONFIG_NB_THREADS; ++i)
333  {
334  if ((pok_threads[i].state == POK_STATE_WAITING) &&
335  (pok_threads[i].wakeup_time <= now))
336  {
337  pok_threads[i].state = POK_STATE_RUNNABLE;
338  }
339  }
340 
341  elected = pok_sched_part_election (0, POK_CONFIG_NB_THREADS);
342  /*
343  * FIXME : current debug session about exceptions-handled
344  printf ("switch to thread %d\n", elected);
345  */
346  pok_sched_context_switch(elected);
347 }
348 #endif /* POK_NEEDS_PARTITIONS */
349 
350 /*
351  * Context-switch function to switch from one thread to another
352  * Rely on architecture-dependent functionnalities (must include arch.h)
353  */
354 void pok_sched_context_switch (const uint32_t elected_id)
355 {
356  uint32_t *current_sp;
357  uint32_t new_sp;
358 
359  if (POK_SCHED_CURRENT_THREAD == elected_id)
360  {
361  return;
362  }
363  current_sp = &POK_CURRENT_THREAD.sp;
364  new_sp = pok_threads[elected_id].sp;
365 /*
366  * FIXME : current debug session about exceptions-handled
367  printf("switch from thread %d, sp=0x%x\n",POK_SCHED_CURRENT_THREAD, current_sp);
368  printf("switch to thread %d, sp=0x%x\n",elected_id, new_sp);
369  */
370  pok_space_switch(POK_CURRENT_THREAD.partition,
371  pok_threads[elected_id].partition);
372 
373  current_thread = elected_id;
374 
375  pok_context_switch(current_sp, new_sp);
376 }
377 
378 #ifdef POK_NEEDS_SCHED_RMS
379 uint32_t pok_sched_part_rms (const uint32_t index_low, const uint32_t index_high)
380 {
381  uint32_t res;
382 #ifdef POK_NEEDS_DEBUG
383  uint32_t from;
384 #endif
385 
386  if (POK_SCHED_CURRENT_THREAD == IDLE_THREAD)
387  {
388  res = prev_current_thread;
389  }
390  else
391  {
392  res = POK_SCHED_CURRENT_THREAD;
393  }
394 
395 #ifdef POK_NEEDS_DEBUG
396  from = res;
397 #endif
398 
399  res= index_low;
400 
401  do
402  {
403  res++;
404  if (res >= index_high)
405  {
406  res = index_low;
407  }
408  }
409  while ((res != index_low) &&
410  (pok_threads[res].state != POK_STATE_RUNNABLE));
411 
412  if ((res == index_low) && (pok_threads[res].state != POK_STATE_RUNNABLE))
413  {
414  res = IDLE_THREAD;
415  if (POK_SCHED_CURRENT_THREAD != IDLE_THREAD)
416  {
417  prev_current_thread = POK_SCHED_CURRENT_THREAD;
418  }
419  }
420 
421 #ifdef POK_NEEDS_DEBUG
422  if ( res!= IDLE_THREAD)
423  {
424  printf("--- scheduling thread: %d {%d} --- ", res,
425  pok_threads[res].period);
426  from=index_low;
427  while ( from <= index_high )
428  {
429  if ( pok_threads[from].state==POK_STATE_RUNNABLE )
430  {
431  printf(" %d {%d} ,",from,pok_threads[from].period);
432  }
433  from++;
434  }
435  printf(" are runnable\n");
436  }
437 #endif
438 
439  return res;
440 }
441 #endif /* POK_NEEDS_SCHED_RMS */
442 
443 
444 uint32_t pok_sched_part_rr (const uint32_t index_low, const uint32_t index_high)
445 {
446  uint32_t res;
447  uint32_t from;
448 
449  if (POK_SCHED_CURRENT_THREAD == IDLE_THREAD)
450  {
451  res = prev_current_thread;
452  }
453  else
454  {
455  res = POK_SCHED_CURRENT_THREAD;
456  }
457 
458  from = res;
459 
460  if ((POK_CURRENT_THREAD.remaining_time_capacity > 0) && (POK_CURRENT_THREAD.state == POK_STATE_RUNNABLE))
461  {
462  return POK_SCHED_CURRENT_THREAD;
463  }
464 
465  do
466  {
467  res++;
468  if (res > index_high)
469  {
470  res = index_low;
471  }
472  }
473  while ((res != from) && (pok_threads[res].state != POK_STATE_RUNNABLE));
474 
475  if ((res == from) && (pok_threads[res].state != POK_STATE_RUNNABLE))
476  {
477  res = IDLE_THREAD;
478  if (POK_SCHED_CURRENT_THREAD != IDLE_THREAD)
479  {
480  prev_current_thread = POK_SCHED_CURRENT_THREAD;
481  }
482  }
483  return res;
484 }
485 
486 
487 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING)
488 void pok_sched_unlock_thread (const uint32_t thread_id)
489 {
490  pok_threads[thread_id].state = POK_STATE_RUNNABLE;
491 }
492 #endif
493 
494 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING)
495 void pok_sched_lock_current_thread (void)
496 {
497  pok_threads[current_thread].state = POK_STATE_LOCK;
498 }
499 
500 void pok_sched_lock_current_thread_timed (const uint64_t time)
501 {
502  pok_threads[current_thread].state = POK_STATE_WAITING;
503  pok_threads[current_thread].wakeup_time = time;
504 }
505 #endif
506 
507 #ifdef POK_NEEDS_SCHED_STOP_SELF
508 void pok_sched_stop_self (void)
509 {
510  POK_CURRENT_THREAD.state = POK_STATE_STOPPED;
511  pok_sched ();
512 }
513 #endif
514 
515 void pok_sched_stop_thread (const uint32_t tid)
516 {
517  pok_threads[tid].state = POK_STATE_STOPPED;
518 }
519 
520 #ifdef POK_NEEDS_DEPRECIATED
521 void pok_sched_lock_thread (const uint32_t thread_id)
522 {
523  pok_threads[thread_id].state = POK_STATE_LOCK;
524 }
525 #endif
526 
527 pok_ret_t pok_sched_end_period ()
528 {
529  POK_CURRENT_THREAD.state = POK_STATE_WAIT_NEXT_ACTIVATION;
530  POK_CURRENT_THREAD.remaining_time_capacity = 0;
531  pok_sched ();
532  return POK_ERRNO_OK;
533 }
534 
535 #if defined (POK_NEEDS_PARTITIONS) && defined (POK_NEEDS_ERROR_HANDLING)
536 void pok_sched_activate_error_thread (void)
537 {
538  uint32_t error_thread = pok_partitions[pok_current_partition].thread_error;
539  if (error_thread != 0)
540  {
541  pok_threads[error_thread].remaining_time_capacity = 1000;
542  pok_threads[error_thread].period = 100;
543  pok_threads[error_thread].next_activation= 0;
544 
545  pok_threads[error_thread].state = POK_STATE_RUNNABLE;
546  pok_sched_context_switch (error_thread);
547  }
548 }
549 #endif
550 
551 #ifdef POK_NEEDS_PARTITIONS
552 
553 uint32_t pok_sched_get_current(uint32_t *thread_id)
554 {
555 #if defined (POK_NEEDS_ERROR_HANDLING)
556  if (pok_partitions[pok_current_partition].thread_error == 0)
557  return POK_ERRNO_THREAD;
558 #endif
559  if (KERNEL_THREAD == POK_SCHED_CURRENT_THREAD
560  || IDLE_THREAD == POK_SCHED_CURRENT_THREAD)
561  {
562  return POK_ERRNO_THREAD;
563  }
564  *thread_id=POK_SCHED_CURRENT_THREAD;
565  return POK_ERRNO_OK;
566 }
567 #endif
568 
569 #endif /* __POK_NEEDS_SCHED */