diff options
author | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-24 04:55:04 -0500 |
---|---|---|
committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-24 04:55:04 -0500 |
commit | 5be3aecdd4b8b0beb981cc0f7fc84b0d0ded2c47 (patch) | |
tree | 7df48cce968c60a37b9c11d4b03b852b201f5d67 | |
parent | 6583dcfbda43e420921e3adf7f2e46dc719e8d26 (diff) |
slack stealing
-rw-r--r-- | include/litmus/mc2_common.h | 2 | ||||
-rw-r--r-- | include/litmus/reservation.h | 44 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 4 | ||||
-rw-r--r-- | litmus/jobs.c | 1 | ||||
-rw-r--r-- | litmus/polling_reservations.c | 28 | ||||
-rw-r--r-- | litmus/reservation.c | 16 | ||||
-rw-r--r-- | litmus/sched_mc2.c | 185 |
7 files changed, 237 insertions, 43 deletions
diff --git a/include/litmus/mc2_common.h b/include/litmus/mc2_common.h index bdc3a6d82a56..e3c0af28f1b9 100644 --- a/include/litmus/mc2_common.h +++ b/include/litmus/mc2_common.h | |||
@@ -21,6 +21,8 @@ struct mc2_task { | |||
21 | 21 | ||
22 | #include <litmus/reservation.h> | 22 | #include <litmus/reservation.h> |
23 | 23 | ||
24 | #define tsk_mc2_data(t) (tsk_rt(t)->mc2_data) | ||
25 | |||
24 | long mc2_task_client_init(struct task_client *tc, struct mc2_task *mc2_param, struct task_struct *tsk, | 26 | long mc2_task_client_init(struct task_client *tc, struct mc2_task *mc2_param, struct task_struct *tsk, |
25 | struct reservation *res); | 27 | struct reservation *res); |
26 | 28 | ||
diff --git a/include/litmus/reservation.h b/include/litmus/reservation.h index 4eecd3f088e8..5ccb20055a56 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); |
@@ -185,10 +188,51 @@ struct sup_reservation_environment { | |||
185 | void sup_init(struct sup_reservation_environment* sup_env); | 188 | void sup_init(struct sup_reservation_environment* sup_env); |
186 | void sup_add_new_reservation(struct sup_reservation_environment* sup_env, | 189 | void sup_add_new_reservation(struct sup_reservation_environment* sup_env, |
187 | struct reservation* new_res); | 190 | struct reservation* new_res); |
191 | void sup_scheduler_update_after(struct sup_reservation_environment* sup_env, | ||
192 | lt_t timeout); | ||
188 | void sup_update_time(struct sup_reservation_environment* sup_env, lt_t now); | 193 | void sup_update_time(struct sup_reservation_environment* sup_env, lt_t now); |
189 | struct task_struct* sup_dispatch(struct sup_reservation_environment* sup_env); | 194 | struct task_struct* sup_dispatch(struct sup_reservation_environment* sup_env); |
190 | 195 | ||
191 | struct reservation* sup_find_by_id(struct sup_reservation_environment* sup_env, | 196 | struct reservation* sup_find_by_id(struct sup_reservation_environment* sup_env, |
192 | unsigned int id); | 197 | unsigned int id); |
198 | |||
199 | /* A global multiprocessor reservation environment. */ | ||
193 | 200 | ||
201 | struct next_timer_event { | ||
202 | lt_t next_update; | ||
203 | int timer_armed_on; | ||
204 | unsigned int id; | ||
205 | struct list_head list; | ||
206 | }; | ||
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 | /* timer event ordered by next_update */ | ||
222 | struct list_head next_events; | ||
223 | /* (schedule_now == true) means call gmp_dispatch() now */ | ||
224 | bool schedule_now; | ||
225 | /* set to true if a call to gmp_dispatch() is imminent */ | ||
226 | bool will_schedule; | ||
227 | }; | ||
228 | /* | ||
229 | void gmp_init(struct gmp_reservation_environment* gmp_env); | ||
230 | void gmp_add_new_reservation(struct gmp_reservation_environment* gmp_env, | ||
231 | struct reservation* new_res); | ||
232 | void gmp_update_time(struct gmp_reservation_environment* gmp_env, lt_t now); | ||
233 | struct task_struct* gmp_dispatch(struct gmp_reservation_environment* gmp_env); | ||
234 | |||
235 | struct reservation* gmp_find_by_id(struct gmp_reservation_environment* gmp_env, | ||
236 | unsigned int id); | ||
237 | */ | ||
194 | #endif | 238 | #endif |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index e626bbbe60d5..284b89e95a51 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -206,6 +206,7 @@ struct rt_job { | |||
206 | }; | 206 | }; |
207 | 207 | ||
208 | struct pfair_param; | 208 | struct pfair_param; |
209 | struct mc2_task; | ||
209 | 210 | ||
210 | /* RT task parameters for scheduling extensions | 211 | /* RT task parameters for scheduling extensions |
211 | * These parameters are inherited during clone and therefore must | 212 | * These parameters are inherited during clone and therefore must |
@@ -322,6 +323,9 @@ struct rt_param { | |||
322 | 323 | ||
323 | /* Pointer to the page shared between userspace and kernel. */ | 324 | /* Pointer to the page shared between userspace and kernel. */ |
324 | struct control_page * ctrl_page; | 325 | struct control_page * ctrl_page; |
326 | |||
327 | /* Mixed-criticality specific data */ | ||
328 | struct mc2_task* mc2_data; | ||
325 | }; | 329 | }; |
326 | 330 | ||
327 | #endif | 331 | #endif |
diff --git a/litmus/jobs.c b/litmus/jobs.c index 547222c3387a..e523e29ea8a6 100644 --- a/litmus/jobs.c +++ b/litmus/jobs.c | |||
@@ -45,6 +45,7 @@ void release_at(struct task_struct *t, lt_t start) | |||
45 | { | 45 | { |
46 | BUG_ON(!t); | 46 | BUG_ON(!t); |
47 | setup_release(t, start); | 47 | setup_release(t, start); |
48 | TRACE("RELEASE!!\n"); | ||
48 | tsk_rt(t)->completed = 0; | 49 | tsk_rt(t)->completed = 0; |
49 | } | 50 | } |
50 | 51 | ||
diff --git a/litmus/polling_reservations.c b/litmus/polling_reservations.c index 4c07ee74bf39..941a371c26e9 100644 --- a/litmus/polling_reservations.c +++ b/litmus/polling_reservations.c | |||
@@ -19,11 +19,19 @@ static void periodic_polling_client_arrives( | |||
19 | switch (res->state) { | 19 | switch (res->state) { |
20 | case RESERVATION_INACTIVE: | 20 | case RESERVATION_INACTIVE: |
21 | /* Figure out next replenishment time. */ | 21 | /* Figure out next replenishment time. */ |
22 | tmp = res->env->current_time - res->env->time_zero; | 22 | if (res->env->time_zero == 0) { |
23 | instances = div64_u64(tmp, pres->period); | 23 | tmp = res->env->current_time - res->env->time_zero; |
24 | res->next_replenishment = | 24 | instances = div64_u64(tmp, pres->period); |
25 | (instances + 1) * pres->period + pres->offset; | 25 | res->next_replenishment = |
26 | 26 | (instances + 1) * pres->period + pres->offset; | |
27 | } | ||
28 | else { | ||
29 | tmp = res->env->current_time - res->env->time_zero; | ||
30 | instances = div64_u64(tmp, pres->period); | ||
31 | res->next_replenishment = res->env->time_zero + instances * pres->period; | ||
32 | } | ||
33 | |||
34 | TRACE("ENV_TIME_ZERO %llu\n", res->env->time_zero); | ||
27 | TRACE("pol-res: activate tmp=%llu instances=%llu period=%llu nextrp=%llu cur=%llu\n", | 35 | TRACE("pol-res: activate tmp=%llu instances=%llu period=%llu nextrp=%llu cur=%llu\n", |
28 | tmp, instances, pres->period, res->next_replenishment, | 36 | tmp, instances, pres->period, res->next_replenishment, |
29 | res->env->current_time); | 37 | res->env->current_time); |
@@ -62,9 +70,10 @@ static void periodic_polling_client_departs( | |||
62 | case RESERVATION_ACTIVE: | 70 | case RESERVATION_ACTIVE: |
63 | if (list_empty(&res->clients)) { | 71 | if (list_empty(&res->clients)) { |
64 | res->env->change_state(res->env, res, | 72 | res->env->change_state(res->env, res, |
65 | did_signal_job_completion ? | ||
66 | RESERVATION_DEPLETED : | ||
67 | RESERVATION_ACTIVE_IDLE); | 73 | RESERVATION_ACTIVE_IDLE); |
74 | // did_signal_job_completion ? | ||
75 | // RESERVATION_DEPLETED : | ||
76 | // RESERVATION_ACTIVE_IDLE); | ||
68 | } /* else: nothing to do, more clients ready */ | 77 | } /* else: nothing to do, more clients ready */ |
69 | break; | 78 | break; |
70 | 79 | ||
@@ -86,6 +95,7 @@ static void periodic_polling_on_replenishment( | |||
86 | res->next_replenishment += pres->period; | 95 | res->next_replenishment += pres->period; |
87 | res->budget_consumed = 0; | 96 | res->budget_consumed = 0; |
88 | 97 | ||
98 | TRACE("polling_replenish(%u): next_replenishment=%llu\n", res->id, res->next_replenishment); | ||
89 | switch (res->state) { | 99 | switch (res->state) { |
90 | case RESERVATION_DEPLETED: | 100 | case RESERVATION_DEPLETED: |
91 | case RESERVATION_INACTIVE: | 101 | case RESERVATION_INACTIVE: |
@@ -270,6 +280,7 @@ void polling_reservation_init( | |||
270 | pres->period = period; | 280 | pres->period = period; |
271 | pres->deadline = deadline; | 281 | pres->deadline = deadline; |
272 | pres->offset = offset; | 282 | pres->offset = offset; |
283 | TRACE_TASK(current, "polling_reservation_init: periodic %d, use_edf %d\n", use_periodic_polling, use_edf_prio); | ||
273 | if (use_periodic_polling) { | 284 | if (use_periodic_polling) { |
274 | if (use_edf_prio) | 285 | if (use_edf_prio) |
275 | pres->res.ops = &periodic_polling_ops_edf; | 286 | pres->res.ops = &periodic_polling_ops_edf; |
@@ -460,7 +471,8 @@ static void td_drain_budget( | |||
460 | switch (res->state) { | 471 | switch (res->state) { |
461 | case RESERVATION_DEPLETED: | 472 | case RESERVATION_DEPLETED: |
462 | case RESERVATION_INACTIVE: | 473 | case RESERVATION_INACTIVE: |
463 | BUG(); | 474 | //BUG(); |
475 | TRACE("TD_DRAIN!!!!!!!!! RES_STATE = %d\n", res->state); | ||
464 | break; | 476 | break; |
465 | 477 | ||
466 | case RESERVATION_ACTIVE_IDLE: | 478 | case RESERVATION_ACTIVE_IDLE: |
diff --git a/litmus/reservation.c b/litmus/reservation.c index 0e43479ff2e1..2dc3dc2b4688 100644 --- a/litmus/reservation.c +++ b/litmus/reservation.c | |||
@@ -48,11 +48,12 @@ static void sup_scheduler_update_at( | |||
48 | struct sup_reservation_environment* sup_env, | 48 | struct sup_reservation_environment* sup_env, |
49 | lt_t when) | 49 | lt_t when) |
50 | { | 50 | { |
51 | TRACE("SCHEDULER_UPDATE_AT update: %llu > when %llu\n", sup_env->next_scheduler_update, when); | ||
51 | if (sup_env->next_scheduler_update > when) | 52 | if (sup_env->next_scheduler_update > when) |
52 | sup_env->next_scheduler_update = when; | 53 | sup_env->next_scheduler_update = when; |
53 | } | 54 | } |
54 | 55 | ||
55 | static void sup_scheduler_update_after( | 56 | void sup_scheduler_update_after( |
56 | struct sup_reservation_environment* sup_env, | 57 | struct sup_reservation_environment* sup_env, |
57 | lt_t timeout) | 58 | lt_t timeout) |
58 | { | 59 | { |
@@ -192,10 +193,13 @@ static void sup_charge_budget( | |||
192 | /* charge all ACTIVE_IDLE up to the first ACTIVE reservation */ | 193 | /* charge all ACTIVE_IDLE up to the first ACTIVE reservation */ |
193 | res = list_entry(pos, struct reservation, list); | 194 | res = list_entry(pos, struct reservation, list); |
194 | if (res->state == RESERVATION_ACTIVE) { | 195 | if (res->state == RESERVATION_ACTIVE) { |
195 | res->ops->drain_budget(res, delta); | 196 | TRACE("sup_charge_budget ACTIVE R%u drain %llu\n", res->id, delta); |
197 | if (encountered_active == 0) | ||
198 | res->ops->drain_budget(res, delta); | ||
196 | encountered_active = 1; | 199 | encountered_active = 1; |
197 | } else { | 200 | } else { |
198 | BUG_ON(res->state != RESERVATION_ACTIVE_IDLE); | 201 | BUG_ON(res->state != RESERVATION_ACTIVE_IDLE); |
202 | TRACE("sup_charge_budget INACTIVE R%u drain %llu\n", res->id, delta); | ||
199 | res->ops->drain_budget(res, delta); | 203 | res->ops->drain_budget(res, delta); |
200 | } | 204 | } |
201 | if (res->state == RESERVATION_ACTIVE || | 205 | if (res->state == RESERVATION_ACTIVE || |
@@ -207,9 +211,9 @@ static void sup_charge_budget( | |||
207 | res->id, res->cur_budget); | 211 | res->id, res->cur_budget); |
208 | sup_scheduler_update_after(sup_env, res->cur_budget); | 212 | sup_scheduler_update_after(sup_env, res->cur_budget); |
209 | } | 213 | } |
210 | if (encountered_active) | 214 | //if (encountered_active == 2) |
211 | /* stop at the first ACTIVE reservation */ | 215 | /* stop at the first ACTIVE reservation */ |
212 | break; | 216 | // break; |
213 | } | 217 | } |
214 | //TRACE("finished charging budgets\n"); | 218 | //TRACE("finished charging budgets\n"); |
215 | } | 219 | } |
@@ -246,7 +250,7 @@ void sup_update_time( | |||
246 | /* If the time didn't advance, there is nothing to do. | 250 | /* If the time didn't advance, there is nothing to do. |
247 | * This check makes it safe to call sup_advance_time() potentially | 251 | * This check makes it safe to call sup_advance_time() potentially |
248 | * multiple times (e.g., via different code paths. */ | 252 | * multiple times (e.g., via different code paths. */ |
249 | //TRACE("(sup_update_time) now: %llu, current_time: %llu\n", now, sup_env->env.current_time); | 253 | TRACE("(sup_update_time) now: %llu, current_time: %llu\n", now, sup_env->env.current_time); |
250 | if (unlikely(now <= sup_env->env.current_time)) | 254 | if (unlikely(now <= sup_env->env.current_time)) |
251 | return; | 255 | return; |
252 | 256 | ||
@@ -258,9 +262,11 @@ void sup_update_time( | |||
258 | sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE; | 262 | sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE; |
259 | 263 | ||
260 | /* deplete budgets by passage of time */ | 264 | /* deplete budgets by passage of time */ |
265 | TRACE("CHARGE###\n"); | ||
261 | sup_charge_budget(sup_env, delta); | 266 | sup_charge_budget(sup_env, delta); |
262 | 267 | ||
263 | /* check if any budgets where replenished */ | 268 | /* check if any budgets where replenished */ |
269 | TRACE("REPLENISH###\n"); | ||
264 | sup_replenish_budgets(sup_env); | 270 | sup_replenish_budgets(sup_env); |
265 | } | 271 | } |
266 | 272 | ||
diff --git a/litmus/sched_mc2.c b/litmus/sched_mc2.c index b9f05238461b..6b29d527fa3a 100644 --- a/litmus/sched_mc2.c +++ b/litmus/sched_mc2.c | |||
@@ -22,15 +22,22 @@ struct mc2_task_state { | |||
22 | struct mc2_task mc2_param; | 22 | struct mc2_task mc2_param; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct crit_entry { | ||
26 | enum crit_level level; | ||
27 | struct task_struct *running; | ||
28 | struct hrtimer ghost_timer; | ||
29 | }; | ||
30 | |||
25 | struct mc2_cpu_state { | 31 | struct mc2_cpu_state { |
26 | raw_spinlock_t lock; | 32 | raw_spinlock_t lock; |
27 | 33 | ||
28 | struct sup_reservation_environment sup_env; | 34 | struct sup_reservation_environment sup_env; |
29 | struct hrtimer timer; | 35 | struct hrtimer timer; |
36 | struct hrtimer g_timer; | ||
30 | 37 | ||
31 | int cpu; | 38 | int cpu; |
32 | struct task_struct* scheduled; | 39 | struct task_struct* scheduled; |
33 | enum crit_level run_level; | 40 | struct crit_entry crit_entries[NUM_CRIT_LEVELS]; |
34 | }; | 41 | }; |
35 | 42 | ||
36 | static DEFINE_PER_CPU(struct mc2_cpu_state, mc2_cpu_state); | 43 | static DEFINE_PER_CPU(struct mc2_cpu_state, mc2_cpu_state); |
@@ -42,30 +49,53 @@ static struct mc2_task_state* get_mc2_state(struct task_struct *tsk) | |||
42 | { | 49 | { |
43 | return (struct mc2_task_state*) tsk_rt(tsk)->plugin_state; | 50 | return (struct mc2_task_state*) tsk_rt(tsk)->plugin_state; |
44 | } | 51 | } |
52 | static enum crit_level get_task_crit_level(struct task_struct *tsk) | ||
53 | { | ||
54 | struct mc2_task_state *tinfo = get_mc2_state(tsk); | ||
55 | if (!tinfo) | ||
56 | return NUM_CRIT_LEVELS; | ||
57 | else | ||
58 | return tinfo->mc2_param.crit; | ||
59 | } | ||
45 | 60 | ||
46 | static void task_departs(struct task_struct *tsk, int job_complete) | 61 | static void task_departs(struct task_struct *tsk, int job_complete) |
47 | { | 62 | { |
48 | struct mc2_task_state* state = get_mc2_state(tsk); | 63 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
64 | struct mc2_cpu_state* state = local_cpu_state(); | ||
49 | struct reservation* res; | 65 | struct reservation* res; |
50 | struct reservation_client *client; | 66 | struct reservation_client *client; |
51 | 67 | ||
52 | res = state->res_info.client.reservation; | 68 | res = tinfo->res_info.client.reservation; |
53 | client = &state->res_info.client; | 69 | client = &tinfo->res_info.client; |
54 | 70 | ||
55 | res->ops->client_departs(res, client, job_complete); | 71 | res->ops->client_departs(res, client, job_complete); |
56 | state->has_departed = true; | 72 | tinfo->has_departed = true; |
73 | TRACE_TASK(tsk, "CLIENT DEPART with budget %llu\n", res->cur_budget); | ||
74 | if (job_complete && res->cur_budget) { | ||
75 | struct crit_entry* ce; | ||
76 | enum crit_level lv = tinfo->mc2_param.crit; | ||
77 | //lt_t now = litmus_clock(); | ||
78 | |||
79 | ce = &state->crit_entries[lv]; | ||
80 | ce->running = tsk; | ||
81 | TRACE_TASK(tsk, "BECOME GHOST at %llu\n", litmus_clock()); | ||
82 | |||
83 | BUG_ON(hrtimer_active(&ce->ghost_timer)); | ||
84 | //TRACE("setting GHOST timer %llu\n", ns_to_ktime(now + res->cur_budget)); | ||
85 | //__hrtimer_start_range_ns(&ce->ghost_timer, ns_to_ktime(now + res->cur_budget), 0, HRTIMER_MODE_ABS_PINNED, 0); | ||
86 | } | ||
57 | } | 87 | } |
58 | 88 | ||
59 | static void task_arrives(struct task_struct *tsk) | 89 | static void task_arrives(struct task_struct *tsk) |
60 | { | 90 | { |
61 | struct mc2_task_state* state = get_mc2_state(tsk); | 91 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
62 | struct reservation* res; | 92 | struct reservation* res; |
63 | struct reservation_client *client; | 93 | struct reservation_client *client; |
64 | 94 | ||
65 | res = state->res_info.client.reservation; | 95 | res = tinfo->res_info.client.reservation; |
66 | client = &state->res_info.client; | 96 | client = &tinfo->res_info.client; |
67 | 97 | ||
68 | state->has_departed = false; | 98 | tinfo->has_departed = false; |
69 | res->ops->client_arrives(res, client); | 99 | res->ops->client_arrives(res, client); |
70 | } | 100 | } |
71 | 101 | ||
@@ -94,7 +124,7 @@ static void mc2_update_timer_and_unlock(struct mc2_cpu_state *state) | |||
94 | /* Reprogram only if not already set correctly. */ | 124 | /* Reprogram only if not already set correctly. */ |
95 | if (!hrtimer_active(&state->timer) || | 125 | if (!hrtimer_active(&state->timer) || |
96 | ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) { | 126 | ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) { |
97 | TRACE("canceling timer...\n"); | 127 | TRACE("canceling timer...at %llu\n", ktime_to_ns(hrtimer_get_expires(&state->timer))); |
98 | hrtimer_cancel(&state->timer); | 128 | hrtimer_cancel(&state->timer); |
99 | TRACE("setting scheduler timer for %llu\n", update); | 129 | TRACE("setting scheduler timer for %llu\n", update); |
100 | /* We cannot use hrtimer_start() here because the | 130 | /* We cannot use hrtimer_start() here because the |
@@ -127,6 +157,49 @@ static void mc2_update_timer_and_unlock(struct mc2_cpu_state *state) | |||
127 | } | 157 | } |
128 | } | 158 | } |
129 | 159 | ||
160 | static void mc2_update_ghost_state(struct mc2_cpu_state *state) | ||
161 | { | ||
162 | int lv = 0; | ||
163 | struct crit_entry* ce; | ||
164 | struct reservation *res; | ||
165 | struct mc2_task_state *tinfo; | ||
166 | |||
167 | for (lv = 0; lv < NUM_CRIT_LEVELS; lv++) { | ||
168 | ce = &state->crit_entries[lv]; | ||
169 | if (ce->running != NULL) { | ||
170 | tinfo = get_mc2_state(ce->running); | ||
171 | if (lv != CRIT_LEVEL_C) | ||
172 | res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); | ||
173 | else | ||
174 | continue; | ||
175 | TRACE("LV %d running id %d budget %llu\n", lv, tinfo->mc2_param.res_id, res->cur_budget); | ||
176 | if (!res->cur_budget) { | ||
177 | TRACE("GHOST FINISH id %d at %llu\n", tinfo->mc2_param.res_id, litmus_clock()); | ||
178 | ce->running = NULL; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static enum hrtimer_restart on_ghost_timer(struct hrtimer *timer) | ||
185 | { | ||
186 | struct crit_entry *ce; | ||
187 | struct mc2_cpu_state *state; | ||
188 | |||
189 | ce = container_of(timer, struct crit_entry, ghost_timer); | ||
190 | state = container_of(ce, struct mc2_cpu_state, crit_entries[ce->level]); | ||
191 | |||
192 | TRACE("GHOST_TIMER FIRED at %llu\n", litmus_clock()); | ||
193 | |||
194 | raw_spin_lock(&state->lock); | ||
195 | sup_update_time(&state->sup_env, litmus_clock()); | ||
196 | mc2_update_ghost_state(state); | ||
197 | |||
198 | raw_spin_unlock(&state->lock); | ||
199 | |||
200 | return HRTIMER_NORESTART; | ||
201 | } | ||
202 | |||
130 | static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | 203 | static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) |
131 | { | 204 | { |
132 | unsigned long flags; | 205 | unsigned long flags; |
@@ -144,9 +217,11 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | |||
144 | */ | 217 | */ |
145 | BUG_ON(state->cpu != raw_smp_processor_id()); | 218 | BUG_ON(state->cpu != raw_smp_processor_id()); |
146 | 219 | ||
220 | TRACE("TIMER FIRED at %llu\n", litmus_clock()); | ||
147 | raw_spin_lock_irqsave(&state->lock, flags); | 221 | raw_spin_lock_irqsave(&state->lock, flags); |
148 | sup_update_time(&state->sup_env, litmus_clock()); | 222 | sup_update_time(&state->sup_env, litmus_clock()); |
149 | 223 | mc2_update_ghost_state(state); | |
224 | |||
150 | update = state->sup_env.next_scheduler_update; | 225 | update = state->sup_env.next_scheduler_update; |
151 | now = state->sup_env.env.current_time; | 226 | now = state->sup_env.env.current_time; |
152 | 227 | ||
@@ -165,6 +240,36 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer) | |||
165 | return restart; | 240 | return restart; |
166 | } | 241 | } |
167 | 242 | ||
243 | struct task_struct* mc2_dispatch(struct sup_reservation_environment* sup_env, struct mc2_cpu_state* state) | ||
244 | { | ||
245 | struct reservation *res, *next; | ||
246 | struct task_struct *tsk = NULL; | ||
247 | struct crit_entry *ce; | ||
248 | enum crit_level lv; | ||
249 | lt_t time_slice; | ||
250 | |||
251 | list_for_each_entry_safe(res, next, &sup_env->active_reservations, list) { | ||
252 | if (res->state == RESERVATION_ACTIVE) { | ||
253 | tsk = res->ops->dispatch_client(res, &time_slice); | ||
254 | if (likely(tsk)) { | ||
255 | lv = get_task_crit_level(tsk); | ||
256 | if (lv == NUM_CRIT_LEVELS) { | ||
257 | sup_scheduler_update_after(sup_env, res->cur_budget); | ||
258 | return tsk; | ||
259 | } else { | ||
260 | ce = &state->crit_entries[lv]; | ||
261 | if (likely(!ce->running)) { | ||
262 | sup_scheduler_update_after(sup_env, res->cur_budget); | ||
263 | return tsk; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | return NULL; | ||
271 | } | ||
272 | |||
168 | static struct task_struct* mc2_schedule(struct task_struct * prev) | 273 | static struct task_struct* mc2_schedule(struct task_struct * prev) |
169 | { | 274 | { |
170 | /* next == NULL means "schedule background work". */ | 275 | /* next == NULL means "schedule background work". */ |
@@ -178,14 +283,17 @@ static struct task_struct* mc2_schedule(struct task_struct * prev) | |||
178 | 283 | ||
179 | /* update time */ | 284 | /* update time */ |
180 | state->sup_env.will_schedule = true; | 285 | state->sup_env.will_schedule = true; |
286 | TRACE_TASK(prev, "MC2_SCHEDULE sup_update_time ####\n"); | ||
181 | sup_update_time(&state->sup_env, litmus_clock()); | 287 | sup_update_time(&state->sup_env, litmus_clock()); |
182 | 288 | TRACE_TASK(prev, "MC2_SCHEDULE sup_update_time !!!!\n"); | |
289 | mc2_update_ghost_state(state); | ||
290 | |||
183 | /* remove task from reservation if it blocks */ | 291 | /* remove task from reservation if it blocks */ |
184 | if (is_realtime(prev) && !is_running(prev)) | 292 | if (is_realtime(prev) && !is_running(prev)) |
185 | task_departs(prev, is_completed(prev)); | 293 | task_departs(prev, is_completed(prev)); |
186 | 294 | ||
187 | /* figure out what to schedule next */ | 295 | /* figure out what to schedule next */ |
188 | state->scheduled = sup_dispatch(&state->sup_env); | 296 | state->scheduled = mc2_dispatch(&state->sup_env, state); |
189 | 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(); |
@@ -197,7 +305,6 @@ static struct task_struct* mc2_schedule(struct task_struct * prev) | |||
197 | 305 | ||
198 | if (prev != state->scheduled && is_realtime(prev)) { | 306 | if (prev != state->scheduled && is_realtime(prev)) { |
199 | TRACE_TASK(prev, "descheduled.\n"); | 307 | TRACE_TASK(prev, "descheduled.\n"); |
200 | state->run_level = NUM_CRIT_LEVELS; | ||
201 | } | 308 | } |
202 | if (state->scheduled) { | 309 | if (state->scheduled) { |
203 | TRACE_TASK(state->scheduled, "scheduled.\n"); | 310 | TRACE_TASK(state->scheduled, "scheduled.\n"); |
@@ -242,9 +349,10 @@ static void mc2_task_resume(struct task_struct *tsk) | |||
242 | * since we might not actually be executing on tinfo->cpu | 349 | * since we might not actually be executing on tinfo->cpu |
243 | * at the moment. */ | 350 | * at the moment. */ |
244 | sup_update_time(&state->sup_env, litmus_clock()); | 351 | sup_update_time(&state->sup_env, litmus_clock()); |
352 | mc2_update_ghost_state(state); | ||
245 | task_arrives(tsk); | 353 | task_arrives(tsk); |
246 | /* NOTE: drops state->lock */ | 354 | /* NOTE: drops state->lock */ |
247 | TRACE("mc2_resume()\n"); | 355 | TRACE_TASK(tsk, "mc2_resume()\n"); |
248 | mc2_update_timer_and_unlock(state); | 356 | mc2_update_timer_and_unlock(state); |
249 | local_irq_restore(flags); | 357 | local_irq_restore(flags); |
250 | } else { | 358 | } else { |
@@ -263,34 +371,36 @@ static long mc2_complete_job(void) | |||
263 | struct mc2_cpu_state *state = local_cpu_state(); | 371 | struct mc2_cpu_state *state = local_cpu_state(); |
264 | struct reservation_environment *env = &(state->sup_env.env); | 372 | struct reservation_environment *env = &(state->sup_env.env); |
265 | struct mc2_task_state *tinfo = get_mc2_state(current); | 373 | struct mc2_task_state *tinfo = get_mc2_state(current); |
374 | struct reservation *res; | ||
266 | 375 | ||
376 | res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); | ||
377 | if (!res) | ||
378 | ; // find in global env | ||
267 | 379 | ||
268 | TRACE_CUR("mc2_complete_job at %llu (deadline: %llu)\n", litmus_clock(), | 380 | TRACE_CUR("mc2_complete_job at %llu (deadline: %llu) (cur->budget: %llu)\n", litmus_clock(), |
269 | get_deadline(current)); | 381 | get_deadline(current), res->cur_budget); |
270 | 382 | ||
271 | tsk_rt(current)->completed = 1; | 383 | tsk_rt(current)->completed = 1; |
272 | 384 | ||
273 | if (tsk_rt(current)->sporadic_release) { | 385 | if (tsk_rt(current)->sporadic_release) { |
274 | env->time_zero = tsk_rt(current)->sporadic_release_time; | 386 | env->time_zero = tsk_rt(current)->sporadic_release_time; |
275 | 387 | res->next_replenishment = tsk_rt(current)->sporadic_release_time; | |
388 | res->cur_budget = 0; | ||
389 | res->env->change_state(res->env, res, RESERVATION_DEPLETED); | ||
390 | |||
276 | if (tinfo->mc2_param.crit == CRIT_LEVEL_A) { | 391 | if (tinfo->mc2_param.crit == CRIT_LEVEL_A) { |
277 | struct reservation *res; | ||
278 | struct table_driven_reservation *tdres; | 392 | struct table_driven_reservation *tdres; |
279 | 393 | ||
280 | sup_update_time(&state->sup_env, litmus_clock()); | 394 | //sup_update_time(&state->sup_env, litmus_clock()); |
281 | res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); | 395 | //res = sup_find_by_id(&state->sup_env, tinfo->mc2_param.res_id); |
282 | tdres = container_of(res, struct table_driven_reservation, res); | 396 | tdres = container_of(res, struct table_driven_reservation, res); |
283 | tdres->next_interval = 0; | 397 | tdres->next_interval = 0; |
284 | tdres->major_cycle_start = tsk_rt(current)->sporadic_release_time; | 398 | tdres->major_cycle_start = tsk_rt(current)->sporadic_release_time; |
285 | res->next_replenishment = tsk_rt(current)->sporadic_release_time; | 399 | res->next_replenishment += tdres->intervals[0].start; |
286 | res->next_replenishment += tdres->intervals[0].start; | ||
287 | res->env->change_state(res->env, res, RESERVATION_DEPLETED); | ||
288 | |||
289 | TRACE_CUR("CHANGE NEXT_REP = %llu\n NEXT_UPDATE = %llu\n", res->next_replenishment, state->sup_env.next_scheduler_update); | ||
290 | } | 400 | } |
291 | 401 | TRACE_CUR("CHANGE NEXT_REP = %llu\n NEXT_UPDATE = %llu\n", res->next_replenishment, state->sup_env.next_scheduler_update); | |
292 | } | 402 | } |
293 | 403 | ||
294 | prepare_for_next_period(current); | 404 | prepare_for_next_period(current); |
295 | next_release = ns_to_ktime(get_release(current)); | 405 | next_release = ns_to_ktime(get_release(current)); |
296 | preempt_disable(); | 406 | preempt_disable(); |
@@ -385,6 +495,7 @@ static void mc2_task_new(struct task_struct *tsk, int on_runqueue, | |||
385 | /* Assumption: litmus_clock() is synchronized across cores | 495 | /* Assumption: litmus_clock() is synchronized across cores |
386 | * [see comment in pres_task_resume()] */ | 496 | * [see comment in pres_task_resume()] */ |
387 | sup_update_time(&state->sup_env, litmus_clock()); | 497 | sup_update_time(&state->sup_env, litmus_clock()); |
498 | mc2_update_ghost_state(state); | ||
388 | task_arrives(tsk); | 499 | task_arrives(tsk); |
389 | /* NOTE: drops state->lock */ | 500 | /* NOTE: drops state->lock */ |
390 | TRACE("mc2_new()\n"); | 501 | TRACE("mc2_new()\n"); |
@@ -456,18 +567,26 @@ static void mc2_task_exit(struct task_struct *tsk) | |||
456 | unsigned long flags; | 567 | unsigned long flags; |
457 | struct mc2_task_state* tinfo = get_mc2_state(tsk); | 568 | struct mc2_task_state* tinfo = get_mc2_state(tsk); |
458 | struct mc2_cpu_state *state = cpu_state_for(tinfo->cpu); | 569 | struct mc2_cpu_state *state = cpu_state_for(tinfo->cpu); |
570 | enum crit_level lv = tinfo->mc2_param.crit; | ||
571 | struct crit_entry* ce; | ||
459 | 572 | ||
460 | raw_spin_lock_irqsave(&state->lock, flags); | 573 | raw_spin_lock_irqsave(&state->lock, flags); |
461 | 574 | ||
462 | if (state->scheduled == tsk) | 575 | if (state->scheduled == tsk) |
463 | state->scheduled = NULL; | 576 | state->scheduled = NULL; |
464 | 577 | ||
578 | ce = &state->crit_entries[lv]; | ||
579 | if (ce->running == tsk) | ||
580 | ce->running = NULL; | ||
581 | |||
465 | /* remove from queues */ | 582 | /* remove from queues */ |
466 | if (is_running(tsk)) { | 583 | if (is_running(tsk)) { |
467 | /* Assumption: litmus_clock() is synchronized across cores | 584 | /* Assumption: litmus_clock() is synchronized across cores |
468 | * [see comment in pres_task_resume()] */ | 585 | * [see comment in pres_task_resume()] */ |
469 | sup_update_time(&state->sup_env, litmus_clock()); | 586 | sup_update_time(&state->sup_env, litmus_clock()); |
587 | mc2_update_ghost_state(state); | ||
470 | task_departs(tsk, 0); | 588 | task_departs(tsk, 0); |
589 | |||
471 | /* NOTE: drops state->lock */ | 590 | /* NOTE: drops state->lock */ |
472 | TRACE("mc2_exit()\n"); | 591 | TRACE("mc2_exit()\n"); |
473 | mc2_update_timer_and_unlock(state); | 592 | mc2_update_timer_and_unlock(state); |
@@ -729,7 +848,7 @@ static void mc2_setup_domain_proc(void) | |||
729 | 848 | ||
730 | static long mc2_activate_plugin(void) | 849 | static long mc2_activate_plugin(void) |
731 | { | 850 | { |
732 | int cpu; | 851 | int cpu, lv; |
733 | struct mc2_cpu_state *state; | 852 | struct mc2_cpu_state *state; |
734 | 853 | ||
735 | for_each_online_cpu(cpu) { | 854 | for_each_online_cpu(cpu) { |
@@ -740,7 +859,13 @@ static long mc2_activate_plugin(void) | |||
740 | raw_spin_lock_init(&state->lock); | 859 | raw_spin_lock_init(&state->lock); |
741 | state->cpu = cpu; | 860 | state->cpu = cpu; |
742 | state->scheduled = NULL; | 861 | state->scheduled = NULL; |
743 | 862 | for (lv = 0; lv < NUM_CRIT_LEVELS; lv++) { | |
863 | struct crit_entry *ce = &state->crit_entries[lv]; | ||
864 | ce->level = lv; | ||
865 | ce->running = NULL; | ||
866 | hrtimer_init(&ce->ghost_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); | ||
867 | ce->ghost_timer.function = on_ghost_timer; | ||
868 | } | ||
744 | sup_init(&state->sup_env); | 869 | sup_init(&state->sup_env); |
745 | 870 | ||
746 | hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); | 871 | hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); |