diff options
| author | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-21 15:54:21 -0500 |
|---|---|---|
| committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-21 15:54:21 -0500 |
| commit | 16a64e75ff5d1deeeb8adaaa0d11b1d6fe236bbe (patch) | |
| tree | 02c8bfade500a847e039ea340c1583d40d1e9fd6 | |
| parent | 6583dcfbda43e420921e3adf7f2e46dc719e8d26 (diff) | |
Initial lv C impl.wip-mc2
| -rw-r--r-- | include/litmus/reservation.h | 55 | ||||
| -rw-r--r-- | litmus/polling_reservations.c | 1 | ||||
| -rw-r--r-- | litmus/reservation.c | 303 | ||||
| -rw-r--r-- | litmus/sched_mc2.c | 453 |
4 files changed, 739 insertions, 73 deletions
diff --git a/include/litmus/reservation.h b/include/litmus/reservation.h index 4eecd3f088e8..0345d3482916 100644 --- a/include/litmus/reservation.h +++ b/include/litmus/reservation.h | |||
| @@ -126,6 +126,9 @@ struct reservation { | |||
| 126 | struct reservation_ops *ops; | 126 | struct reservation_ops *ops; |
| 127 | 127 | ||
| 128 | struct list_head clients; | 128 | struct list_head clients; |
| 129 | |||
| 130 | /* for global env. */ | ||
| 131 | int scheduled_on; | ||
| 129 | }; | 132 | }; |
| 130 | 133 | ||
| 131 | void reservation_init(struct reservation *res); | 134 | void reservation_init(struct reservation *res); |
| @@ -191,4 +194,56 @@ struct task_struct* sup_dispatch(struct sup_reservation_environment* sup_env); | |||
| 191 | struct reservation* sup_find_by_id(struct sup_reservation_environment* sup_env, | 194 | struct reservation* sup_find_by_id(struct sup_reservation_environment* sup_env, |
| 192 | unsigned int id); | 195 | unsigned int id); |
| 193 | 196 | ||
| 197 | #define ENV_RESCHEDULE_NOW (0) | ||
| 198 | #define ENV_NO_SCHEDULER_UPDATE (ULLONG_MAX) | ||
| 199 | |||
| 200 | struct next_timer_event { | ||
| 201 | lt_t next_event; | ||
| 202 | int timer_armed_on; | ||
| 203 | struct list_head list; | ||
| 204 | }; | ||
| 205 | |||
| 206 | /* A global multiprocessor reservation environment. | ||
| 207 | */ | ||
| 208 | struct gmp_reservation_environment { | ||
| 209 | //raw_spinlock_t lock; | ||
| 210 | struct reservation_environment env; | ||
| 211 | |||
| 212 | /* ordered by priority */ | ||
| 213 | struct list_head active_reservations; | ||
| 214 | |||
| 215 | /* ordered by next_replenishment */ | ||
| 216 | struct list_head depleted_reservations; | ||
| 217 | |||
| 218 | /* unordered */ | ||
| 219 | struct list_head inactive_reservations; | ||
| 220 | |||
| 221 | /* - ENV_RESCHEDULE_NOW means call gmp_dispatch() now | ||
| 222 | * - ENV_NO_SCHEDULER_UPDATE means nothing to do | ||
| 223 | * any other value means program a timer for the given time | ||
| 224 | */ | ||
| 225 | struct list_head next_events; | ||
| 226 | raw_spinlock_t event_lock; | ||
| 227 | bool schedule_now; | ||
| 228 | /* set to true if a call to gmp_dispatch() is imminent */ | ||
| 229 | bool will_schedule; | ||
| 230 | }; | ||
| 231 | |||
| 232 | /* Contract: | ||
| 233 | * - before calling into sup_ code, or any reservation methods, | ||
| 234 | * update the time with sup_update_time(); and | ||
| 235 | * - after calling into sup_ code, or any reservation methods, | ||
| 236 | * check next_scheduler_update and program timer or trigger | ||
| 237 | * scheduler invocation accordingly. | ||
| 238 | */ | ||
| 239 | |||
| 240 | void gmp_init(struct gmp_reservation_environment* gmp_env); | ||
| 241 | void gmp_add_new_reservation(struct gmp_reservation_environment* gmp_env, | ||
| 242 | struct reservation* new_res); | ||
| 243 | void gmp_update_time(struct gmp_reservation_environment* gmp_env, lt_t now); | ||
| 244 | struct task_struct* gmp_dispatch(struct gmp_reservation_environment* gmp_env); | ||
| 245 | |||
| 246 | struct reservation* gmp_find_by_id(struct gmp_reservation_environment* gmp_env, | ||
| 247 | unsigned int id); | ||
| 248 | |||
| 194 | #endif | 249 | #endif |
diff --git a/litmus/polling_reservations.c b/litmus/polling_reservations.c index 4c07ee74bf39..81f8e0f54ffd 100644 --- a/litmus/polling_reservations.c +++ b/litmus/polling_reservations.c | |||
| @@ -72,6 +72,7 @@ static void periodic_polling_client_departs( | |||
| 72 | /* do nothing */ | 72 | /* do nothing */ |
| 73 | break; | 73 | break; |
| 74 | } | 74 | } |
| 75 | res->scheduled_on = NO_CPU; | ||
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | static void periodic_polling_on_replenishment( | 78 | static void periodic_polling_on_replenishment( |
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 | } | ||
diff --git a/litmus/sched_mc2.c b/litmus/sched_mc2.c index b9f05238461b..3c8aa739345d 100644 --- a/litmus/sched_mc2.c +++ b/litmus/sched_mc2.c | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | #include <litmus/reservation.h> | 15 | #include <litmus/reservation.h> |
| 16 | #include <litmus/polling_reservations.h> | 16 | #include <litmus/polling_reservations.h> |
| 17 | 17 | ||
| 18 | struct gmp_reservation_environment _global_env; | ||
| 19 | |||
| 18 | struct mc2_task_state { | 20 | struct mc2_task_state { |
| 19 | struct task_client res_info; | 21 | struct task_client res_info; |
| 20 | int cpu; | 22 | int cpu; |
| @@ -26,11 +28,18 @@ struct mc2_cpu_state { | |||
| 26 | raw_spinlock_t lock; | 28 | raw_spinlock_t lock; |
| 27 | 29 | ||
| 28 | struct sup_reservation_environment sup_env; | 30 | struct sup_reservation_environment sup_env; |
| 31 | struct gmp_reservation_environment* gmp_env; | ||
| 29 | struct hrtimer timer; | 32 | struct hrtimer timer; |
| 30 | 33 | ||
| 31 | int cpu; | 34 | int cpu; |
| 32 | struct task_struct* scheduled; | 35 | struct task_struct* scheduled; |
| 36 | struct task_struct* will_schedule; | ||
| 37 | struct task_struct* linked; // for level C | ||
| 33 | enum crit_level run_level; | 38 | enum crit_level run_level; |
| 39 | struct task_struct* crit_entry[NUM_CRIT_LEVELS]; // mc2_task_state (get_mc2_state) | ||
| 40 | |||
| 41 | // indicate the current timer event is global | ||
| 42 | bool is_global_event; | ||
| 34 | }; | 43 | }; |
| 35 | 44 | ||
| 36 | static DEFINE_PER_CPU(struct mc2_cpu_state, mc2_cpu_state); | 45 | static DEFINE_PER_CPU(struct mc2_cpu_state, mc2_cpu_state); |
| @@ -74,12 +83,14 @@ static void mc2_update_timer_and_unlock(struct mc2_cpu_state *state) | |||
| 74 | { | 83 | { |
| 75 | int local; | 84 | int local; |
| 76 | lt_t update, now; | 85 | lt_t update, now; |
| 77 | 86 | struct next_timer_event *n_event = NULL; | |
| 87 | int global_found = 0; | ||
| 88 | |||
| 78 | update = state->sup_env.next_scheduler_update; | 89 | update = state->sup_env.next_scheduler_update; |
| 79 | now = state->sup_env.env.current_time; | 90 | now = state->sup_env.env.current_time; |
| 80 | 91 | ||
| 81 | /* Be sure we're actually running on the right core, | 92 | /* Be sure we're actually running on the right core, |
| 82 | * as pres_update_timer() is also called from pres_task_resume(), | 93 | * as mc2_update_timer() is also called from mc2_task_resume(), |
| 83 | * which might be called on any CPU when a thread resumes. | 94 | * which might be called on any CPU when a thread resumes. |
| 84 | */ | 95 | */ |
| 85 | local = local_cpu_state() == state; | 96 | local = local_cpu_state() == state; |
| @@ -87,16 +98,50 @@ static void mc2_update_timer_and_unlock(struct mc2_cpu_state *state) | |||
| 87 | /* Must drop state lock before calling into hrtimer_start(), which | 98 | /* Must drop state lock before calling into hrtimer_start(), which |
| 88 | * may raise a softirq, which in turn may wake ksoftirqd. */ | 99 | * may raise a softirq, which in turn may wake ksoftirqd. */ |
| 89 | raw_spin_unlock(&state->lock); | 100 | raw_spin_unlock(&state->lock); |
| 101 | |||
| 102 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 103 | list_for_each_entry(n_event, &state->gmp_env->next_events, list) { | ||
| 104 | TRACE("G_EVENT time: %llu, timer_armed_on: %d\n", n_event->next_event, n_event->timer_armed_on == NO_CPU?(-1):n_event->timer_armed_on); | ||
| 105 | if (n_event->timer_armed_on == NO_CPU) { | ||
| 106 | global_found = 1; | ||
| 107 | break; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | if (global_found == 1) { | ||
| 112 | if (update >= n_event->next_event) { | ||
| 113 | update = n_event->next_event; | ||
| 114 | now = _global_env.env.current_time; | ||
| 115 | //state->is_global_event = true; | ||
| 116 | //n_event->timer_armed_on = state->cpu; | ||
| 117 | } else { // next event is sup | ||
| 118 | global_found = 0; | ||
| 119 | } | ||
| 120 | } | ||
| 90 | 121 | ||
| 122 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 123 | |||
| 91 | if (update <= now) { | 124 | if (update <= now) { |
| 92 | litmus_reschedule(state->cpu); | 125 | litmus_reschedule(state->cpu); |
| 93 | } else if (likely(local && update != SUP_NO_SCHEDULER_UPDATE)) { | 126 | } else if (likely(local && update != SUP_NO_SCHEDULER_UPDATE)) { |
| 94 | /* Reprogram only if not already set correctly. */ | 127 | /* Reprogram only if not already set correctly. */ |
| 95 | if (!hrtimer_active(&state->timer) || | 128 | if (!hrtimer_active(&state->timer) || |
| 96 | ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) { | 129 | ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) { |
| 130 | |||
| 131 | if ((ktime_to_ns(hrtimer_get_expires(&state->timer)) > update) && (state->is_global_event == true)) { | ||
| 132 | struct next_timer_event *prev_event = NULL; | ||
| 133 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 134 | list_for_each_entry(prev_event, &state->gmp_env->next_events, list) { | ||
| 135 | if (prev_event->timer_armed_on == state->cpu) { | ||
| 136 | prev_event->timer_armed_on = NO_CPU; | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 141 | } | ||
| 97 | TRACE("canceling timer...\n"); | 142 | TRACE("canceling timer...\n"); |
| 98 | hrtimer_cancel(&state->timer); | 143 | hrtimer_cancel(&state->timer); |
| 99 | TRACE("setting scheduler timer for %llu\n", update); | 144 | TRACE("setting scheduler (global: %d) timer for %llu\n", state->is_global_event, update); |
| 100 | /* We cannot use hrtimer_start() here because the | 145 | /* We cannot use hrtimer_start() here because the |
| 101 | * wakeup flag must be set to zero. */ | 146 | * wakeup flag must be set to zero. */ |
| 102 | __hrtimer_start_range_ns(&state->timer, | 147 | __hrtimer_start_range_ns(&state->timer, |
| @@ -104,6 +149,16 @@ static void mc2_update_timer_and_unlock(struct mc2_cpu_state *state) | |||
| 104 | 0 /* timer coalescing slack */, | 149 | 0 /* timer coalescing slack */, |
| 105 | HRTIMER_MODE_ABS_PINNED, | 150 | HRTIMER_MODE_ABS_PINNED, |
| 106 | 0 /* wakeup */); | 151 | 0 /* wakeup */); |
| 152 | if (global_found) { | ||
| 153 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 154 | state->is_global_event = true; | ||
| 155 | n_event->timer_armed_on = state->cpu; | ||
| 156 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 157 | } else { | ||
| 158 | state->is_global_event = false; | ||
| 159 | } | ||
| 160 | |||
| 161 | TRACE("set scheduler (global: %d) timer for %llu on P%d\n", state->is_global_event, update, n_event->timer_armed_on); | ||
| 107 | } | 162 | } |
| 108 | } else if (unlikely(!local && update != SUP_NO_SCHEDULER_UPDATE)) { | 163 | } else if (unlikely(!local && update != SUP_NO_SCHEDULER_UPDATE)) { |
| 109 | /* Poke remote core only if timer needs to be set earlier than | 164 | /* Poke remote core only if timer needs to be set earlier than |
| @@ -132,6 +187,7 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | |||
| 132 | unsigned long flags; | 187 | unsigned long flags; |
| 133 | enum hrtimer_restart restart = HRTIMER_NORESTART; | 188 | enum hrtimer_restart restart = HRTIMER_NORESTART; |
| 134 | struct mc2_cpu_state *state; | 189 | struct mc2_cpu_state *state; |
| 190 | struct next_timer_event *n_event, *next; | ||
| 135 | lt_t update, now; | 191 | lt_t update, now; |
| 136 | 192 | ||
| 137 | state = container_of(timer, struct mc2_cpu_state, timer); | 193 | state = container_of(timer, struct mc2_cpu_state, timer); |
| @@ -144,16 +200,47 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | |||
| 144 | */ | 200 | */ |
| 145 | BUG_ON(state->cpu != raw_smp_processor_id()); | 201 | BUG_ON(state->cpu != raw_smp_processor_id()); |
| 146 | 202 | ||
| 203 | TRACE("TIMER fired at %llu\n", litmus_clock()); | ||
| 204 | |||
| 205 | if (state->is_global_event == true) { | ||
| 206 | |||
| 207 | raw_spin_lock_irqsave(&(_global_env.event_lock), flags); | ||
| 208 | |||
| 209 | TRACE("GLOBAL EVENT FIRED\n"); | ||
| 210 | list_for_each_entry_safe(n_event, next, &state->gmp_env->next_events, list) { | ||
| 211 | if (n_event->timer_armed_on == state->cpu) { | ||
| 212 | list_del(&n_event->list); | ||
| 213 | TRACE("EVENT ENTRY IS DELETED\n"); | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | gmp_update_time(state->gmp_env, litmus_clock()); | ||
| 218 | |||
| 219 | |||
| 220 | update = n_event->next_event; | ||
| 221 | now = state->gmp_env->env.current_time; | ||
| 222 | |||
| 223 | kfree(n_event); | ||
| 224 | TRACE("ON TIMER UPDATE = %llu, NOW = %llu\n", update, now); | ||
| 225 | raw_spin_unlock_irqrestore(&(_global_env.event_lock), flags); | ||
| 226 | } | ||
| 227 | |||
| 147 | raw_spin_lock_irqsave(&state->lock, flags); | 228 | raw_spin_lock_irqsave(&state->lock, flags); |
| 148 | sup_update_time(&state->sup_env, litmus_clock()); | 229 | |
| 149 | 230 | ||
| 150 | update = state->sup_env.next_scheduler_update; | 231 | if (state->is_global_event != true) { |
| 151 | now = state->sup_env.env.current_time; | 232 | sup_update_time(&state->sup_env, litmus_clock()); |
| 233 | |||
| 234 | update = state->sup_env.next_scheduler_update; | ||
| 235 | now = state->sup_env.env.current_time; | ||
| 236 | } else { | ||
| 237 | state->is_global_event = false; | ||
| 238 | } | ||
| 152 | 239 | ||
| 153 | TRACE_CUR("on_scheduling_timer at %llu, upd:%llu (for cpu=%d)\n", | 240 | TRACE_CUR("on_scheduling_timer at %llu, upd:%llu (for cpu=%d)\n", |
| 154 | now, update, state->cpu); | 241 | now, update, state->cpu); |
| 155 | 242 | ||
| 156 | if (update <= now) { | 243 | if (update <= now || state->gmp_env->schedule_now == true) { |
| 157 | litmus_reschedule_local(); | 244 | litmus_reschedule_local(); |
| 158 | } else if (update != SUP_NO_SCHEDULER_UPDATE) { | 245 | } else if (update != SUP_NO_SCHEDULER_UPDATE) { |
| 159 | hrtimer_set_expires(timer, ns_to_ktime(update)); | 246 | hrtimer_set_expires(timer, ns_to_ktime(update)); |
| @@ -161,7 +248,7 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | |||
| 161 | } | 248 | } |
| 162 | 249 | ||
| 163 | raw_spin_unlock_irqrestore(&state->lock, flags); | 250 | raw_spin_unlock_irqrestore(&state->lock, flags); |
| 164 | 251 | ||
| 165 | return restart; | 252 | return restart; |
| 166 | } | 253 | } |
| 167 | 254 | ||
| @@ -176,10 +263,20 @@ static struct task_struct* mc2_schedule(struct task_struct * prev) | |||
| 176 | BUG_ON(state->scheduled && state->scheduled != prev); | 263 | BUG_ON(state->scheduled && state->scheduled != prev); |
| 177 | BUG_ON(state->scheduled && !is_realtime(prev)); | 264 | BUG_ON(state->scheduled && !is_realtime(prev)); |
| 178 | 265 | ||
| 266 | tinfo = get_mc2_state(prev); | ||
| 267 | if (state->scheduled != NULL) { | ||
| 268 | struct reservation* res; | ||
| 269 | if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 270 | res = gmp_find_by_id(state->gmp_env, tinfo->mc2_param.res_id); | ||
| 271 | res->scheduled_on = NO_CPU; | ||
| 272 | prev->rt_param.scheduled_on = NO_CPU; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 179 | /* update time */ | 276 | /* update time */ |
| 180 | state->sup_env.will_schedule = true; | 277 | state->sup_env.will_schedule = true; |
| 181 | sup_update_time(&state->sup_env, litmus_clock()); | 278 | sup_update_time(&state->sup_env, litmus_clock()); |
| 182 | 279 | ||
| 183 | /* remove task from reservation if it blocks */ | 280 | /* remove task from reservation if it blocks */ |
| 184 | if (is_realtime(prev) && !is_running(prev)) | 281 | if (is_realtime(prev) && !is_running(prev)) |
| 185 | task_departs(prev, is_completed(prev)); | 282 | task_departs(prev, is_completed(prev)); |
| @@ -187,6 +284,17 @@ static struct task_struct* mc2_schedule(struct task_struct * prev) | |||
| 187 | /* figure out what to schedule next */ | 284 | /* figure out what to schedule next */ |
| 188 | state->scheduled = sup_dispatch(&state->sup_env); | 285 | state->scheduled = sup_dispatch(&state->sup_env); |
| 189 | 286 | ||
| 287 | if (!state->scheduled) { | ||
| 288 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 289 | |||
| 290 | state->gmp_env->will_schedule = true; | ||
| 291 | gmp_update_time(state->gmp_env, litmus_clock()); | ||
| 292 | //state->scheduled = gmp_dispatch(&_global_env); | ||
| 293 | state->gmp_env->will_schedule = false; | ||
| 294 | |||
| 295 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 296 | } | ||
| 297 | |||
| 190 | /* Notify LITMUS^RT core that we've arrived at a scheduling decision. */ | 298 | /* Notify LITMUS^RT core that we've arrived at a scheduling decision. */ |
| 191 | sched_state_task_picked(); | 299 | sched_state_task_picked(); |
| 192 | 300 | ||
| @@ -196,13 +304,27 @@ static struct task_struct* mc2_schedule(struct task_struct * prev) | |||
| 196 | mc2_update_timer_and_unlock(state); | 304 | mc2_update_timer_and_unlock(state); |
| 197 | 305 | ||
| 198 | if (prev != state->scheduled && is_realtime(prev)) { | 306 | if (prev != state->scheduled && is_realtime(prev)) { |
| 307 | struct reservation* res; | ||
| 199 | TRACE_TASK(prev, "descheduled.\n"); | 308 | TRACE_TASK(prev, "descheduled.\n"); |
| 309 | TRACE_TASK(state->scheduled, "SCHEDULED.\n"); | ||
| 200 | state->run_level = NUM_CRIT_LEVELS; | 310 | state->run_level = NUM_CRIT_LEVELS; |
| 311 | tinfo = get_mc2_state(prev); | ||
| 312 | if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 313 | res = gmp_find_by_id(state->gmp_env, tinfo->mc2_param.res_id); | ||
| 314 | res->scheduled_on = NO_CPU; | ||
| 315 | prev->rt_param.scheduled_on = NO_CPU; | ||
| 316 | } | ||
| 201 | } | 317 | } |
| 202 | if (state->scheduled) { | 318 | if (state->scheduled) { |
| 319 | struct reservation* res; | ||
| 203 | TRACE_TASK(state->scheduled, "scheduled.\n"); | 320 | TRACE_TASK(state->scheduled, "scheduled.\n"); |
| 204 | //tinfo = get_mc2_state(state->scheduled); | 321 | tinfo = get_mc2_state(state->scheduled); |
| 205 | //state->run_level = tinfo->mc2_param.crit; | 322 | state->run_level = tinfo->mc2_param.crit; |
| 323 | if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 324 | res = gmp_find_by_id(state->gmp_env, tinfo->mc2_param.res_id); | ||
| 325 | res->scheduled_on = state->cpu; | ||
| 326 | state->scheduled->rt_param.scheduled_on = state->cpu; | ||
| 327 | } | ||
| 206 | } | 328 | } |
| 207 | 329 | ||
| 208 | return state->scheduled; | 330 | return state->scheduled; |
| @@ -230,10 +352,16 @@ static void mc2_task_resume(struct task_struct *tsk) | |||
| 230 | { | 352 | { |
| 231 | unsigned long flags; | 353 | unsigned long flags; |
| 232 | struct mc2_task_state* tinfo = get_mc2_state(tsk); | 354 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
| 233 | struct mc2_cpu_state *state = cpu_state_for(tinfo->cpu); | 355 | struct mc2_cpu_state *state; // = cpu_state_for(tinfo->cpu); |
| 234 | 356 | ||
| 235 | TRACE_TASK(tsk, "thread wakes up at %llu\n", litmus_clock()); | 357 | TRACE_TASK(tsk, "thread wakes up at %llu\n", litmus_clock()); |
| 236 | 358 | ||
| 359 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { | ||
| 360 | state = cpu_state_for(tinfo->cpu); | ||
| 361 | } else { | ||
| 362 | state = local_cpu_state(); | ||
| 363 | } | ||
| 364 | |||
| 237 | raw_spin_lock_irqsave(&state->lock, flags); | 365 | raw_spin_lock_irqsave(&state->lock, flags); |
| 238 | /* Requeue only if self-suspension was already processed. */ | 366 | /* Requeue only if self-suspension was already processed. */ |
| 239 | if (tinfo->has_departed) | 367 | if (tinfo->has_departed) |
| @@ -241,8 +369,16 @@ static void mc2_task_resume(struct task_struct *tsk) | |||
| 241 | /* Assumption: litmus_clock() is synchronized across cores, | 369 | /* Assumption: litmus_clock() is synchronized across cores, |
| 242 | * since we might not actually be executing on tinfo->cpu | 370 | * since we might not actually be executing on tinfo->cpu |
| 243 | * at the moment. */ | 371 | * at the moment. */ |
| 244 | sup_update_time(&state->sup_env, litmus_clock()); | 372 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { |
| 245 | task_arrives(tsk); | 373 | sup_update_time(&state->sup_env, litmus_clock()); |
| 374 | task_arrives(tsk); | ||
| 375 | } else if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 376 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 377 | gmp_update_time(state->gmp_env, litmus_clock()); | ||
| 378 | task_arrives(tsk); | ||
| 379 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 380 | } | ||
| 381 | |||
| 246 | /* NOTE: drops state->lock */ | 382 | /* NOTE: drops state->lock */ |
| 247 | TRACE("mc2_resume()\n"); | 383 | TRACE("mc2_resume()\n"); |
| 248 | mc2_update_timer_and_unlock(state); | 384 | mc2_update_timer_and_unlock(state); |
| @@ -255,24 +391,40 @@ static void mc2_task_resume(struct task_struct *tsk) | |||
| 255 | resume_legacy_task_model_updates(tsk); | 391 | resume_legacy_task_model_updates(tsk); |
| 256 | } | 392 | } |
| 257 | 393 | ||
| 394 | static void mc2_task_block(struct task_struct *task) | ||
| 395 | { | ||
| 396 | struct mc2_task_state *tinfo; | ||
| 397 | |||
| 398 | tinfo = get_mc2_state(task); | ||
| 399 | |||
| 400 | TRACE_TASK(task, "TASK BLOCK\n"); | ||
| 401 | if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 402 | struct reservation *res = gmp_find_by_id(&_global_env, tinfo->mc2_param.res_id); | ||
| 403 | res->scheduled_on = NO_CPU; | ||
| 404 | task->rt_param.scheduled_on = NO_CPU; | ||
| 405 | } | ||
| 406 | } | ||
| 258 | /* syscall backend for job completions */ | 407 | /* syscall backend for job completions */ |
| 259 | static long mc2_complete_job(void) | 408 | static long mc2_complete_job(void) |
| 260 | { | 409 | { |
| 261 | ktime_t next_release; | 410 | ktime_t next_release; |
| 262 | long err; | 411 | long err; |
| 263 | struct mc2_cpu_state *state = local_cpu_state(); | 412 | struct mc2_cpu_state *state = local_cpu_state(); |
| 264 | struct reservation_environment *env = &(state->sup_env.env); | 413 | struct reservation_environment *env = NULL; |
| 265 | struct mc2_task_state *tinfo = get_mc2_state(current); | 414 | struct mc2_task_state *tinfo = get_mc2_state(current); |
| 266 | 415 | ||
| 416 | if (tinfo->mc2_param.crit == CRIT_LEVEL_C) | ||
| 417 | env = &(_global_env.env); | ||
| 418 | else | ||
| 419 | env = &(state->sup_env.env); | ||
| 267 | 420 | ||
| 268 | TRACE_CUR("mc2_complete_job at %llu (deadline: %llu)\n", litmus_clock(), | 421 | TRACE_CUR("mc2_complete_job at %llu (deadline: %llu)\n", litmus_clock(), get_deadline(current)); |
| 269 | get_deadline(current)); | ||
| 270 | 422 | ||
| 271 | tsk_rt(current)->completed = 1; | 423 | tsk_rt(current)->completed = 1; |
| 272 | 424 | ||
| 273 | if (tsk_rt(current)->sporadic_release) { | 425 | if (tsk_rt(current)->sporadic_release) { |
| 274 | env->time_zero = tsk_rt(current)->sporadic_release_time; | 426 | env->time_zero = tsk_rt(current)->sporadic_release_time; |
| 275 | 427 | hrtimer_cancel(&state->timer); | |
| 276 | if (tinfo->mc2_param.crit == CRIT_LEVEL_A) { | 428 | if (tinfo->mc2_param.crit == CRIT_LEVEL_A) { |
| 277 | struct reservation *res; | 429 | struct reservation *res; |
| 278 | struct table_driven_reservation *tdres; | 430 | struct table_driven_reservation *tdres; |
| @@ -286,7 +438,7 @@ static long mc2_complete_job(void) | |||
| 286 | res->next_replenishment += tdres->intervals[0].start; | 438 | res->next_replenishment += tdres->intervals[0].start; |
| 287 | res->env->change_state(res->env, res, RESERVATION_DEPLETED); | 439 | res->env->change_state(res->env, res, RESERVATION_DEPLETED); |
| 288 | 440 | ||
| 289 | TRACE_CUR("CHANGE NEXT_REP = %llu\n NEXT_UPDATE = %llu\n", res->next_replenishment, state->sup_env.next_scheduler_update); | 441 | TRACE_CUR("CHANGE NEXT_REP = %llu NEXT_UPDATE = %llu\n", res->next_replenishment, state->sup_env.next_scheduler_update); |
| 290 | } | 442 | } |
| 291 | 443 | ||
| 292 | } | 444 | } |
| @@ -327,32 +479,55 @@ static long mc2_admit_task(struct task_struct *tsk) | |||
| 327 | } | 479 | } |
| 328 | 480 | ||
| 329 | preempt_disable(); | 481 | preempt_disable(); |
| 330 | 482 | if (mp->crit == CRIT_LEVEL_C) { | |
| 331 | state = cpu_state_for(task_cpu(tsk)); | 483 | raw_spin_lock_irqsave(&(_global_env.event_lock), flags); |
| 332 | raw_spin_lock_irqsave(&state->lock, flags); | ||
| 333 | |||
| 334 | res = sup_find_by_id(&state->sup_env, mp->res_id); | ||
| 335 | |||
| 336 | /* found the appropriate reservation (or vCPU) */ | ||
| 337 | if (res) { | ||
| 338 | TRACE_TASK(tsk, "FOUND RES ID\n"); | ||
| 339 | tinfo->mc2_param.crit = mp->crit; | ||
| 340 | tinfo->mc2_param.res_id = mp->res_id; | ||
| 341 | 484 | ||
| 342 | kfree(tsk_rt(tsk)->plugin_state); | 485 | res = gmp_find_by_id(&_global_env, mp->res_id); |
| 343 | tsk_rt(tsk)->plugin_state = NULL; | 486 | if (res) { |
| 487 | TRACE_TASK(tsk, "FOUND GMP RES ID\n"); | ||
| 488 | tinfo->mc2_param.crit = mp->crit; | ||
| 489 | tinfo->mc2_param.res_id = mp->res_id; | ||
| 490 | |||
| 491 | kfree(tsk_rt(tsk)->plugin_state); | ||
| 492 | tsk_rt(tsk)->plugin_state = NULL; | ||
| 493 | |||
| 494 | err = mc2_task_client_init(&tinfo->res_info, &tinfo->mc2_param, tsk, res); | ||
| 495 | tinfo->cpu = -1; | ||
| 496 | tinfo->has_departed = true; | ||
| 497 | tsk_rt(tsk)->plugin_state = tinfo; | ||
| 498 | |||
| 499 | tsk_rt(tsk)->task_params.budget_policy = NO_ENFORCEMENT; | ||
| 500 | } | ||
| 344 | 501 | ||
| 345 | err = mc2_task_client_init(&tinfo->res_info, &tinfo->mc2_param, tsk, res); | 502 | raw_spin_unlock_irqrestore(&(_global_env.event_lock), flags); |
| 346 | tinfo->cpu = task_cpu(tsk); | 503 | |
| 347 | tinfo->has_departed = true; | 504 | } else { |
| 348 | tsk_rt(tsk)->plugin_state = tinfo; | 505 | state = cpu_state_for(task_cpu(tsk)); |
| 506 | raw_spin_lock_irqsave(&state->lock, flags); | ||
| 349 | 507 | ||
| 350 | /* disable LITMUS^RT's per-thread budget enforcement */ | 508 | res = sup_find_by_id(&state->sup_env, mp->res_id); |
| 351 | tsk_rt(tsk)->task_params.budget_policy = NO_ENFORCEMENT; | ||
| 352 | } | ||
| 353 | 509 | ||
| 354 | raw_spin_unlock_irqrestore(&state->lock, flags); | 510 | /* found the appropriate reservation (or vCPU) */ |
| 511 | if (res) { | ||
| 512 | TRACE_TASK(tsk, "FOUND SUP RES ID\n"); | ||
| 513 | tinfo->mc2_param.crit = mp->crit; | ||
| 514 | tinfo->mc2_param.res_id = mp->res_id; | ||
| 515 | |||
| 516 | kfree(tsk_rt(tsk)->plugin_state); | ||
| 517 | tsk_rt(tsk)->plugin_state = NULL; | ||
| 518 | |||
| 519 | err = mc2_task_client_init(&tinfo->res_info, &tinfo->mc2_param, tsk, res); | ||
| 520 | tinfo->cpu = task_cpu(tsk); | ||
| 521 | tinfo->has_departed = true; | ||
| 522 | tsk_rt(tsk)->plugin_state = tinfo; | ||
| 523 | |||
| 524 | /* disable LITMUS^RT's per-thread budget enforcement */ | ||
| 525 | tsk_rt(tsk)->task_params.budget_policy = NO_ENFORCEMENT; | ||
| 526 | } | ||
| 355 | 527 | ||
| 528 | raw_spin_unlock_irqrestore(&state->lock, flags); | ||
| 529 | } | ||
| 530 | |||
| 356 | preempt_enable(); | 531 | preempt_enable(); |
| 357 | 532 | ||
| 358 | if (err) | 533 | if (err) |
| @@ -366,15 +541,29 @@ static void mc2_task_new(struct task_struct *tsk, int on_runqueue, | |||
| 366 | { | 541 | { |
| 367 | unsigned long flags; | 542 | unsigned long flags; |
| 368 | struct mc2_task_state* tinfo = get_mc2_state(tsk); | 543 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
| 369 | struct mc2_cpu_state *state = cpu_state_for(tinfo->cpu); | 544 | struct mc2_cpu_state *state; // = cpu_state_for(tinfo->cpu); |
| 370 | struct reservation *res; | 545 | struct reservation *res; |
| 371 | 546 | ||
| 372 | TRACE_TASK(tsk, "new RT task %llu (on_rq:%d, running:%d)\n", | 547 | TRACE_TASK(tsk, "new RT task %llu (on_rq:%d, running:%d)\n", |
| 373 | litmus_clock(), on_runqueue, is_running); | 548 | litmus_clock(), on_runqueue, is_running); |
| 374 | 549 | ||
| 550 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { | ||
| 551 | state = cpu_state_for(tinfo->cpu); | ||
| 552 | } else { | ||
| 553 | state = local_cpu_state(); | ||
| 554 | } | ||
| 555 | |||
| 375 | /* acquire the lock protecting the state and disable interrupts */ | 556 | /* acquire the lock protecting the state and disable interrupts */ |
| 376 | raw_spin_lock_irqsave(&state->lock, flags); | 557 | raw_spin_lock_irqsave(&state->lock, flags); |
| 377 | 558 | ||
| 559 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { | ||
| 560 | res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); | ||
| 561 | } else { | ||
| 562 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 563 | res = gmp_find_by_id(&_global_env, tinfo->mc2_param.res_id); | ||
| 564 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 565 | } | ||
| 566 | |||
| 378 | if (is_running) { | 567 | if (is_running) { |
| 379 | state->scheduled = tsk; | 568 | state->scheduled = tsk; |
| 380 | /* make sure this task should actually be running */ | 569 | /* make sure this task should actually be running */ |
| @@ -384,7 +573,14 @@ static void mc2_task_new(struct task_struct *tsk, int on_runqueue, | |||
| 384 | if (on_runqueue || is_running) { | 573 | if (on_runqueue || is_running) { |
| 385 | /* Assumption: litmus_clock() is synchronized across cores | 574 | /* Assumption: litmus_clock() is synchronized across cores |
| 386 | * [see comment in pres_task_resume()] */ | 575 | * [see comment in pres_task_resume()] */ |
| 387 | sup_update_time(&state->sup_env, litmus_clock()); | 576 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { |
| 577 | sup_update_time(&state->sup_env, litmus_clock()); | ||
| 578 | } else if (tinfo->mc2_param.crit == CRIT_LEVEL_C) { | ||
| 579 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 580 | TRACE_TASK(tsk, "CALL GMP_UPDATE_TIME in task_new at %llu\n", litmus_clock()); | ||
| 581 | gmp_update_time(state->gmp_env, litmus_clock()); | ||
| 582 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 583 | } | ||
| 388 | task_arrives(tsk); | 584 | task_arrives(tsk); |
| 389 | /* NOTE: drops state->lock */ | 585 | /* NOTE: drops state->lock */ |
| 390 | TRACE("mc2_new()\n"); | 586 | TRACE("mc2_new()\n"); |
| @@ -393,7 +589,6 @@ static void mc2_task_new(struct task_struct *tsk, int on_runqueue, | |||
| 393 | } else | 589 | } else |
| 394 | raw_spin_unlock_irqrestore(&state->lock, flags); | 590 | raw_spin_unlock_irqrestore(&state->lock, flags); |
| 395 | 591 | ||
| 396 | res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); | ||
| 397 | release_at(tsk, res->next_replenishment); | 592 | release_at(tsk, res->next_replenishment); |
| 398 | if (res) | 593 | if (res) |
| 399 | TRACE_TASK(tsk, "next_replenishment = %llu\n", res->next_replenishment); | 594 | TRACE_TASK(tsk, "next_replenishment = %llu\n", res->next_replenishment); |
| @@ -407,9 +602,14 @@ static long mc2_reservation_destroy(unsigned int reservation_id, int cpu) | |||
| 407 | struct mc2_cpu_state *state; | 602 | struct mc2_cpu_state *state; |
| 408 | struct reservation *res = NULL, *next; | 603 | struct reservation *res = NULL, *next; |
| 409 | struct sup_reservation_environment *sup_env; | 604 | struct sup_reservation_environment *sup_env; |
| 605 | struct gmp_reservation_environment *gmp_env; | ||
| 410 | int found = 0; | 606 | int found = 0; |
| 411 | 607 | ||
| 412 | state = cpu_state_for(cpu); | 608 | if (cpu != -1) |
| 609 | state = cpu_state_for(cpu); | ||
| 610 | else | ||
| 611 | state = local_cpu_state(); | ||
| 612 | |||
| 413 | raw_spin_lock(&state->lock); | 613 | raw_spin_lock(&state->lock); |
| 414 | 614 | ||
| 415 | // res = sup_find_by_id(&state->sup_env, reservation_id); | 615 | // res = sup_find_by_id(&state->sup_env, reservation_id); |
| @@ -447,6 +647,43 @@ static long mc2_reservation_destroy(unsigned int reservation_id, int cpu) | |||
| 447 | 647 | ||
| 448 | raw_spin_unlock(&state->lock); | 648 | raw_spin_unlock(&state->lock); |
| 449 | 649 | ||
| 650 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 651 | |||
| 652 | gmp_env = &_global_env; | ||
| 653 | //if (!res) { | ||
| 654 | if (!found) { | ||
| 655 | list_for_each_entry_safe(res, next, &gmp_env->depleted_reservations, list) { | ||
| 656 | if (res->id == reservation_id) { | ||
| 657 | list_del(&res->list); | ||
| 658 | //kfree(res); | ||
| 659 | found = 1; | ||
| 660 | ret = 0; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | if (!found) { | ||
| 665 | list_for_each_entry_safe(res, next, &gmp_env->inactive_reservations, list) { | ||
| 666 | if (res->id == reservation_id) { | ||
| 667 | list_del(&res->list); | ||
| 668 | //kfree(res); | ||
| 669 | found = 1; | ||
| 670 | ret = 0; | ||
| 671 | } | ||
| 672 | } | ||
| 673 | } | ||
| 674 | if (!found) { | ||
| 675 | list_for_each_entry_safe(res, next, &gmp_env->active_reservations, list) { | ||
| 676 | if (res->id == reservation_id) { | ||
| 677 | list_del(&res->list); | ||
| 678 | //kfree(res); | ||
| 679 | found = 1; | ||
| 680 | ret = 0; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 686 | |||
| 450 | TRACE("RESERVATION_DESTROY ret = %d\n", ret); | 687 | TRACE("RESERVATION_DESTROY ret = %d\n", ret); |
| 451 | return ret; | 688 | return ret; |
| 452 | } | 689 | } |
| @@ -455,8 +692,14 @@ static void mc2_task_exit(struct task_struct *tsk) | |||
| 455 | { | 692 | { |
| 456 | unsigned long flags; | 693 | unsigned long flags; |
| 457 | struct mc2_task_state* tinfo = get_mc2_state(tsk); | 694 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
| 458 | struct mc2_cpu_state *state = cpu_state_for(tinfo->cpu); | 695 | struct mc2_cpu_state *state; // = cpu_state_for(tinfo->cpu); |
| 459 | 696 | ||
| 697 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) { | ||
| 698 | state = cpu_state_for(tinfo->cpu); | ||
| 699 | } else { | ||
| 700 | state = local_cpu_state(); | ||
| 701 | } | ||
| 702 | |||
| 460 | raw_spin_lock_irqsave(&state->lock, flags); | 703 | raw_spin_lock_irqsave(&state->lock, flags); |
| 461 | 704 | ||
| 462 | if (state->scheduled == tsk) | 705 | if (state->scheduled == tsk) |
| @@ -466,7 +709,13 @@ static void mc2_task_exit(struct task_struct *tsk) | |||
| 466 | if (is_running(tsk)) { | 709 | if (is_running(tsk)) { |
| 467 | /* Assumption: litmus_clock() is synchronized across cores | 710 | /* Assumption: litmus_clock() is synchronized across cores |
| 468 | * [see comment in pres_task_resume()] */ | 711 | * [see comment in pres_task_resume()] */ |
| 469 | sup_update_time(&state->sup_env, litmus_clock()); | 712 | if (tinfo->mc2_param.crit != CRIT_LEVEL_C) |
| 713 | sup_update_time(&state->sup_env, litmus_clock()); | ||
| 714 | else { | ||
| 715 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 716 | gmp_update_time(state->gmp_env, litmus_clock()); | ||
| 717 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 718 | } | ||
| 470 | task_departs(tsk, 0); | 719 | task_departs(tsk, 0); |
| 471 | /* NOTE: drops state->lock */ | 720 | /* NOTE: drops state->lock */ |
| 472 | TRACE("mc2_exit()\n"); | 721 | TRACE("mc2_exit()\n"); |
| @@ -505,7 +754,7 @@ static long create_polling_reservation( | |||
| 505 | int use_edf = config->priority == LITMUS_NO_PRIORITY; | 754 | int use_edf = config->priority == LITMUS_NO_PRIORITY; |
| 506 | int periodic = res_type == PERIODIC_POLLING; | 755 | int periodic = res_type == PERIODIC_POLLING; |
| 507 | long err = -EINVAL; | 756 | long err = -EINVAL; |
| 508 | 757 | ||
| 509 | if (config->polling_params.budget > | 758 | if (config->polling_params.budget > |
| 510 | config->polling_params.period) { | 759 | config->polling_params.period) { |
| 511 | printk(KERN_ERR "invalid polling reservation (%u): " | 760 | printk(KERN_ERR "invalid polling reservation (%u): " |
| @@ -533,26 +782,48 @@ static long create_polling_reservation( | |||
| 533 | if (!pres) | 782 | if (!pres) |
| 534 | return -ENOMEM; | 783 | return -ENOMEM; |
| 535 | 784 | ||
| 536 | state = cpu_state_for(config->cpu); | 785 | if (config->cpu != -1) { |
| 537 | raw_spin_lock_irqsave(&state->lock, flags); | 786 | state = cpu_state_for(config->cpu); |
| 787 | raw_spin_lock_irqsave(&state->lock, flags); | ||
| 538 | 788 | ||
| 539 | res = sup_find_by_id(&state->sup_env, config->id); | 789 | res = sup_find_by_id(&state->sup_env, config->id); |
| 540 | if (!res) { | 790 | if (!res) { |
| 541 | polling_reservation_init(pres, use_edf, periodic, | 791 | polling_reservation_init(pres, use_edf, periodic, |
| 542 | config->polling_params.budget, | 792 | config->polling_params.budget, |
| 543 | config->polling_params.period, | 793 | config->polling_params.period, |
| 544 | config->polling_params.relative_deadline, | 794 | config->polling_params.relative_deadline, |
| 545 | config->polling_params.offset); | 795 | config->polling_params.offset); |
| 546 | pres->res.id = config->id; | 796 | pres->res.id = config->id; |
| 547 | if (!use_edf) | 797 | if (!use_edf) |
| 548 | pres->res.priority = config->priority; | 798 | pres->res.priority = config->priority; |
| 549 | sup_add_new_reservation(&state->sup_env, &pres->res); | 799 | sup_add_new_reservation(&state->sup_env, &pres->res); |
| 550 | err = config->id; | 800 | err = config->id; |
| 551 | } else { | 801 | } else { |
| 552 | err = -EEXIST; | 802 | err = -EEXIST; |
| 553 | } | 803 | } |
| 554 | 804 | ||
| 555 | raw_spin_unlock_irqrestore(&state->lock, flags); | 805 | raw_spin_unlock_irqrestore(&state->lock, flags); |
| 806 | } else if (config->cpu == -1) { | ||
| 807 | raw_spin_lock_irqsave(&(_global_env.event_lock), flags); | ||
| 808 | |||
| 809 | res = gmp_find_by_id(&_global_env, config->id); | ||
| 810 | if (!res) { | ||
| 811 | polling_reservation_init(pres, use_edf, periodic, | ||
| 812 | config->polling_params.budget, | ||
| 813 | config->polling_params.period, | ||
| 814 | config->polling_params.relative_deadline, | ||
| 815 | config->polling_params.offset); | ||
| 816 | pres->res.id = config->id; | ||
| 817 | if (!use_edf) | ||
| 818 | pres->res.priority = config->priority; | ||
| 819 | gmp_add_new_reservation(&_global_env, &pres->res); | ||
| 820 | err = config->id; | ||
| 821 | } else { | ||
| 822 | err = -EEXIST; | ||
| 823 | } | ||
| 824 | |||
| 825 | raw_spin_unlock_irqrestore(&(_global_env.event_lock), flags); | ||
| 826 | } | ||
| 556 | 827 | ||
| 557 | if (err < 0) | 828 | if (err < 0) |
| 558 | kfree(pres); | 829 | kfree(pres); |
| @@ -671,10 +942,12 @@ static long mc2_reservation_create(int res_type, void* __user _config) | |||
| 671 | if (copy_from_user(&config, _config, sizeof(config))) | 942 | if (copy_from_user(&config, _config, sizeof(config))) |
| 672 | return -EFAULT; | 943 | return -EFAULT; |
| 673 | 944 | ||
| 674 | if (config.cpu < 0 || !cpu_online(config.cpu)) { | 945 | if (config.cpu != -1) { |
| 675 | printk(KERN_ERR "invalid polling reservation (%u): " | 946 | if (config.cpu < 0 || !cpu_online(config.cpu)) { |
| 676 | "CPU %d offline\n", config.id, config.cpu); | 947 | printk(KERN_ERR "invalid polling reservation (%u): " |
| 677 | return -EINVAL; | 948 | "CPU %d offline\n", config.id, config.cpu); |
| 949 | return -EINVAL; | ||
| 950 | } | ||
| 678 | } | 951 | } |
| 679 | 952 | ||
| 680 | switch (res_type) { | 953 | switch (res_type) { |
| @@ -732,6 +1005,8 @@ static long mc2_activate_plugin(void) | |||
| 732 | int cpu; | 1005 | int cpu; |
| 733 | struct mc2_cpu_state *state; | 1006 | struct mc2_cpu_state *state; |
| 734 | 1007 | ||
| 1008 | gmp_init(&_global_env); | ||
| 1009 | |||
| 735 | for_each_online_cpu(cpu) { | 1010 | for_each_online_cpu(cpu) { |
| 736 | TRACE("Initializing CPU%d...\n", cpu); | 1011 | TRACE("Initializing CPU%d...\n", cpu); |
| 737 | 1012 | ||
| @@ -740,7 +1015,11 @@ static long mc2_activate_plugin(void) | |||
| 740 | raw_spin_lock_init(&state->lock); | 1015 | raw_spin_lock_init(&state->lock); |
| 741 | state->cpu = cpu; | 1016 | state->cpu = cpu; |
| 742 | state->scheduled = NULL; | 1017 | state->scheduled = NULL; |
| 743 | 1018 | state->will_schedule = NULL; | |
| 1019 | state->linked = NULL; | ||
| 1020 | state->gmp_env = &_global_env; | ||
| 1021 | state->is_global_event = false; | ||
| 1022 | |||
| 744 | sup_init(&state->sup_env); | 1023 | sup_init(&state->sup_env); |
| 745 | 1024 | ||
| 746 | hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); | 1025 | hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); |
| @@ -794,6 +1073,37 @@ static long mc2_deactivate_plugin(void) | |||
| 794 | raw_spin_unlock(&state->lock); | 1073 | raw_spin_unlock(&state->lock); |
| 795 | } | 1074 | } |
| 796 | 1075 | ||
| 1076 | raw_spin_lock(&(_global_env.event_lock)); | ||
| 1077 | |||
| 1078 | /* Delete all reservations --- assumes struct reservation | ||
| 1079 | * is prefix of containing struct. */ | ||
| 1080 | |||
| 1081 | while (!list_empty(&_global_env.active_reservations)) { | ||
| 1082 | res = list_first_entry( | ||
| 1083 | &_global_env.active_reservations, | ||
| 1084 | struct reservation, list); | ||
| 1085 | list_del(&res->list); | ||
| 1086 | kfree(res); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | while (!list_empty(&_global_env.inactive_reservations)) { | ||
| 1090 | res = list_first_entry( | ||
| 1091 | &_global_env.inactive_reservations, | ||
| 1092 | struct reservation, list); | ||
| 1093 | list_del(&res->list); | ||
| 1094 | kfree(res); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | while (!list_empty(&_global_env.depleted_reservations)) { | ||
| 1098 | res = list_first_entry( | ||
| 1099 | &_global_env.depleted_reservations, | ||
| 1100 | struct reservation, list); | ||
| 1101 | list_del(&res->list); | ||
| 1102 | kfree(res); | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | raw_spin_unlock(&(_global_env.event_lock)); | ||
| 1106 | |||
| 797 | destroy_domain_proc_info(&mc2_domain_proc_info); | 1107 | destroy_domain_proc_info(&mc2_domain_proc_info); |
| 798 | return 0; | 1108 | return 0; |
| 799 | } | 1109 | } |
| @@ -802,6 +1112,7 @@ static struct sched_plugin mc2_plugin = { | |||
| 802 | .plugin_name = "MC2", | 1112 | .plugin_name = "MC2", |
| 803 | .schedule = mc2_schedule, | 1113 | .schedule = mc2_schedule, |
| 804 | .task_wake_up = mc2_task_resume, | 1114 | .task_wake_up = mc2_task_resume, |
| 1115 | .task_block = mc2_task_block, | ||
| 805 | .admit_task = mc2_admit_task, | 1116 | .admit_task = mc2_admit_task, |
| 806 | .task_new = mc2_task_new, | 1117 | .task_new = mc2_task_new, |
| 807 | .task_exit = mc2_task_exit, | 1118 | .task_exit = mc2_task_exit, |
