aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-06-13 22:54:33 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2012-06-13 22:54:33 -0400
commit63360ea7ec23f403462e5335d4a3aed9d756a24e (patch)
tree25535ae302ca39f2f1168f4aa94017b2fdf0908d
parent42cbfb1aecca6482f278e640ea4af21f02a775f9 (diff)
Added syscall hooks, 'finished' produce/consume code.
-rw-r--r--include/litmus/litmus.h20
-rw-r--r--include/litmus/pgm.h28
-rw-r--r--include/litmus/rt_param.h19
-rw-r--r--include/litmus/unistd_32.h6
-rw-r--r--include/litmus/unistd_64.h12
-rw-r--r--litmus/jobs.c15
-rw-r--r--litmus/litmus.c120
-rw-r--r--litmus/pgm.c290
-rw-r--r--litmus/sched_gsn_edf.c65
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) \
138int is_pgm_satisfied(struct task_struct* t); 134 (is_pgm_intermediate(t) && \
139void pgm_produce(struct task_struct* t); 135 tsk_rt(t)->pgm_params.produce == NULL && \
140void pgm_consume(struct task_struct* t); 136 tsk_rt(t)->pgm_params.consume != NULL)
141int 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
151void srp_ceiling_block(void); 139void 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
13int is_pgm_satisfied(struct task_struct* t);
14
15void pgm_prepare_for_next_period(struct task_struct *t);
16
17int pgm_complete_job(struct task_struct* t);
18
19int do_pgm_add_edge(struct task_struct *a, int nr_gen,
20 struct task_struct *b, int nr_req);
21int do_pgm_signal_ready(struct task_struct *src);
22int do_pgm_set_nr_children(int nr_children);
23int 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
80struct 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
100struct pgm_produce 108struct 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
106struct pgm_consumption 114struct 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
112struct pgm_consume 121struct 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
121struct rt_pgm { 129struct 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
9void prepare_for_next_period(struct task_struct *t) 13void 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 */
34long complete_job(void) 38long 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 */
25atomic_t rt_task_count = ATOMIC_INIT(0); 29atomic_t rt_task_count = ATOMIC_INIT(0);
26static DEFINE_RAW_SPINLOCK(task_transition_lock); 30static 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
295asmlinkage 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
324out:
325 return retval;
326}
327
328asmlinkage 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
352out:
353 return retval;
354}
355
356asmlinkage 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
365out:
366 return retval;
367}
368
369asmlinkage 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
378out:
379 return retval;
380}
381
382
383#else
384asmlinkage long sys_add_pgm_edge(struct pgm_edge __user *edge)
385{
386 return -EINVAL;
387}
388
389asmlinkage long sys_pgm_signal_ready(pid_t r)
390{
391 return -EINVAL;
392}
393
394asmlinkage long sys_pgm_set_nr_children(int nr_children)
395{
396 return -EINVAL;
397}
398
399asmlinkage 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. */
290static void reinit_litmus_state(struct task_struct* p, int restore) 410static 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
12static void pgm_consume(struct task_struct *t);
13static void pgm_produce_intermediate(struct task_struct *t);
14static void pgm_produce_root(struct task_struct *t);
9 15
10static inline int __is_pgm_satisfied(struct task_struct* t) 16
17static 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
19int is_pgm_satisfied(struct task_struct* t) 33
34static 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
37void pgm_produce(struct task_struct* t) 48
49static 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
81void pgm_consume(struct task_struct* t) 121
122static 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
137static 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
102int pgm_complete(struct task_struct* t) 161
162/**********************************************/
163
164
165int 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
184void 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
192int 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
241int 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
298out:
299 return retval;
300}
301
302int 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
313int 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
322int 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