diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2011-09-21 00:09:18 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2011-09-21 00:10:41 -0400 |
commit | 536d91a595c116ca869b3a07a35873cbeff37db3 (patch) | |
tree | dd3b32db071e7c7af24dff5c59c87c94e2af51d8 | |
parent | 313bcb226f88d17b193f9e7db7ecb4f57320a596 (diff) |
Passes simple tests.
-rw-r--r-- | include/litmus/sched_mc.h | 2 | ||||
-rw-r--r-- | litmus/litmus.c | 2 | ||||
-rw-r--r-- | litmus/sched_mc_ce.c | 198 |
3 files changed, 138 insertions, 64 deletions
diff --git a/include/litmus/sched_mc.h b/include/litmus/sched_mc.h index 32ef68150c81..94ec895afca0 100644 --- a/include/litmus/sched_mc.h +++ b/include/litmus/sched_mc.h | |||
@@ -21,6 +21,8 @@ struct mc_task { | |||
21 | struct mc_job { | 21 | struct mc_job { |
22 | int is_ghost:1; | 22 | int is_ghost:1; |
23 | lt_t ghost_budget; | 23 | lt_t ghost_budget; |
24 | /* which invocation of the CE is this */ | ||
25 | unsigned int expected_job; | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | #ifdef __KERNEL__ | 28 | #ifdef __KERNEL__ |
diff --git a/litmus/litmus.c b/litmus/litmus.c index 7db9fdadc7db..272fa8419a8a 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -288,7 +288,7 @@ asmlinkage long sys_set_rt_task_mc_param(pid_t pid, struct mc_task __user *param | |||
288 | struct task_struct *target; | 288 | struct task_struct *target; |
289 | int retval = -EINVAL; | 289 | int retval = -EINVAL; |
290 | 290 | ||
291 | printk("Setting up mixed-criicality task parameters for process %d.\n", | 291 | printk("Setting up mixed-criticality task parameters for process %d.\n", |
292 | pid); | 292 | pid); |
293 | 293 | ||
294 | if (pid < 0 || param == 0) { | 294 | if (pid < 0 || param == 0) { |
diff --git a/litmus/sched_mc_ce.c b/litmus/sched_mc_ce.c index 1fdca7a7d3aa..32865c2d9c22 100644 --- a/litmus/sched_mc_ce.c +++ b/litmus/sched_mc_ce.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <litmus/rt_param.h> | 21 | #include <litmus/rt_param.h> |
22 | #include <litmus/sched_mc.h> | 22 | #include <litmus/sched_mc.h> |
23 | #include <litmus/litmus_proc.h> | 23 | #include <litmus/litmus_proc.h> |
24 | #include <litmus/sched_trace.h> | ||
24 | 25 | ||
25 | static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; | 26 | static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; |
26 | 27 | ||
@@ -31,7 +32,6 @@ static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; | |||
31 | static atomic_t start_time_set = ATOMIC_INIT(0); | 32 | static atomic_t start_time_set = ATOMIC_INIT(0); |
32 | static atomic64_t start_time = ATOMIC64_INIT(0); | 33 | static atomic64_t start_time = ATOMIC64_INIT(0); |
33 | static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL; | 34 | static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL; |
34 | static DEFINE_RAW_SPINLOCK(activate_lock); | ||
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Cache the budget along with the struct PID for a task so that we don't need | 37 | * Cache the budget along with the struct PID for a task so that we don't need |
@@ -40,9 +40,8 @@ static DEFINE_RAW_SPINLOCK(activate_lock); | |||
40 | */ | 40 | */ |
41 | struct ce_dom_pid_entry { | 41 | struct ce_dom_pid_entry { |
42 | struct pid *pid; | 42 | struct pid *pid; |
43 | /* execution cost (sometimes called budget) */ | 43 | lt_t budget; |
44 | lt_t exec_cost; | 44 | /* accumulated (summed) budgets, including this one */ |
45 | /* accumulated (summed) exec costs, including this one */ | ||
46 | lt_t acc_time; | 45 | lt_t acc_time; |
47 | }; | 46 | }; |
48 | 47 | ||
@@ -64,22 +63,29 @@ DEFINE_PER_CPU(domain_t, mc_ce_doms); | |||
64 | DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data); | 63 | DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data); |
65 | 64 | ||
66 | /* | 65 | /* |
66 | * Get the offset into the cycle taking the start time into account. | ||
67 | */ | ||
68 | static inline lt_t get_cycle_offset(const lt_t when, const lt_t cycle_time) | ||
69 | { | ||
70 | return (when - atomic64_read(&start_time)) % cycle_time; | ||
71 | } | ||
72 | |||
73 | /* | ||
67 | * Return the index into the PID entries table of what to schedule next. | 74 | * Return the index into the PID entries table of what to schedule next. |
68 | * Don't call if the table is empty. Assumes the caller has the domain lock. | 75 | * Don't call if the table is empty. Assumes the caller has the domain lock. |
76 | * The offset parameter is the offset into the cycle. | ||
69 | * | 77 | * |
70 | * TODO Currently O(n) in the number of tasks on the CPU. Binary search? | 78 | * TODO Currently O(n) in the number of tasks on the CPU. Binary search? |
71 | */ | 79 | */ |
72 | static int mc_ce_schedule_at(const lt_t when, const domain_t *dom) | 80 | static int mc_ce_schedule_at(const domain_t *dom, lt_t offset) |
73 | { | 81 | { |
74 | const struct ce_dom_data *ce_data = dom->data; | 82 | const struct ce_dom_data *ce_data = dom->data; |
75 | const struct ce_dom_pid_entry *pid_entry = NULL; | 83 | const struct ce_dom_pid_entry *pid_entry = NULL; |
76 | lt_t offset; | ||
77 | int i; | 84 | int i; |
78 | 85 | ||
79 | BUG_ON(ce_data->cycle_time < 1); | 86 | BUG_ON(ce_data->cycle_time < 1); |
80 | BUG_ON(ce_data->num_pid_entries < 1); | 87 | BUG_ON(ce_data->num_pid_entries < 1); |
81 | 88 | ||
82 | offset = (when - atomic64_read(&start_time)) % ce_data->cycle_time; | ||
83 | for (i = 0; i < ce_data->num_pid_entries; ++i) { | 89 | for (i = 0; i < ce_data->num_pid_entries; ++i) { |
84 | pid_entry = &ce_data->pid_entries[i]; | 90 | pid_entry = &ce_data->pid_entries[i]; |
85 | if (offset < pid_entry->acc_time) { | 91 | if (offset < pid_entry->acc_time) { |
@@ -89,6 +95,7 @@ static int mc_ce_schedule_at(const lt_t when, const domain_t *dom) | |||
89 | } | 95 | } |
90 | /* can only happen if cycle_time is not right */ | 96 | /* can only happen if cycle_time is not right */ |
91 | BUG_ON(pid_entry->acc_time > ce_data->cycle_time); | 97 | BUG_ON(pid_entry->acc_time > ce_data->cycle_time); |
98 | TRACE("MC-CE schedule at returned task %d for CPU %d\n", i, ce_data->cpu); | ||
92 | return i; | 99 | return i; |
93 | } | 100 | } |
94 | 101 | ||
@@ -117,11 +124,14 @@ static struct task_struct *mc_ce_schedule(struct task_struct *prev) | |||
117 | request_exit_np(ce_data->scheduled); | 124 | request_exit_np(ce_data->scheduled); |
118 | next = prev; | 125 | next = prev; |
119 | } else if (ce_data->should_schedule && | 126 | } else if (ce_data->should_schedule && |
120 | is_running(ce_data->should_schedule)) { | 127 | is_running(ce_data->should_schedule) && |
121 | /* schedule the task for this period if it's not blocked */ | 128 | RT_F_SLEEP != get_rt_flags(ce_data->should_schedule)) { |
122 | next = ce_data->should_schedule; | 129 | /* |
130 | * schedule the task that should be executing in the cyclic | ||
131 | * schedule if it is not blocked and not sleeping | ||
132 | */ | ||
133 | next = ce_data->should_schedule; | ||
123 | } | 134 | } |
124 | |||
125 | sched_state_task_picked(); | 135 | sched_state_task_picked(); |
126 | raw_spin_unlock(dom->lock); | 136 | raw_spin_unlock(dom->lock); |
127 | return next; | 137 | return next; |
@@ -211,11 +221,11 @@ static long mc_ce_admit_task(struct task_struct *ts) | |||
211 | lvl_a_id, get_partition(ts)); | 221 | lvl_a_id, get_partition(ts)); |
212 | goto out_put_pid_unlock; | 222 | goto out_put_pid_unlock; |
213 | } | 223 | } |
214 | if (get_exec_cost(ts) != ce_data->pid_entries[lvl_a_id].exec_cost) { | 224 | if (get_exec_cost(ts) >= ce_data->pid_entries[lvl_a_id].budget) { |
215 | printk(KERN_INFO "litmus: saved exec cost %llu and task exec " | 225 | printk(KERN_INFO "litmus: execution cost %llu is larger than " |
216 | "cost %llu differ\n", | 226 | "the budget %llu\n", |
217 | ce_data->pid_entries[lvl_a_id].exec_cost, | 227 | get_exec_cost(ts), |
218 | get_exec_cost(ts)); | 228 | ce_data->pid_entries[lvl_a_id].budget); |
219 | goto out_put_pid_unlock; | 229 | goto out_put_pid_unlock; |
220 | } | 230 | } |
221 | ce_data->pid_entries[lvl_a_id].pid = pid; | 231 | ce_data->pid_entries[lvl_a_id].pid = pid; |
@@ -243,12 +253,19 @@ static void mc_ce_task_new(struct task_struct *ts, int on_rq, int running) | |||
243 | struct pid *pid_should_be_running; | 253 | struct pid *pid_should_be_running; |
244 | unsigned long flags; | 254 | unsigned long flags; |
245 | int idx, should_be_running; | 255 | int idx, should_be_running; |
256 | lt_t offset; | ||
246 | 257 | ||
247 | /* have to call mc_ce_schedule_at because the task only gets a PID | 258 | /* have to call mc_ce_schedule_at because the task only gets a PID |
248 | * entry after calling admit_task */ | 259 | * entry after calling admit_task */ |
249 | 260 | ||
250 | raw_spin_lock_irqsave(dom->lock, flags); | 261 | raw_spin_lock_irqsave(dom->lock, flags); |
251 | idx = mc_ce_schedule_at(litmus_clock(), dom); | 262 | /* initialize some task state */ |
263 | set_rt_flags(ts, RT_F_RUNNING); | ||
264 | tsk_rt(ts)->job_params.job_no = 0; | ||
265 | tsk_mc_data(ts)->mc_job.expected_job = 0; | ||
266 | |||
267 | offset = get_cycle_offset(litmus_clock(), ce_data->cycle_time); | ||
268 | idx = mc_ce_schedule_at(dom, offset); | ||
252 | pid_should_be_running = ce_data->pid_entries[idx].pid; | 269 | pid_should_be_running = ce_data->pid_entries[idx].pid; |
253 | rcu_read_lock(); | 270 | rcu_read_lock(); |
254 | should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID)); | 271 | should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID)); |
@@ -301,9 +318,13 @@ static void mc_ce_task_block(struct task_struct *ts) | |||
301 | */ | 318 | */ |
302 | static long mc_ce_complete_job(void) | 319 | static long mc_ce_complete_job(void) |
303 | { | 320 | { |
304 | /* TODO */ | 321 | /* mark that the task wishes to sleep */ |
305 | printk(KERN_EMERG "complete job called TODO\n"); | 322 | set_rt_flags(current, RT_F_SLEEP); |
306 | BUG(); | 323 | tsk_rt(current)->job_params.job_no++; |
324 | /* call schedule, this will return when a new job arrives | ||
325 | * it also takes care of preparing for the next release | ||
326 | */ | ||
327 | schedule(); | ||
307 | return 0; | 328 | return 0; |
308 | } | 329 | } |
309 | 330 | ||
@@ -327,6 +348,10 @@ static void mc_ce_task_exit(struct task_struct *ts) | |||
327 | BUG_ON(!pid); | 348 | BUG_ON(!pid); |
328 | put_pid(pid); | 349 | put_pid(pid); |
329 | ce_data->pid_entries[lvl_a_id].pid = NULL; | 350 | ce_data->pid_entries[lvl_a_id].pid = NULL; |
351 | if (ce_data->scheduled == ts) | ||
352 | ce_data->scheduled = NULL; | ||
353 | if (ce_data->should_schedule == ts) | ||
354 | ce_data->should_schedule = NULL; | ||
330 | raw_spin_unlock_irqrestore(dom->lock, flags); | 355 | raw_spin_unlock_irqrestore(dom->lock, flags); |
331 | } | 356 | } |
332 | 357 | ||
@@ -340,28 +365,64 @@ static void mc_ce_task_exit(struct task_struct *ts) | |||
340 | */ | 365 | */ |
341 | static enum hrtimer_restart timer_callback(struct hrtimer *timer) | 366 | static enum hrtimer_restart timer_callback(struct hrtimer *timer) |
342 | { | 367 | { |
343 | struct ce_dom_data *ce_data = container_of(timer, | ||
344 | struct ce_dom_data, timer); | ||
345 | domain_t *dom = &per_cpu(mc_ce_doms, ce_data->cpu); | ||
346 | /* relative and absolute times for cycles */ | 368 | /* relative and absolute times for cycles */ |
347 | lt_t now, offset_rel, cycle_start_abs, next_timer_abs; | 369 | lt_t now, offset_rel, cycle_start_abs, next_timer_abs; |
370 | struct task_struct *should_schedule; | ||
348 | struct ce_dom_pid_entry *pid_entry; | 371 | struct ce_dom_pid_entry *pid_entry; |
372 | struct ce_dom_data *ce_data; | ||
349 | unsigned long flags; | 373 | unsigned long flags; |
374 | domain_t *dom; | ||
350 | int idx; | 375 | int idx; |
351 | 376 | ||
377 | ce_data = container_of(timer, struct ce_dom_data, timer); | ||
378 | dom = &per_cpu(mc_ce_doms, ce_data->cpu); | ||
379 | |||
352 | raw_spin_lock_irqsave(dom->lock, flags); | 380 | raw_spin_lock_irqsave(dom->lock, flags); |
353 | 381 | ||
354 | now = litmus_clock(); | 382 | now = litmus_clock(); |
355 | offset_rel = (now - atomic64_read(&start_time)) % ce_data->cycle_time; | 383 | TRACE("timer callback at %llu on CPU %d\n", now, ce_data->cpu); |
384 | /* Based off of the current time, figure out the offset into the cycle | ||
385 | * and the cycle's start time, and determine what should be scheduled. | ||
386 | */ | ||
387 | offset_rel = get_cycle_offset(now, ce_data->cycle_time); | ||
356 | cycle_start_abs = now - offset_rel; | 388 | cycle_start_abs = now - offset_rel; |
357 | idx = mc_ce_schedule_at(now, dom); | 389 | idx = mc_ce_schedule_at(dom, offset_rel); |
358 | pid_entry = &ce_data->pid_entries[idx]; | 390 | pid_entry = &ce_data->pid_entries[idx]; |
391 | /* set the timer to fire at the next cycle start */ | ||
359 | next_timer_abs = cycle_start_abs + pid_entry->acc_time; | 392 | next_timer_abs = cycle_start_abs + pid_entry->acc_time; |
360 | hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs)); | 393 | hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs)); |
394 | |||
361 | /* get the task_struct (pid_task can accept a NULL) */ | 395 | /* get the task_struct (pid_task can accept a NULL) */ |
362 | rcu_read_lock(); | 396 | rcu_read_lock(); |
363 | ce_data->should_schedule = pid_task(pid_entry->pid, PIDTYPE_PID); | 397 | should_schedule = pid_task(pid_entry->pid, PIDTYPE_PID); |
364 | rcu_read_unlock(); | 398 | rcu_read_unlock(); |
399 | ce_data->should_schedule = should_schedule; | ||
400 | |||
401 | if (should_schedule && atomic_read(&start_time_set)) { | ||
402 | /* we only start tracking this after the job release syscall */ | ||
403 | tsk_mc_data(should_schedule)->mc_job.expected_job++; | ||
404 | /* | ||
405 | * If jobs are not overrunning their budgets, then this | ||
406 | * should not happen. | ||
407 | */ | ||
408 | WARN(tsk_mc_data(should_schedule)->mc_job.expected_job != | ||
409 | tsk_rt(should_schedule)->job_params.job_no, | ||
410 | "LITMUS MC-CE level A timer fired, " | ||
411 | "but the task %d seems to be " | ||
412 | "overrunning its budget\n", | ||
413 | should_schedule->pid); | ||
414 | } | ||
415 | |||
416 | if (ce_data->should_schedule) { | ||
417 | tsk_rt(should_schedule)->job_params.deadline = | ||
418 | cycle_start_abs + pid_entry->acc_time; | ||
419 | tsk_rt(should_schedule)->job_params.release = | ||
420 | tsk_rt(should_schedule)->job_params.deadline - | ||
421 | pid_entry->budget; | ||
422 | tsk_rt(should_schedule)->job_params.exec_time = 0; | ||
423 | sched_trace_task_release(should_schedule); | ||
424 | set_rt_flags(ce_data->should_schedule, RT_F_RUNNING); | ||
425 | } | ||
365 | if (ce_data->scheduled != ce_data->should_schedule) | 426 | if (ce_data->scheduled != ce_data->should_schedule) |
366 | preempt_if_preemptable(ce_data->scheduled, ce_data->cpu); | 427 | preempt_if_preemptable(ce_data->scheduled, ce_data->cpu); |
367 | 428 | ||
@@ -377,12 +438,13 @@ static int cancel_all_timers(void) | |||
377 | { | 438 | { |
378 | struct ce_dom_data *ce_data; | 439 | struct ce_dom_data *ce_data; |
379 | domain_t *dom; | 440 | domain_t *dom; |
380 | int cpu, ret = 0; | 441 | int cpu, ret = 0, cancel_res; |
381 | 442 | ||
382 | for_each_online_cpu(cpu) { | 443 | for_each_online_cpu(cpu) { |
383 | dom = &per_cpu(mc_ce_doms, cpu); | 444 | dom = &per_cpu(mc_ce_doms, cpu); |
384 | ce_data = dom->data; | 445 | ce_data = dom->data; |
385 | ret = ret || hrtimer_cancel(&ce_data->timer); | 446 | cancel_res = hrtimer_cancel(&ce_data->timer); |
447 | ret = ret || cancel_res; | ||
386 | } | 448 | } |
387 | return ret; | 449 | return ret; |
388 | } | 450 | } |
@@ -410,9 +472,9 @@ static void arm_all_timers(void) | |||
410 | } | 472 | } |
411 | 473 | ||
412 | /* | 474 | /* |
413 | * There are no real releases in the CE, but the task releasing code will | 475 | * There are no real releases in the CE, but the task releease syscall will |
414 | * call this. We can re-set our notion of the CE period start to make | 476 | * call this. We can re-set our notion of the CE period start to make |
415 | * the schedule line up. | 477 | * the schedule look pretty. |
416 | */ | 478 | */ |
417 | static void mc_ce_release_at(struct task_struct *ts, lt_t start) | 479 | static void mc_ce_release_at(struct task_struct *ts, lt_t start) |
418 | { | 480 | { |
@@ -431,8 +493,6 @@ static long mc_ce_activate_plugin(void) | |||
431 | domain_t *dom; | 493 | domain_t *dom; |
432 | int cpu; | 494 | int cpu; |
433 | 495 | ||
434 | raw_spin_lock(&activate_lock); | ||
435 | |||
436 | for_each_online_cpu(cpu) { | 496 | for_each_online_cpu(cpu) { |
437 | dom = &per_cpu(mc_ce_doms, cpu); | 497 | dom = &per_cpu(mc_ce_doms, cpu); |
438 | ce_data = dom->data; | 498 | ce_data = dom->data; |
@@ -443,7 +503,6 @@ static long mc_ce_activate_plugin(void) | |||
443 | atomic_set(&start_time_set, 0); | 503 | atomic_set(&start_time_set, 0); |
444 | atomic64_set(&start_time, litmus_clock()); | 504 | atomic64_set(&start_time, litmus_clock()); |
445 | arm_all_timers(); | 505 | arm_all_timers(); |
446 | raw_spin_unlock(&activate_lock); | ||
447 | return 0; | 506 | return 0; |
448 | } | 507 | } |
449 | 508 | ||
@@ -464,13 +523,12 @@ static void clear_pid_entries(void) | |||
464 | put_pid(ce_data->pid_entries[entry].pid); | 523 | put_pid(ce_data->pid_entries[entry].pid); |
465 | ce_data->pid_entries[entry].pid = NULL; | 524 | ce_data->pid_entries[entry].pid = NULL; |
466 | } | 525 | } |
467 | ce_data->pid_entries[entry].exec_cost = 0; | 526 | ce_data->pid_entries[entry].budget = 0; |
468 | ce_data->pid_entries[entry].acc_time = 0; | 527 | ce_data->pid_entries[entry].acc_time = 0; |
469 | } | 528 | } |
470 | } | 529 | } |
471 | } | 530 | } |
472 | 531 | ||
473 | static void tear_down_proc(void); | ||
474 | static long mc_ce_deactivate_plugin(void) | 532 | static long mc_ce_deactivate_plugin(void) |
475 | { | 533 | { |
476 | domain_t *dom; | 534 | domain_t *dom; |
@@ -484,8 +542,6 @@ static long mc_ce_deactivate_plugin(void) | |||
484 | atomic_set(&ce_data->timer_info.state, | 542 | atomic_set(&ce_data->timer_info.state, |
485 | HRTIMER_START_ON_INACTIVE); | 543 | HRTIMER_START_ON_INACTIVE); |
486 | } | 544 | } |
487 | clear_pid_entries(); | ||
488 | tear_down_proc(); | ||
489 | return 0; | 545 | return 0; |
490 | } | 546 | } |
491 | 547 | ||
@@ -513,7 +569,6 @@ static int __init init_sched_mc_ce(void) | |||
513 | domain_t *dom; | 569 | domain_t *dom; |
514 | int cpu, err; | 570 | int cpu, err; |
515 | 571 | ||
516 | clear_pid_entries(); | ||
517 | for_each_online_cpu(cpu) { | 572 | for_each_online_cpu(cpu) { |
518 | dom = &per_cpu(mc_ce_doms, cpu); | 573 | dom = &per_cpu(mc_ce_doms, cpu); |
519 | pd_domain_init(dom, NULL, NULL, NULL, NULL, NULL); | 574 | pd_domain_init(dom, NULL, NULL, NULL, NULL, NULL); |
@@ -524,6 +579,7 @@ static int __init init_sched_mc_ce(void) | |||
524 | ce_data->cpu = cpu; | 579 | ce_data->cpu = cpu; |
525 | ce_data->timer.function = timer_callback; | 580 | ce_data->timer.function = timer_callback; |
526 | } | 581 | } |
582 | clear_pid_entries(); | ||
527 | err = setup_proc(); | 583 | err = setup_proc(); |
528 | if (!err) | 584 | if (!err) |
529 | err = register_sched_plugin(&mc_ce_plugin); | 585 | err = register_sched_plugin(&mc_ce_plugin); |
@@ -537,15 +593,18 @@ static int write_into_proc(char *proc_buf, const int proc_size, char *fmt, ...) | |||
537 | int n; | 593 | int n; |
538 | va_list args; | 594 | va_list args; |
539 | 595 | ||
596 | /* When writing to procfs, we don't care about the trailing null that | ||
597 | * is not included in the count returned by vscnprintf. | ||
598 | */ | ||
540 | va_start(args, fmt); | 599 | va_start(args, fmt); |
541 | n = vscnprintf(buf, BUF_SIZE, fmt, args); | 600 | n = vsnprintf(buf, BUF_SIZE, fmt, args); |
542 | va_end(args); | 601 | va_end(args); |
543 | if (BUF_SIZE <= n || proc_size <= n - 1) { | 602 | if (BUF_SIZE <= n || proc_size <= n) { |
544 | /* too big for formatting buffer or proc (less null byte) */ | 603 | /* too big for formatting buffer or proc (less null byte) */ |
545 | n = -EINVAL; | 604 | n = -EINVAL; |
546 | goto out; | 605 | goto out; |
547 | } | 606 | } |
548 | memcpy(proc_buf, buf, n - 1); | 607 | memcpy(proc_buf, buf, n); |
549 | out: | 608 | out: |
550 | return n; | 609 | return n; |
551 | } | 610 | } |
@@ -553,6 +612,9 @@ out: | |||
553 | 612 | ||
554 | /* | 613 | /* |
555 | * Writes a PID entry to the procfs. | 614 | * Writes a PID entry to the procfs. |
615 | * | ||
616 | * @page buffer to write into. | ||
617 | * @count bytes available in the buffer | ||
556 | */ | 618 | */ |
557 | #define PID_SPACE 15 | 619 | #define PID_SPACE 15 |
558 | #define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN) | 620 | #define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN) |
@@ -579,28 +641,28 @@ static int write_pid_entry(char *page, const int count, const int cpu, | |||
579 | *ti_b = ' '; /* nuke the null byte */ | 641 | *ti_b = ' '; /* nuke the null byte */ |
580 | ti_b++; | 642 | ti_b++; |
581 | get_task_comm(ti_b, ts); | 643 | get_task_comm(ti_b, ts); |
582 | task_info[TASK_INFO_BUF - 1] = '\0'; | ||
583 | } else { | 644 | } else { |
584 | const char *msg = "pid_task() failed :("; | 645 | strncpy(task_info, "pid_task() failed :(", |
585 | strncpy(task_info, msg, sizeof(msg)); | 646 | TASK_INFO_BUF); |
586 | } | 647 | } |
587 | 648 | ||
588 | } else | 649 | } else |
589 | strncpy(task_info, "no", 3); | 650 | strncpy(task_info, "no", TASK_INFO_BUF); |
651 | task_info[TASK_INFO_BUF - 1] = '\0'; /* just to be sure */ | ||
590 | 652 | ||
591 | err = write_into_proc(page, count - n, "# task: %s\n", task_info); | 653 | err = write_into_proc(page + n, count - n, "# task: %s\n", task_info); |
592 | if (err < 0) { | 654 | if (err < 0) { |
593 | n = -ENOSPC; | 655 | n = -ENOSPC; |
594 | goto out; | 656 | goto out; |
595 | } | 657 | } |
596 | n += err; | 658 | n += err; |
597 | err = write_into_proc(page, count - n, "%d, %d, %llu\n", | 659 | err = write_into_proc(page + n, count - n, "%d, %d, %llu\n", |
598 | cpu, task, pid_entry->exec_cost); | 660 | cpu, task, pid_entry->budget); |
599 | if (err < 0) { | 661 | if (err < 0) { |
600 | n = -ENOSPC; | 662 | n = -ENOSPC; |
601 | goto out; | 663 | goto out; |
602 | } | 664 | } |
603 | n =+ err; | 665 | n += err; |
604 | out: | 666 | out: |
605 | return n; | 667 | return n; |
606 | } | 668 | } |
@@ -618,15 +680,15 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count, | |||
618 | domain_t *dom; | 680 | domain_t *dom; |
619 | 681 | ||
620 | if (off > 0) { | 682 | if (off > 0) { |
621 | *eof = 1; | 683 | printk(KERN_INFO "litmus: MC-CE called read with off > 0\n"); |
622 | return 0; | 684 | goto out; |
623 | } | 685 | } |
624 | 686 | ||
625 | for_each_online_cpu(cpu) { | 687 | for_each_online_cpu(cpu) { |
626 | dom = &per_cpu(mc_ce_doms, cpu); | 688 | dom = &per_cpu(mc_ce_doms, cpu); |
627 | ce_data = dom->data; | 689 | ce_data = dom->data; |
628 | for (t = 0; t < ce_data->num_pid_entries; ++t) { | 690 | for (t = 0; t < ce_data->num_pid_entries; ++t) { |
629 | err = write_pid_entry(page, count - n, | 691 | err = write_pid_entry(page + n, count - n, |
630 | cpu, t, &ce_data->pid_entries[t]); | 692 | cpu, t, &ce_data->pid_entries[t]); |
631 | if (err < 0) { | 693 | if (err < 0) { |
632 | n = -ENOSPC; | 694 | n = -ENOSPC; |
@@ -635,8 +697,8 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count, | |||
635 | n += err; | 697 | n += err; |
636 | } | 698 | } |
637 | } | 699 | } |
638 | *eof = 1; | ||
639 | out: | 700 | out: |
701 | *eof = 1; | ||
640 | return n; | 702 | return n; |
641 | } | 703 | } |
642 | 704 | ||
@@ -660,8 +722,8 @@ static int skip_comment(const char *buf, const unsigned long max) | |||
660 | return i; | 722 | return i; |
661 | } | 723 | } |
662 | 724 | ||
663 | /* a budget of 1 millisecond is probably reasonable */ | 725 | /* a budget of 5 milliseconds is probably reasonable */ |
664 | #define BUDGET_THRESHOLD 1000000ULL | 726 | #define BUDGET_THRESHOLD 5000000ULL |
665 | static int setup_pid_entry(const int cpu, const int task, const lt_t budget) | 727 | static int setup_pid_entry(const int cpu, const int task, const lt_t budget) |
666 | { | 728 | { |
667 | domain_t *dom = &per_cpu(mc_ce_doms, cpu); | 729 | domain_t *dom = &per_cpu(mc_ce_doms, cpu); |
@@ -670,9 +732,10 @@ static int setup_pid_entry(const int cpu, const int task, const lt_t budget) | |||
670 | int err = 0; | 732 | int err = 0; |
671 | 733 | ||
672 | /* check the inputs */ | 734 | /* check the inputs */ |
673 | if (cpu < 0 || cpu >= NR_CPUS || task < 1 || task > PID_MAX_DEFAULT || | 735 | if (cpu < 0 || NR_CPUS <= cpu || task < 0 || |
736 | CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS <= task || | ||
674 | budget < 1) { | 737 | budget < 1) { |
675 | printk(KERN_INFO "litmus: bad cpu or task ID sent to " | 738 | printk(KERN_INFO "litmus: bad cpu, task ID, or budget sent to " |
676 | "MC-CE proc\n"); | 739 | "MC-CE proc\n"); |
677 | err = -EINVAL; | 740 | err = -EINVAL; |
678 | goto out; | 741 | goto out; |
@@ -692,7 +755,7 @@ static int setup_pid_entry(const int cpu, const int task, const lt_t budget) | |||
692 | /* add the new entry */ | 755 | /* add the new entry */ |
693 | new_entry = &ce_data->pid_entries[ce_data->num_pid_entries]; | 756 | new_entry = &ce_data->pid_entries[ce_data->num_pid_entries]; |
694 | BUG_ON(NULL != new_entry->pid); | 757 | BUG_ON(NULL != new_entry->pid); |
695 | new_entry->exec_cost = budget; | 758 | new_entry->budget = budget; |
696 | new_entry->acc_time = ce_data->cycle_time + budget; | 759 | new_entry->acc_time = ce_data->cycle_time + budget; |
697 | /* update the domain entry */ | 760 | /* update the domain entry */ |
698 | ce_data->cycle_time += budget; | 761 | ce_data->cycle_time += budget; |
@@ -717,8 +780,6 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer, | |||
717 | int cpu, task, cnt = 0, chars_read, converted, err; | 780 | int cpu, task, cnt = 0, chars_read, converted, err; |
718 | lt_t budget; | 781 | lt_t budget; |
719 | 782 | ||
720 | raw_spin_lock(&activate_lock); | ||
721 | |||
722 | if (is_active_plugin()) { | 783 | if (is_active_plugin()) { |
723 | printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin " | 784 | printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin " |
724 | "active\n"); | 785 | "active\n"); |
@@ -727,11 +788,15 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer, | |||
727 | } | 788 | } |
728 | 789 | ||
729 | if (count > PROCFS_MAX_SIZE) { | 790 | if (count > PROCFS_MAX_SIZE) { |
791 | printk(KERN_INFO "litmus: MC-CE procfs got too many bytes " | ||
792 | "from user-space.\n"); | ||
730 | cnt = -EINVAL; | 793 | cnt = -EINVAL; |
731 | goto out; | 794 | goto out; |
732 | } | 795 | } |
733 | 796 | ||
734 | if (copy_from_user(kbuf, buffer, count)) { | 797 | if (copy_from_user(kbuf, buffer, count)) { |
798 | printk(KERN_INFO "litmus: couldn't copy from user %s\n", | ||
799 | __FUNCTION__); | ||
735 | cnt = -EFAULT; | 800 | cnt = -EFAULT; |
736 | goto out; | 801 | goto out; |
737 | } | 802 | } |
@@ -750,9 +815,11 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer, | |||
750 | c += chars_read; | 815 | c += chars_read; |
751 | continue; | 816 | continue; |
752 | } | 817 | } |
753 | chars_read = sscanf(c, "%d, %d, %llu%n", &cpu, &task, &budget, | 818 | converted = sscanf(c, "%d, %d, %llu%n", &cpu, &task, &budget, |
754 | &converted); | 819 | &chars_read); |
755 | if (3 != converted) { | 820 | if (3 != converted) { |
821 | printk(KERN_INFO "litmus: MC-CE procfs expected three " | ||
822 | "arguments, but got %d.\n", converted); | ||
756 | cnt = -EINVAL; | 823 | cnt = -EINVAL; |
757 | goto out; | 824 | goto out; |
758 | } | 825 | } |
@@ -765,7 +832,6 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer, | |||
765 | } | 832 | } |
766 | } | 833 | } |
767 | out: | 834 | out: |
768 | raw_spin_unlock(&activate_lock); | ||
769 | return cnt; | 835 | return cnt; |
770 | } | 836 | } |
771 | #undef PROCFS_MAX_SIZE | 837 | #undef PROCFS_MAX_SIZE |
@@ -803,4 +869,10 @@ out: | |||
803 | } | 869 | } |
804 | #undef CE_FILE_PROC_NAME | 870 | #undef CE_FILE_PROC_NAME |
805 | 871 | ||
872 | static void clean_sched_mc_ce(void) | ||
873 | { | ||
874 | tear_down_proc(); | ||
875 | } | ||
876 | |||
806 | module_init(init_sched_mc_ce); | 877 | module_init(init_sched_mc_ce); |
878 | module_exit(clean_sched_mc_ce); | ||