diff options
Diffstat (limited to 'litmus/reservation.c')
-rw-r--r-- | litmus/reservation.c | 303 |
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 | |||
321 | static 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 | |||
352 | static 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 | |||
359 | static 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 | |||
381 | static 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 | |||
392 | static 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 | |||
413 | static 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 | |||
430 | static 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 | |||
451 | void 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 | |||
460 | struct 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 | |||
481 | static 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 | |||
515 | static 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 | |||
538 | void 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 | |||
561 | struct 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 | |||
582 | static 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 | |||
602 | void 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 | } | ||