aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/reservation.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/reservation.c')
-rw-r--r--litmus/reservation.c303
1 files changed, 301 insertions, 2 deletions
diff --git a/litmus/reservation.c b/litmus/reservation.c
index 0e43479ff2e1..35b3b5de5d0c 100644
--- a/litmus/reservation.c
+++ b/litmus/reservation.c
@@ -1,4 +1,5 @@
1#include <linux/sched.h> 1#include <linux/sched.h>
2#include <linux/slab.h>
2 3
3#include <litmus/litmus.h> 4#include <litmus/litmus.h>
4#include <litmus/reservation.h> 5#include <litmus/reservation.h>
@@ -203,8 +204,7 @@ static void sup_charge_budget(
203 { 204 {
204 /* make sure scheduler is invoked when this reservation expires 205 /* make sure scheduler is invoked when this reservation expires
205 * its remaining budget */ 206 * its remaining budget */
206 TRACE("requesting scheduler update for reservation %u in %llu nanoseconds\n", 207 //TRACE("requesting scheduler update for reservation %u in %llu nanoseconds\n", res->id, res->cur_budget);
207 res->id, res->cur_budget);
208 sup_scheduler_update_after(sup_env, res->cur_budget); 208 sup_scheduler_update_after(sup_env, res->cur_budget);
209 } 209 }
210 if (encountered_active) 210 if (encountered_active)
@@ -317,3 +317,302 @@ void sup_init(struct sup_reservation_environment* sup_env)
317 317
318 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE; 318 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE;
319} 319}
320
321static void gmp_scheduler_update_at(
322 struct gmp_reservation_environment* gmp_env,
323 lt_t when)
324{
325 struct next_timer_event *nevent;
326 struct list_head *pos;
327 struct next_timer_event *queued;
328 int found = 0;
329
330 nevent = kzalloc(sizeof(*nevent), GFP_KERNEL);
331 nevent->next_event = when;
332 nevent->timer_armed_on = NO_CPU;
333
334 list_for_each(pos, &gmp_env->next_events) {
335 queued = list_entry(pos, struct next_timer_event, list);
336 if (queued->next_event > nevent->next_event) {
337 list_add(&nevent->list, pos->prev);
338 found = 1;
339 TRACE("NEXT_EVENT ADDED after %llu\n", queued->next_event);
340 break;
341 }
342 }
343
344 if (!found) {
345 list_add_tail(&nevent->list, &gmp_env->next_events);
346 TRACE("NEXT_EVENT ADDED at [0]\n");
347 }
348
349 TRACE("GMP_SCHEDULER_UPDATE_AT update_time: %llu\n", nevent->next_event);
350}
351
352static void gmp_scheduler_update_after(
353 struct gmp_reservation_environment* gmp_env,
354 lt_t timeout)
355{
356 gmp_scheduler_update_at(gmp_env, gmp_env->env.current_time + timeout);
357}
358
359static int _gmp_queue_depleted(
360 struct gmp_reservation_environment* gmp_env,
361 struct reservation *res)
362{
363 struct list_head *pos;
364 struct reservation *queued;
365 int passed_earlier = 0;
366
367 list_for_each(pos, &gmp_env->depleted_reservations) {
368 queued = list_entry(pos, struct reservation, list);
369 if (queued->next_replenishment > res->next_replenishment) {
370 list_add(&res->list, pos->prev);
371 return passed_earlier;
372 } else
373 passed_earlier = 1;
374 }
375
376 list_add_tail(&res->list, &gmp_env->depleted_reservations);
377
378 return passed_earlier;
379}
380
381static void gmp_queue_depleted(
382 struct gmp_reservation_environment* gmp_env,
383 struct reservation *res)
384{
385 int passed_earlier = _gmp_queue_depleted(gmp_env, res);
386
387 /* check for updated replenishment time */
388 if (!passed_earlier)
389 gmp_scheduler_update_at(gmp_env, res->next_replenishment);
390}
391
392static int _gmp_queue_active(
393 struct gmp_reservation_environment* gmp_env,
394 struct reservation *res)
395{
396 struct list_head *pos;
397 struct reservation *queued;
398 int passed_active = 0;
399
400 list_for_each(pos, &gmp_env->active_reservations) {
401 queued = list_entry(pos, struct reservation, list);
402 if (queued->priority > res->priority) {
403 list_add(&res->list, pos->prev);
404 return passed_active;
405 } else if (queued->state == RESERVATION_ACTIVE)
406 passed_active = 1;
407 }
408
409 list_add_tail(&res->list, &gmp_env->active_reservations);
410 return passed_active;
411}
412
413static void gmp_queue_active(
414 struct gmp_reservation_environment* gmp_env,
415 struct reservation *res)
416{
417 int passed_active = _gmp_queue_active(gmp_env, res);
418
419 /* check for possible preemption */
420 if (res->state == RESERVATION_ACTIVE && !passed_active) {
421 gmp_env->schedule_now = true;
422 } else {
423 /* Active means this reservation is draining budget => make sure
424 * the scheduler is called to notice when the reservation budget has been
425 * drained completely. */
426 gmp_scheduler_update_after(gmp_env, res->cur_budget);
427 }
428}
429
430static void gmp_queue_reservation(
431 struct gmp_reservation_environment* gmp_env,
432 struct reservation *res)
433{
434 TRACE("GMP_QUEUE_RES state (%d)\n", res->state);
435 switch (res->state) {
436 case RESERVATION_INACTIVE:
437 list_add(&res->list, &gmp_env->inactive_reservations);
438 break;
439
440 case RESERVATION_DEPLETED:
441 gmp_queue_depleted(gmp_env, res);
442 break;
443
444 case RESERVATION_ACTIVE_IDLE:
445 case RESERVATION_ACTIVE:
446 gmp_queue_active(gmp_env, res);
447 break;
448 }
449}
450
451void gmp_add_new_reservation(
452 struct gmp_reservation_environment* gmp_env,
453 struct reservation* new_res)
454{
455 new_res->env = &gmp_env->env;
456 TRACE("GMP_ADD_NEW_RES\n");
457 gmp_queue_reservation(gmp_env, new_res);
458}
459
460struct reservation* gmp_find_by_id(struct gmp_reservation_environment* gmp_env,
461 unsigned int id)
462{
463 struct reservation *res;
464
465 list_for_each_entry(res, &gmp_env->active_reservations, list) {
466 if (res->id == id)
467 return res;
468 }
469 list_for_each_entry(res, &gmp_env->inactive_reservations, list) {
470 if (res->id == id)
471 return res;
472 }
473 list_for_each_entry(res, &gmp_env->depleted_reservations, list) {
474 if (res->id == id)
475 return res;
476 }
477
478 return NULL;
479}
480
481static void gmp_charge_budget(
482 struct gmp_reservation_environment* gmp_env,
483 lt_t delta)
484{
485 struct list_head *pos, *next;
486 struct reservation *res;
487
488 //int encountered_active = 0;
489
490 list_for_each_safe(pos, next, &gmp_env->active_reservations) {
491 /* charge all ACTIVE_IDLE up to the current scheduled ACTIVE reservation */
492 res = list_entry(pos, struct reservation, list);
493 if (res->state == RESERVATION_ACTIVE) {
494 res->ops->drain_budget(res, delta);
495 //encountered_active = 1;
496 } else {
497 BUG_ON(res->state != RESERVATION_ACTIVE_IDLE);
498 res->ops->drain_budget(res, delta);
499 }
500 if (res->state == RESERVATION_ACTIVE ||
501 res->state == RESERVATION_ACTIVE_IDLE)
502 {
503 /* make sure scheduler is invoked when this reservation expires
504 * its remaining budget */
505 TRACE("[GMP] requesting scheduler update for reservation %u in %llu nanoseconds\n", res->id, res->cur_budget);
506 gmp_scheduler_update_after(gmp_env, res->cur_budget);
507 }
508// if (encountered_active)
509 /* stop at the first ACTIVE reservation */
510// break;
511 }
512 //TRACE("finished charging budgets\n");
513}
514
515static void gmp_replenish_budgets(struct gmp_reservation_environment* gmp_env)
516{
517 struct list_head *pos, *next;
518 struct reservation *res;
519
520 list_for_each_safe(pos, next, &gmp_env->depleted_reservations) {
521 res = list_entry(pos, struct reservation, list);
522 if (res->next_replenishment <= gmp_env->env.current_time) {
523 res->ops->replenish(res);
524 } else {
525 /* list is ordered by increasing depletion times */
526 break;
527 }
528 }
529 //TRACE("finished replenishing budgets\n");
530
531 /* request a scheduler update at the next replenishment instant */
532 res = list_first_entry_or_null(&gmp_env->depleted_reservations,
533 struct reservation, list);
534 if (res)
535 gmp_scheduler_update_at(gmp_env, res->next_replenishment);
536}
537
538void gmp_update_time(
539 struct gmp_reservation_environment* gmp_env,
540 lt_t now)
541{
542 lt_t delta;
543
544 /* If the time didn't advance, there is nothing to do.
545 * This check makes it safe to call gmp_advance_time() potentially
546 * multiple times (e.g., via different code paths. */
547 //TRACE("(gmp_update_time) now: %llu, current_time: %llu\n", now, gmp_env->env.current_time);
548 if (unlikely(now <= gmp_env->env.current_time))
549 return;
550
551 delta = now - gmp_env->env.current_time;
552 gmp_env->env.current_time = now;
553
554 /* deplete budgets by passage of time */
555 gmp_charge_budget(gmp_env, delta);
556
557 /* check if any budgets where replenished */
558 gmp_replenish_budgets(gmp_env);
559}
560
561struct task_struct* gmp_dispatch(struct gmp_reservation_environment* gmp_env)
562{
563 struct reservation *res, *next;
564 struct task_struct *tsk = NULL;
565 lt_t time_slice;
566
567 list_for_each_entry_safe(res, next, &gmp_env->active_reservations, list) {
568 if (res->state == RESERVATION_ACTIVE && res->scheduled_on == NO_CPU) {
569 tsk = res->ops->dispatch_client(res, &time_slice);
570 if (likely(tsk)) {
571 if (time_slice)
572 gmp_scheduler_update_after(gmp_env, time_slice);
573 gmp_scheduler_update_after(gmp_env, res->cur_budget);
574 return tsk;
575 }
576 }
577 }
578
579 return NULL;
580}
581
582static void gmp_res_change_state(
583 struct reservation_environment* env,
584 struct reservation *res,
585 reservation_state_t new_state)
586{
587 struct gmp_reservation_environment* gmp_env;
588
589 gmp_env = container_of(env, struct gmp_reservation_environment, env);
590
591 TRACE("[GMP] reservation R%d state %d->%d at %llu\n",
592 res->id, res->state, new_state, env->current_time);
593
594 list_del(&res->list);
595 /* check if we need to reschedule because we lost an active reservation */
596 if (res->state == RESERVATION_ACTIVE && !gmp_env->will_schedule)
597 gmp_env->schedule_now = true;
598 res->state = new_state;
599 gmp_queue_reservation(gmp_env, res);
600}
601
602void gmp_init(struct gmp_reservation_environment* gmp_env)
603{
604 memset(gmp_env, sizeof(*gmp_env), 0);
605
606 INIT_LIST_HEAD(&gmp_env->active_reservations);
607 INIT_LIST_HEAD(&gmp_env->depleted_reservations);
608 INIT_LIST_HEAD(&gmp_env->inactive_reservations);
609
610 gmp_env->env.change_state = gmp_res_change_state;
611
612 gmp_env->schedule_now = false;
613
614 //raw_spin_lock_init(&gmp_env->lock);
615 INIT_LIST_HEAD(&gmp_env->next_events);
616
617 raw_spin_lock_init(&gmp_env->event_lock);
618}