diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-06-13 22:54:33 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-06-13 22:54:33 -0400 |
commit | 63360ea7ec23f403462e5335d4a3aed9d756a24e (patch) | |
tree | 25535ae302ca39f2f1168f4aa94017b2fdf0908d | |
parent | 42cbfb1aecca6482f278e640ea4af21f02a775f9 (diff) |
Added syscall hooks, 'finished' produce/consume code.
-rw-r--r-- | include/litmus/litmus.h | 20 | ||||
-rw-r--r-- | include/litmus/pgm.h | 28 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 19 | ||||
-rw-r--r-- | include/litmus/unistd_32.h | 6 | ||||
-rw-r--r-- | include/litmus/unistd_64.h | 12 | ||||
-rw-r--r-- | litmus/jobs.c | 15 | ||||
-rw-r--r-- | litmus/litmus.c | 120 | ||||
-rw-r--r-- | litmus/pgm.c | 290 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 65 |
9 files changed, 504 insertions, 71 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 683407328f5a..cfafef3a795d 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -126,26 +126,14 @@ void preempt_if_preemptable(struct task_struct* t, int on_cpu); | |||
126 | (is_pgm(t) && \ | 126 | (is_pgm(t) && \ |
127 | tsk_rt(t)->pgm_params.produce != NULL && \ | 127 | tsk_rt(t)->pgm_params.produce != NULL && \ |
128 | tsk_rt(t)->pgm_params.consume == NULL) | 128 | tsk_rt(t)->pgm_params.consume == NULL) |
129 | #define is_pgm_sink(t) \ | ||
130 | (is_pgm(t) && \ | ||
131 | tsk_rt(t)->pgm_params.produce == NULL && \ | ||
132 | tsk_rt(t)->pgm_params.consume != NULL) | ||
133 | #define is_pgm_intermediate(t) \ | 129 | #define is_pgm_intermediate(t) \ |
134 | (is_pgm(t) && \ | 130 | (is_pgm(t) && \ |
135 | tsk_rt(t)->pgm_params.produce != NULL && \ | 131 | tsk_rt(t)->pgm_params.produce != NULL && \ |
136 | tsk_rt(t)->pgm_params.consume != NULL) | 132 | tsk_rt(t)->pgm_params.consume != NULL) |
137 | #ifdef CONFIG_PGM | 133 | #define is_pgm_sink(t) \ |
138 | int is_pgm_satisfied(struct task_struct* t); | 134 | (is_pgm_intermediate(t) && \ |
139 | void pgm_produce(struct task_struct* t); | 135 | tsk_rt(t)->pgm_params.produce == NULL && \ |
140 | void pgm_consume(struct task_struct* t); | 136 | tsk_rt(t)->pgm_params.consume != NULL) |
141 | int pgm_complete(struct task_struct* t); | ||
142 | #else | ||
143 | /* nothing */ | ||
144 | #define is_pgm_satisfied(t) | ||
145 | #define pgm_produce(t) | ||
146 | #define pgm_consume(t) | ||
147 | #define pgm_complete(t) | ||
148 | #endif | ||
149 | 137 | ||
150 | #ifdef CONFIG_LITMUS_LOCKING | 138 | #ifdef CONFIG_LITMUS_LOCKING |
151 | void srp_ceiling_block(void); | 139 | void srp_ceiling_block(void); |
diff --git a/include/litmus/pgm.h b/include/litmus/pgm.h new file mode 100644 index 000000000000..688fc3b9bbe2 --- /dev/null +++ b/include/litmus/pgm.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Routines for constructing and working with PGMs. | ||
3 | */ | ||
4 | |||
5 | #ifndef __UNC_PGM_H__ | ||
6 | #define __UNC_PGM_H__ | ||
7 | |||
8 | #include <linux/sched.h> | ||
9 | |||
10 | #include <litmus/litmus.h> | ||
11 | #include <litmus/rt_param.h> | ||
12 | |||
13 | int is_pgm_satisfied(struct task_struct* t); | ||
14 | |||
15 | void pgm_prepare_for_next_period(struct task_struct *t); | ||
16 | |||
17 | int pgm_complete_job(struct task_struct* t); | ||
18 | |||
19 | int do_pgm_add_edge(struct task_struct *a, int nr_gen, | ||
20 | struct task_struct *b, int nr_req); | ||
21 | int do_pgm_signal_ready(struct task_struct *src); | ||
22 | int do_pgm_set_nr_children(int nr_children); | ||
23 | int do_pgm_wait_for_children(void); | ||
24 | |||
25 | // TODO | ||
26 | //int pgm_remove_edge(struct task_struct *a, struct task_struct *b); | ||
27 | |||
28 | #endif | ||
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index 613e9f98294e..a767e52882f4 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -77,6 +77,14 @@ struct control_page { | |||
77 | /* to be extended */ | 77 | /* to be extended */ |
78 | }; | 78 | }; |
79 | 79 | ||
80 | struct pgm_edge { | ||
81 | pid_t a; | ||
82 | int a_nr_produced; | ||
83 | |||
84 | pid_t b; | ||
85 | int b_nr_consumed; | ||
86 | }; | ||
87 | |||
80 | /* don't export internal data structures to user space (liblitmus) */ | 88 | /* don't export internal data structures to user space (liblitmus) */ |
81 | #ifdef __KERNEL__ | 89 | #ifdef __KERNEL__ |
82 | 90 | ||
@@ -100,28 +108,29 @@ struct pgm_production | |||
100 | struct pgm_produce | 108 | struct pgm_produce |
101 | { | 109 | { |
102 | unsigned long nr_productions; /* num productions/children */ | 110 | unsigned long nr_productions; /* num productions/children */ |
103 | struct pgm_production produce[0]; /* array of productions */ | 111 | struct pgm_production produce[MAX_FAN]; /* array of productions. TODO: make dyn alloc */ |
104 | }; | 112 | }; |
105 | 113 | ||
106 | struct pgm_consumption | 114 | struct pgm_consumption |
107 | { | 115 | { |
116 | /* assumption required == number consumed */ | ||
108 | unsigned long required; /* number tokens required before firing */ | 117 | unsigned long required; /* number tokens required before firing */ |
109 | long nr_tokens; /* constraint met when >= required */ | 118 | long nr_tokens; /* constraint met when >= required */ |
110 | }; | 119 | }; |
111 | 120 | ||
112 | struct pgm_consume | 121 | struct pgm_consume |
113 | { | 122 | { |
114 | spinlock_t lock; | 123 | spinlock_t lock; /* TODO: Use atomics instead of a lock. */ |
115 | unsigned long nr_consumptions; /* num of consumption constraints */ | 124 | unsigned long nr_consumptions; /* num of consumption constraints */ |
116 | unsigned long unsatisfied[NR_FAN_CHUNKS]; /* bit-array of unsatisfied constraints */ | 125 | unsigned long unsatisfied[NR_FAN_CHUNKS]; /* bit-array of unsatisfied constraints */ |
117 | struct pgm_consumption consume[0]; /* array of consumption constraints */ | 126 | struct pgm_consumption consume[MAX_FAN]; /* array of consumption constraints. TODO: make dyn alloc */ |
118 | //atomic_t nr_pending_release; | ||
119 | }; | 127 | }; |
120 | 128 | ||
121 | struct rt_pgm { | 129 | struct rt_pgm { |
122 | struct pgm_produce *produce; /* output and current state */ | 130 | struct pgm_produce *produce; /* output and current state */ |
123 | struct pgm_consume *consume; /* input constraints and current state */ | 131 | struct pgm_consume *consume; /* input constraints and current state */ |
124 | struct task_struct *src; /* only not NULL if task is sink */ | 132 | struct task_struct *root; /* root node of the PGM */ |
133 | // struct task_struct *src; /* only not NULL if task is sink */ | ||
125 | }; | 134 | }; |
126 | 135 | ||
127 | #endif /* end PGM */ | 136 | #endif /* end PGM */ |
diff --git a/include/litmus/unistd_32.h b/include/litmus/unistd_32.h index 94264c27d9ac..92e733c42041 100644 --- a/include/litmus/unistd_32.h +++ b/include/litmus/unistd_32.h | |||
@@ -17,5 +17,9 @@ | |||
17 | #define __NR_wait_for_ts_release __LSC(9) | 17 | #define __NR_wait_for_ts_release __LSC(9) |
18 | #define __NR_release_ts __LSC(10) | 18 | #define __NR_release_ts __LSC(10) |
19 | #define __NR_null_call __LSC(11) | 19 | #define __NR_null_call __LSC(11) |
20 | #define __NR_add_pgm_edge __LSC(12) | ||
21 | #define __NR_pgm_signal_ready __LSC(13) | ||
22 | #define __NR_pgm_set_nr_children __LSC(14) | ||
23 | #define __NR_pgm_wait_for_children __LSC(15) | ||
20 | 24 | ||
21 | #define NR_litmus_syscalls 12 | 25 | #define NR_litmus_syscalls 16 |
diff --git a/include/litmus/unistd_64.h b/include/litmus/unistd_64.h index d5ced0d2642c..84125395dfe6 100644 --- a/include/litmus/unistd_64.h +++ b/include/litmus/unistd_64.h | |||
@@ -27,7 +27,15 @@ __SYSCALL(__NR_wait_for_job_release, sys_wait_for_job_release) | |||
27 | __SYSCALL(__NR_wait_for_ts_release, sys_wait_for_ts_release) | 27 | __SYSCALL(__NR_wait_for_ts_release, sys_wait_for_ts_release) |
28 | #define __NR_release_ts __LSC(10) | 28 | #define __NR_release_ts __LSC(10) |
29 | __SYSCALL(__NR_release_ts, sys_release_ts) | 29 | __SYSCALL(__NR_release_ts, sys_release_ts) |
30 | #define __NR_null_call __LSC(11) | 30 | #define __NR_null_call __LSC(11) |
31 | __SYSCALL(__NR_null_call, sys_null_call) | 31 | __SYSCALL(__NR_null_call, sys_null_call) |
32 | #define __NR_add_pgm_edge __LSC(12) | ||
33 | __SYSCALL(__NR_add_pgm_edge, sys_add_pgm_edge) | ||
34 | #define __NR_pgm_signal_ready __LSC(13) | ||
35 | __SYSCALL(__NR_pgm_signal_ready, sys_pgm_signal_ready) | ||
36 | #define __NR_pgm_set_nr_children __LSC(14) | ||
37 | __SYSCALL(__NR_pgm_set_nr_children, sys_pgm_set_nr_children) | ||
38 | #define __NR_pgm_wait_for_children __LSC(15) | ||
39 | __SYSCALL(__NR_pgm_wait_for_children, sys_pgm_wait_for_children) | ||
32 | 40 | ||
33 | #define NR_litmus_syscalls 12 | 41 | #define NR_litmus_syscalls 16 |
diff --git a/litmus/jobs.c b/litmus/jobs.c index 36e314625d86..ab2b05df91a9 100644 --- a/litmus/jobs.c +++ b/litmus/jobs.c | |||
@@ -6,6 +6,10 @@ | |||
6 | #include <litmus/litmus.h> | 6 | #include <litmus/litmus.h> |
7 | #include <litmus/jobs.h> | 7 | #include <litmus/jobs.h> |
8 | 8 | ||
9 | #ifdef CONFIG_PGM | ||
10 | #include <litmus/pgm.h> | ||
11 | #endif | ||
12 | |||
9 | void prepare_for_next_period(struct task_struct *t) | 13 | void prepare_for_next_period(struct task_struct *t) |
10 | { | 14 | { |
11 | BUG_ON(!t); | 15 | BUG_ON(!t); |
@@ -33,8 +37,17 @@ void release_at(struct task_struct *t, lt_t start) | |||
33 | */ | 37 | */ |
34 | long complete_job(void) | 38 | long complete_job(void) |
35 | { | 39 | { |
40 | struct task_struct *t = current; | ||
41 | |||
42 | #ifdef CONFIG_PGM | ||
43 | if(is_pgm(t)) { | ||
44 | /* produce tokens, etc. */ | ||
45 | pgm_complete_job(t); | ||
46 | } | ||
47 | #endif | ||
48 | |||
36 | /* Mark that we do not excute anymore */ | 49 | /* Mark that we do not excute anymore */ |
37 | set_rt_flags(current, RT_F_SLEEP); | 50 | set_rt_flags(t, RT_F_SLEEP); |
38 | /* call schedule, this will return when a new job arrives | 51 | /* call schedule, this will return when a new job arrives |
39 | * it also takes care of preparing for the next release | 52 | * it also takes care of preparing for the next release |
40 | */ | 53 | */ |
diff --git a/litmus/litmus.c b/litmus/litmus.c index 301390148d02..f6d29a42332a 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -21,6 +21,10 @@ | |||
21 | #include <litmus/affinity.h> | 21 | #include <litmus/affinity.h> |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #ifdef CONFIG_PGM | ||
25 | #include <litmus/pgm.h> | ||
26 | #endif | ||
27 | |||
24 | /* Number of RT tasks that exist in the system */ | 28 | /* Number of RT tasks that exist in the system */ |
25 | atomic_t rt_task_count = ATOMIC_INIT(0); | 29 | atomic_t rt_task_count = ATOMIC_INIT(0); |
26 | static DEFINE_RAW_SPINLOCK(task_transition_lock); | 30 | static DEFINE_RAW_SPINLOCK(task_transition_lock); |
@@ -286,6 +290,122 @@ asmlinkage long sys_null_call(cycles_t __user *ts) | |||
286 | return ret; | 290 | return ret; |
287 | } | 291 | } |
288 | 292 | ||
293 | |||
294 | #ifdef CONIG_PGM | ||
295 | asmlinkage long sys_add_pgm_edge(void* __user *user_edge) | ||
296 | { | ||
297 | int retval = -EINVAL; | ||
298 | struct pgm_edge edge; | ||
299 | struct task_struct *a, *b; | ||
300 | |||
301 | if(!access_ok(VERIFY_READ, user_edge, sizeof(struct pgm_edge))) | ||
302 | goto out; | ||
303 | |||
304 | if(__copy_from_user(&edge, user_edge, sizeof(struct pgm_edge))) | ||
305 | goto out; | ||
306 | |||
307 | if(edge.a < 0 || edge.b < 0) | ||
308 | goto out; | ||
309 | |||
310 | read_lock_irq(&tasklist_lock); | ||
311 | a = find_task_by_vpid(edge.a); | ||
312 | b = find_task_by_vpid(edge.b); | ||
313 | read_unlock_irq(&tasklist_lock); | ||
314 | |||
315 | if(!a || !b) | ||
316 | goto out; | ||
317 | |||
318 | if(!is_realtime(a) || !is_realtime(b)) | ||
319 | goto out; | ||
320 | |||
321 | retval = do_add_pgm_edge(a, edge.a_nr_produced, | ||
322 | b, edge.b.nr_consumed); | ||
323 | |||
324 | out: | ||
325 | return retval; | ||
326 | } | ||
327 | |||
328 | asmlinkage long sys_pgm_signal_ready(pid_t r) | ||
329 | { | ||
330 | int retval = -EINVAL; | ||
331 | |||
332 | struct task_struct *root; | ||
333 | |||
334 | if(p < 0) | ||
335 | goto out; | ||
336 | |||
337 | read_lock_irq(&tasklist_lock); | ||
338 | root = find_task_by_vpid(r); | ||
339 | read_unlock_irq(&tasklist_lock); | ||
340 | |||
341 | if(!root) | ||
342 | goto out; | ||
343 | |||
344 | if(!is_realtime(root)) | ||
345 | goto out; | ||
346 | |||
347 | if(!is_pgm_src(root)) | ||
348 | goto out; | ||
349 | |||
350 | retval = do_pgm_signal_ready(root); | ||
351 | |||
352 | out: | ||
353 | return retval; | ||
354 | } | ||
355 | |||
356 | asmlinkage long sys_pgm_set_nr_children(int nr_children) | ||
357 | { | ||
358 | int retval = -EINVAL; | ||
359 | |||
360 | if(nr_children <= 0) | ||
361 | goto out; | ||
362 | |||
363 | retval = do_pgm_set_nr_children(nr_children); | ||
364 | |||
365 | out: | ||
366 | return retval; | ||
367 | } | ||
368 | |||
369 | asmlinkage long sys_pgm_wait_for_children(void) | ||
370 | { | ||
371 | int retval = -EINVAL; | ||
372 | |||
373 | if(!is_realtime(current) || !is_pgm_src(current)) | ||
374 | goto out; | ||
375 | |||
376 | retval = do_pgm_wait_for_children(); | ||
377 | |||
378 | out: | ||
379 | return retval; | ||
380 | } | ||
381 | |||
382 | |||
383 | #else | ||
384 | asmlinkage long sys_add_pgm_edge(struct pgm_edge __user *edge) | ||
385 | { | ||
386 | return -EINVAL; | ||
387 | } | ||
388 | |||
389 | asmlinkage long sys_pgm_signal_ready(pid_t r) | ||
390 | { | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | asmlinkage long sys_pgm_set_nr_children(int nr_children) | ||
395 | { | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | asmlinkage long sys_pgm_wait_for_children(void) | ||
400 | { | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | #endif | ||
404 | |||
405 | |||
406 | |||
407 | |||
408 | |||
289 | /* p is a real-time task. Re-init its state as a best-effort task. */ | 409 | /* p is a real-time task. Re-init its state as a best-effort task. */ |
290 | static void reinit_litmus_state(struct task_struct* p, int restore) | 410 | static void reinit_litmus_state(struct task_struct* p, int restore) |
291 | { | 411 | { |
diff --git a/litmus/pgm.c b/litmus/pgm.c index 6710644eae8e..661fb2065dea 100644 --- a/litmus/pgm.c +++ b/litmus/pgm.c | |||
@@ -1,48 +1,60 @@ | |||
1 | #include <linux/sched.h> | 1 | |
2 | #include <linux/bitops.h> | 2 | #include <linux/slab.h> |
3 | #include <linux/spinlock.h> | 3 | #include <linux/spinlock.h> |
4 | 4 | ||
5 | #include <litmus/litmus.h> | 5 | #include <litmus/pgm.h> |
6 | #include <litmus/sched_plugin.h> | 6 | #include <litmus/sched_plugin.h> |
7 | #include <litmus/rt_param.h> | 7 | #include <litmus/jobs.h> |
8 | |||
9 | #include <litmus/trace.h> | ||
10 | |||
8 | 11 | ||
12 | static void pgm_consume(struct task_struct *t); | ||
13 | static void pgm_produce_intermediate(struct task_struct *t); | ||
14 | static void pgm_produce_root(struct task_struct *t); | ||
9 | 15 | ||
10 | static inline int __is_pgm_satisfied(struct task_struct* t) | 16 | |
17 | static inline int __is_pgm_satisfied(struct task_struct *t) | ||
11 | { | 18 | { |
12 | unsigned long unsatisfied = | 19 | unsigned long unsatisfied = |
13 | find_first_bit(tsk_rt(t)->pgm_params.consume->unsatisfied, | 20 | find_first_bit(tsk_rt(t)->pgm_params.consume->unsatisfied, |
14 | tsk_rt(t)->pgm_params.consume->nr_consumptions); | 21 | tsk_rt(t)->pgm_params.consume->nr_consumptions); |
15 | 22 | ||
16 | return (unsatisfied == tsk_rt(t)->pgm_params.consume->nr_consumptions); | 23 | int is_sat = (unsatisfied == |
24 | tsk_rt(t)->pgm_params.consume->nr_consumptions); | ||
25 | |||
26 | TRACE_TASK(t, "is_satisfied = %d (unsatisifed = %x)\n", | ||
27 | is_sat, | ||
28 | unsatisfied); | ||
29 | |||
30 | return (is_sat); | ||
17 | } | 31 | } |
18 | 32 | ||
19 | int is_pgm_satisfied(struct task_struct* t) | 33 | |
34 | static void pgm_produce(struct task_struct *t) | ||
20 | { | 35 | { |
21 | int is_satisfied; | ||
22 | unsigned long flags; | ||
23 | |||
24 | BUG_ON(!t); | 36 | BUG_ON(!t); |
25 | BUG_ON(!is_realtime(t)); | 37 | BUG_ON(!is_realtime(t)); |
26 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | 38 | BUG_ON(!is_pgm(t)); |
27 | 39 | ||
28 | spin_lock_irqsave(&tsk_rt(t)->pgm_params.consume->lock, flags); | 40 | if(!is_pgm_sink(t)) { |
29 | 41 | pgm_produce_intermediate(t); | |
30 | is_satisfied = __is_pgm_satisfied(t); | 42 | } |
31 | 43 | else { | |
32 | spin_unlock_irqrestore(&tsk_rt(t)->pgm_params.consume->lock, flags); | 44 | pgm_produce_root(t); |
33 | 45 | } | |
34 | return (is_satisfied); | ||
35 | } | 46 | } |
36 | 47 | ||
37 | void pgm_produce(struct task_struct* t) | 48 | |
49 | static void pgm_produce_intermediate(struct task_struct *t) | ||
38 | { | 50 | { |
39 | unsigned long i; | 51 | unsigned long i; |
40 | struct pgm_produce *prod; | 52 | struct pgm_produce *prod; |
41 | 53 | ||
42 | BUG_ON(!t); | 54 | BUG_ON(is_pgm_sink(t)); |
43 | BUG_ON(!is_realtime(t)); | 55 | |
44 | BUG_ON(!is_pgm(t) || is_pgm_sink(t)); | 56 | TRACE_TASK(t, "pgm_produce_intermediate()\n"); |
45 | 57 | ||
46 | prod = tsk_rt(t)->pgm_params.produce; | 58 | prod = tsk_rt(t)->pgm_params.produce; |
47 | 59 | ||
48 | for(i = 0; i < prod->nr_productions; ++i) { | 60 | for(i = 0; i < prod->nr_productions; ++i) { |
@@ -51,7 +63,7 @@ void pgm_produce(struct task_struct* t) | |||
51 | struct pgm_consumption *child_input; | 63 | struct pgm_consumption *child_input; |
52 | int unsatisfied; | 64 | int unsatisfied; |
53 | unsigned long flags; | 65 | unsigned long flags; |
54 | 66 | int release_child = 0; | |
55 | 67 | ||
56 | BUG_ON(!is_pgm(child) || is_pgm_src(child)); | 68 | BUG_ON(!is_pgm(child) || is_pgm_src(child)); |
57 | 69 | ||
@@ -60,25 +72,69 @@ void pgm_produce(struct task_struct* t) | |||
60 | spin_lock_irqsave(&tsk_rt(child)->pgm_params.consume->lock, flags); | 72 | spin_lock_irqsave(&tsk_rt(child)->pgm_params.consume->lock, flags); |
61 | 73 | ||
62 | child_input->nr_tokens += to_produce->nr_tokens; | 74 | child_input->nr_tokens += to_produce->nr_tokens; |
75 | |||
76 | TRACE_TASK(t, "producing %d tokens to %s/%d (tot now = %d, wants = %d)\n", | ||
77 | to_produce->nr_tokens, | ||
78 | child->comm, child->pid, | ||
79 | child_input->nr_tokens, | ||
80 | child_input->required); | ||
63 | 81 | ||
64 | if(child_input->nr_tokens >= child_input->required) { | 82 | if(child_input->nr_tokens >= child_input->required) { |
65 | unsatisfied = __test_and_clear_bit(to_produce->production_idx, | 83 | unsatisfied = __test_and_clear_bit(to_produce->production_idx, |
66 | tsk_rt(child)->pgm_params.consume->unsatisfied); | 84 | tsk_rt(child)->pgm_params.consume->unsatisfied); |
67 | 85 | ||
68 | if(unsatisfied) { | 86 | if(unsatisfied) { |
69 | /* we satisfied the child's requirement */ | 87 | /* we satisfied the child's requirement for this input */ |
88 | TRACE_TASK(t, "completed a req of %s/%d\n", | ||
89 | child->comm, child->pid); | ||
90 | |||
70 | if(__is_pgm_satisfied(child)) { | 91 | if(__is_pgm_satisfied(child)) { |
71 | /* all requirements met: release the child */ | 92 | /* all requirements have been met: release the child */ |
72 | 93 | ||
94 | TRACE_TASK(t, "completed all reqs of %s\%d!\n", | ||
95 | child->comm, child->pid); | ||
96 | |||
97 | release_child = 1; | ||
73 | } | 98 | } |
74 | } | 99 | } |
100 | else { | ||
101 | TRACE_TASK(t, "%s/%d already had constraint satisifed???\n", | ||
102 | child->comm, child->pid); | ||
103 | } | ||
75 | } | 104 | } |
76 | 105 | ||
106 | /* drop the child's lock before we try to wake it up, otherwise we may | ||
107 | * deadlock with scheduler's locks | ||
108 | */ | ||
77 | spin_unlock_irqrestore(&tsk_rt(child)->pgm_params.consume->lock, flags); | 109 | spin_unlock_irqrestore(&tsk_rt(child)->pgm_params.consume->lock, flags); |
110 | |||
111 | if(release_child) | ||
112 | { | ||
113 | pgm_consume(child); | ||
114 | |||
115 | TRACE_TASK(t, "waking up %s/%d\n", child->comm, child->pid); | ||
116 | litmus->task_wake_up(child); | ||
117 | } | ||
78 | } | 118 | } |
79 | } | 119 | } |
80 | 120 | ||
81 | void pgm_consume(struct task_struct* t) | 121 | |
122 | static void pgm_produce_root(struct task_struct *t) | ||
123 | { | ||
124 | struct task_struct *root; | ||
125 | BUG_ON(!is_pgm_sink(t)); | ||
126 | |||
127 | root = tsk_rt(t)->pgm_params.root; | ||
128 | |||
129 | TRACE_TASK(t, "waking up PGM root %s/%d\n", | ||
130 | root->comm, root->pid); | ||
131 | |||
132 | /* wake up the new task, the task will sleep if it is too soon. */ | ||
133 | litmus->task_wake_up(root); | ||
134 | } | ||
135 | |||
136 | |||
137 | static void pgm_consume(struct task_struct *t) | ||
82 | { | 138 | { |
83 | struct pgm_consume* cons; | 139 | struct pgm_consume* cons; |
84 | unsigned long i; | 140 | unsigned long i; |
@@ -88,6 +144,9 @@ void pgm_consume(struct task_struct* t) | |||
88 | BUG_ON(!is_realtime(t)); | 144 | BUG_ON(!is_realtime(t)); |
89 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | 145 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); |
90 | 146 | ||
147 | TRACE("%s/%d is consuming tokens! Munch munch... yum!\n", | ||
148 | t->comm, t->pid); | ||
149 | |||
91 | cons = tsk_rt(t)->pgm_params.consume; | 150 | cons = tsk_rt(t)->pgm_params.consume; |
92 | 151 | ||
93 | spin_lock_irqsave(&cons->lock, flags); | 152 | spin_lock_irqsave(&cons->lock, flags); |
@@ -99,33 +158,174 @@ void pgm_consume(struct task_struct* t) | |||
99 | spin_unlock_irqrestore(&cons->lock, flags); | 158 | spin_unlock_irqrestore(&cons->lock, flags); |
100 | } | 159 | } |
101 | 160 | ||
102 | int pgm_complete(struct task_struct* t) | 161 | |
162 | /**********************************************/ | ||
163 | |||
164 | |||
165 | int is_pgm_satisfied(struct task_struct *t) | ||
103 | { | 166 | { |
104 | struct pgm_consume* cons; | 167 | int is_satisfied; |
105 | unsigned long i; | ||
106 | unsigned long flags; | 168 | unsigned long flags; |
107 | int keep_going = 0; | ||
108 | 169 | ||
109 | BUG_ON(!t); | 170 | BUG_ON(!t); |
110 | BUG_ON(!is_realtime(t)); | 171 | BUG_ON(!is_realtime(t)); |
111 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | 172 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); |
112 | 173 | ||
113 | cons = tsk_rt(t)->pgm_params.consume; | 174 | spin_lock_irqsave(&tsk_rt(t)->pgm_params.consume->lock, flags); |
114 | 175 | ||
115 | spin_lock_irqsave(&cons->lock, flags); | 176 | is_satisfied = __is_pgm_satisfied(t); |
116 | 177 | ||
117 | for(i = 0; i < cons->nr_consumptions; ++i) { | 178 | spin_unlock_irqrestore(&tsk_rt(t)->pgm_params.consume->lock, flags); |
118 | if(cons->consume[i].nr_tokens <= cons->consume[i].required) { | 179 | |
119 | __set_bit(i, cons->unsatisfied); | 180 | return (is_satisfied); |
120 | } | 181 | } |
121 | } | 182 | |
183 | |||
184 | void pgm_prepare_for_next_period(struct task_struct *t) | ||
185 | { | ||
186 | TRACE_TASK(t, "pgm_prepage_for_next_period().\n"); | ||
187 | |||
188 | prepare_for_next_period(t); | ||
189 | } | ||
190 | |||
191 | |||
192 | int pgm_complete_job(struct task_struct *t) | ||
193 | { | ||
194 | struct pgm_consume *cons; | ||
195 | unsigned long i; | ||
196 | unsigned long flags; | ||
197 | int still_satisfied = 0; | ||
122 | 198 | ||
123 | keep_going = __is_pgm_satisfied(t); | 199 | BUG_ON(!t); |
200 | BUG_ON(!is_realtime(t)); | ||
201 | BUG_ON(!is_pgm(t)); | ||
202 | |||
203 | TRACE_TASK(t, "pgm_complete_job(). [src/inter/sink] = [%d/%d/%d]\n", | ||
204 | is_pgm_src(t), is_pgm_intermediate(t), is_pgm_sink(t)); | ||
205 | |||
206 | if(!is_pgm_src(t)) { | ||
207 | |||
208 | TRACE_TASK(t, "re-evaluating constraints\n"); | ||
209 | |||
210 | cons = tsk_rt(t)->pgm_params.consume; | ||
211 | |||
212 | if(cons->nr_consumptions != 0) { | ||
213 | /* flag constraints as unmet */ | ||
214 | spin_lock_irqsave(&cons->lock, flags); | ||
124 | 215 | ||
125 | spin_unlock_irqrestore(&cons->lock, flags); | 216 | for(i = 0; i < cons->nr_consumptions; ++i) { |
217 | if(cons->consume[i].nr_tokens <= cons->consume[i].required) { | ||
218 | __set_bit(i, cons->unsatisfied); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | still_satisfied = __is_pgm_satisfied(t); | ||
126 | 223 | ||
127 | return(keep_going); | 224 | spin_unlock_irqrestore(&cons->lock, flags); |
225 | } | ||
226 | |||
227 | if(still_satisfied) { | ||
228 | TRACE_TASK(t, "all constraints are still satisfied!\n"); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* produce new tokens, possibly waking up children, | ||
233 | * or setup for the next PGM root. | ||
234 | */ | ||
235 | pgm_produce(t); | ||
236 | |||
237 | return(still_satisfied); | ||
128 | } | 238 | } |
129 | 239 | ||
130 | 240 | ||
241 | int do_pgm_add_edge(struct task_struct *a, int nr_gen, | ||
242 | struct task_struct *b, int nr_req) | ||
243 | { | ||
244 | int retval = 0; | ||
245 | struct pgm_produce *prod; | ||
246 | struct pgm_consume *cons; | ||
247 | |||
248 | // validation of parameters takes place upstream. | ||
249 | |||
250 | if(!is_pgm(a)) { | ||
251 | // 'a' is the root. set itself as such. | ||
252 | tsk_rt(a)->pgm_params.root = a; | ||
253 | } | ||
254 | |||
255 | if(tsk_rt(a)->pgm_params.produce == NULL) { | ||
256 | tsk_rt(a)->pgm_params.produce = | ||
257 | kmalloc(sizeof(pgm_produce), GFP_KERNEL); | ||
258 | memset(tsk_rt(a)->pgm_params.produce, 0, sizeof(pgm_produce)); | ||
259 | } | ||
260 | |||
261 | if(tsk_rt(b)->pgm_params.consume == NULL) { | ||
262 | tsk_rt(b)->pgm_params.consume = | ||
263 | kmalloc(sizeof(pgm_consume), GFP_KERNEL); | ||
264 | memset(tsk_rt(b)->pgm_params.consume, 0, sizeof(pgm_consume)); | ||
265 | |||
266 | spin_lock_init(&(tsk_rt(b)->pgm_params.consume->lock)); | ||
267 | } | ||
268 | |||
269 | prod = tsk_rt(a)->pgm_params.produce; | ||
270 | cons = tsk_rt(b)->pgm_params.consume; | ||
271 | |||
272 | if(prod->nr_productions + 1 >= MAX_FAN || | ||
273 | cons->nr_consumptions + 1 >= MAX_FAN) { | ||
274 | retval = -EINVAL; | ||
275 | goto out; | ||
276 | } | ||
277 | |||
278 | // set up parent | ||
279 | prod->produce[prod->nr_productions].child = b; | ||
280 | prod->produce[prod->nr_productions].production_idx = cons->nr_consumptions; | ||
281 | prod->produce[prod->nr_productions].nr_tokens = nr_gen; | ||
282 | ++(prod->nr_productions); | ||
283 | |||
284 | |||
285 | // set up child | ||
286 | cons->consume[cons->nr_consumptions].required = nr_req; | ||
287 | cons->consume[cons->nr_consumptions].nr_tokens = 0; | ||
288 | __set_bit(cons->nr_consumptions, cons->unsatisfied); | ||
289 | ++(cons->nr_consumptions); | ||
290 | |||
291 | // copy over root node from a to b | ||
292 | tsk_rt(b)->pgm_params.root = tsk_rt(a)->pgm_params.root; | ||
293 | |||
294 | // mark as pgm nodes | ||
295 | tsk_rt(a)->is_pgm_node = 1; | ||
296 | tsk_rt(b)->is_pgm_node = 1; | ||
297 | |||
298 | out: | ||
299 | return retval; | ||
300 | } | ||
301 | |||
302 | int do_pgm_signal_ready(struct task_struct *root) | ||
303 | { | ||
304 | int retval = -EINVAL; | ||
305 | |||
306 | tsk_rt(current)->pgm_params.root = root; | ||
307 | |||
308 | /* decrement the parent's semaphore and then suspend */ | ||
309 | |||
310 | return retval; | ||
311 | } | ||
312 | |||
313 | int do_pgm_set_nr_children(int nr_children) | ||
314 | { | ||
315 | int retval = -EINVAL; | ||
316 | |||
317 | /* TODO: set up a counting semaphore */ | ||
318 | |||
319 | return retval; | ||
320 | } | ||
321 | |||
322 | int do_pgm_wait_for_children(void) | ||
323 | { | ||
324 | int retval = -EINVAL; | ||
325 | struct task_struct *root = current; | ||
326 | |||
327 | /* TODO: sleep on a counting semaphore */ | ||
328 | |||
329 | return retval; | ||
330 | } | ||
131 | 331 | ||
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 6ed504f4750e..c1145fc1dc8c 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -30,6 +30,10 @@ | |||
30 | 30 | ||
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | 32 | ||
33 | #ifdef CONFIG_PGM | ||
34 | #include <litmus/pgm.h> | ||
35 | #endif | ||
36 | |||
33 | /* Overview of GSN-EDF operations. | 37 | /* Overview of GSN-EDF operations. |
34 | * | 38 | * |
35 | * For a detailed explanation of GSN-EDF have a look at the FMLP paper. This | 39 | * For a detailed explanation of GSN-EDF have a look at the FMLP paper. This |
@@ -250,12 +254,43 @@ static noinline void requeue(struct task_struct* task) | |||
250 | /* sanity check before insertion */ | 254 | /* sanity check before insertion */ |
251 | BUG_ON(is_queued(task)); | 255 | BUG_ON(is_queued(task)); |
252 | 256 | ||
257 | #ifndef CONFIG_PGM | ||
253 | if (is_released(task, litmus_clock())) | 258 | if (is_released(task, litmus_clock())) |
254 | __add_ready(&gsnedf, task); | 259 | __add_ready(&gsnedf, task); |
255 | else { | 260 | else { |
256 | /* it has got to wait */ | 261 | /* it has got to wait */ |
257 | add_release(&gsnedf, task); | 262 | add_release(&gsnedf, task); |
258 | } | 263 | } |
264 | #else | ||
265 | /* !!! DON'T ALLOW pgm_src NODES TO REQUEUE AFTER COMPLETION !!! | ||
266 | * !!! They are enqueued by their pgm_sink nodes !!! | ||
267 | */ | ||
268 | if (!is_pgm(task) || is_pgm_src(task)) { | ||
269 | if (is_released(task, litmus_clock())) { | ||
270 | __add_ready(&gsnedf, task); | ||
271 | } | ||
272 | else { | ||
273 | /* it has got to wait */ | ||
274 | add_release(&gsnedf, task); | ||
275 | } | ||
276 | } | ||
277 | else { | ||
278 | if (is_pgm_intermediate(task)) { | ||
279 | if (is_pgm_satisfied(task)) { | ||
280 | __add_ready(&gsnedf, task); | ||
281 | } | ||
282 | else { | ||
283 | /* put in no queue. parent will wake it up since | ||
284 | we are doing early releasing. */ | ||
285 | WARN_ON(1); | ||
286 | } | ||
287 | } | ||
288 | else { | ||
289 | /* should be unreachable */ | ||
290 | WARN_ON(1); | ||
291 | } | ||
292 | } | ||
293 | #endif | ||
259 | } | 294 | } |
260 | 295 | ||
261 | #ifdef CONFIG_SCHED_CPU_AFFINITY | 296 | #ifdef CONFIG_SCHED_CPU_AFFINITY |
@@ -341,16 +376,44 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
341 | 376 | ||
342 | /* set flags */ | 377 | /* set flags */ |
343 | set_rt_flags(t, RT_F_SLEEP); | 378 | set_rt_flags(t, RT_F_SLEEP); |
379 | |||
380 | #ifndef CONFIG_PGM | ||
344 | /* prepare for next period */ | 381 | /* prepare for next period */ |
345 | prepare_for_next_period(t); | 382 | prepare_for_next_period(t); |
346 | if (is_released(t, litmus_clock())) | 383 | |
384 | if(is_released(t, litmus_clock())) { | ||
347 | sched_trace_task_release(t); | 385 | sched_trace_task_release(t); |
386 | } | ||
387 | |||
348 | /* unlink */ | 388 | /* unlink */ |
349 | unlink(t); | 389 | unlink(t); |
350 | /* requeue | 390 | /* requeue |
351 | * But don't requeue a blocking task. */ | 391 | * But don't requeue a blocking task. */ |
352 | if (is_running(t)) | 392 | if (is_running(t)) |
353 | gsnedf_job_arrival(t); | 393 | gsnedf_job_arrival(t); |
394 | |||
395 | #else | ||
396 | if(!is_pgm(t)) { | ||
397 | /* prepare for next period */ | ||
398 | prepare_for_next_period(t); | ||
399 | |||
400 | if(is_released(t, litmus_clock())) { | ||
401 | sched_trace_task_release(t); | ||
402 | } | ||
403 | } | ||
404 | else { | ||
405 | /* prepare for next period */ | ||
406 | pgm_prepare_for_next_period(t); | ||
407 | } | ||
408 | |||
409 | /* unlink */ | ||
410 | unlink(t); | ||
411 | /* requeue | ||
412 | * But don't requeue a blocking task, or pgm tasks */ | ||
413 | if (!is_pgm(t) && is_running(t)) { | ||
414 | gsnedf_job_arrival(t); | ||
415 | } | ||
416 | #endif | ||
354 | } | 417 | } |
355 | 418 | ||
356 | /* gsnedf_tick - this function is called for every local timer | 419 | /* gsnedf_tick - this function is called for every local timer |