diff options
-rw-r--r-- | include/litmus/litmus.h | 27 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 76 | ||||
-rw-r--r-- | litmus/Makefile | 2 | ||||
-rw-r--r-- | litmus/pgm.c | 131 |
4 files changed, 202 insertions, 34 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 0b071fd359f9..683407328f5a 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -120,6 +120,33 @@ static inline lt_t litmus_clock(void) | |||
120 | 120 | ||
121 | void preempt_if_preemptable(struct task_struct* t, int on_cpu); | 121 | void preempt_if_preemptable(struct task_struct* t, int on_cpu); |
122 | 122 | ||
123 | /* PGM macros */ | ||
124 | #define is_pgm(t) (tsk_rt(t)->is_pgm_node) | ||
125 | #define is_pgm_src(t) \ | ||
126 | (is_pgm(t) && \ | ||
127 | tsk_rt(t)->pgm_params.produce != 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) \ | ||
134 | (is_pgm(t) && \ | ||
135 | tsk_rt(t)->pgm_params.produce != NULL && \ | ||
136 | tsk_rt(t)->pgm_params.consume != NULL) | ||
137 | #ifdef CONFIG_PGM | ||
138 | int is_pgm_satisfied(struct task_struct* t); | ||
139 | void pgm_produce(struct task_struct* t); | ||
140 | void pgm_consume(struct task_struct* t); | ||
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 | |||
123 | #ifdef CONFIG_LITMUS_LOCKING | 150 | #ifdef CONFIG_LITMUS_LOCKING |
124 | void srp_ceiling_block(void); | 151 | void srp_ceiling_block(void); |
125 | #else | 152 | #else |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index a5d68250eef3..613e9f98294e 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -44,41 +44,7 @@ struct rt_task { | |||
44 | 44 | ||
45 | 45 | ||
46 | #ifdef CONFIG_PGM | 46 | #ifdef CONFIG_PGM |
47 | |||
48 | #define MAX_FAN CONFIG_MAX_PGM_FAN | 47 | #define MAX_FAN CONFIG_MAX_PGM_FAN |
49 | #define FAN_BYTES (((MAX_FAN)/8) + ((MAX_FAN)%8 != 0)) | ||
50 | |||
51 | struct pgm_production | ||
52 | { | ||
53 | struct task_struct* child; /* task that receives tokens */ | ||
54 | int nr_tokens; /* num tokens to generate */ | ||
55 | }; | ||
56 | |||
57 | struct pgm_produce | ||
58 | { | ||
59 | int nr_productions; /* num productions/children */ | ||
60 | struct pgm_production produce[0]; /* array of productions */ | ||
61 | }; | ||
62 | |||
63 | struct pgm_consumption | ||
64 | { | ||
65 | int required; /* number tokens required before firing */ | ||
66 | atomic_t token_countdown; /* consumption constraint met when <= 0 */ | ||
67 | }; | ||
68 | |||
69 | struct pgm_consume | ||
70 | { | ||
71 | int nr_consumptions; /* num of consumption constraints */ | ||
72 | char satisfied[FAN_BYTES]; /* bit-array of satisfied constraints; | ||
73 | bit == 0 means satisfied! */ | ||
74 | struct pgm_consumption consume[0]; /* array of consumption constraints */ | ||
75 | }; | ||
76 | |||
77 | struct rt_pgm { | ||
78 | struct pgm_produce *produce; /* output and current state */ | ||
79 | struct pgm_consume *consume; /* input constraints and current state */ | ||
80 | struct task_struct *src; /* only not NULL if task is sink */ | ||
81 | }; | ||
82 | #endif | 48 | #endif |
83 | 49 | ||
84 | union np_flag { | 50 | union np_flag { |
@@ -118,6 +84,48 @@ struct _rt_domain; | |||
118 | struct bheap_node; | 84 | struct bheap_node; |
119 | struct release_heap; | 85 | struct release_heap; |
120 | 86 | ||
87 | #ifdef CONFIG_PGM | ||
88 | |||
89 | #define FAN_CHUNK_SIZE (sizeof(unsigned long)) | ||
90 | #define NR_FAN_BITS_PER_CHUNK (8*FAN_CHUNK_SIZE) | ||
91 | #define NR_FAN_CHUNKS (((MAX_FAN)/(NR_FAN_BITS_PER_CHUNK)) + ((MAX_FAN)%(NR_FAN_BITS_PER_CHUNK) != 0)) | ||
92 | |||
93 | struct pgm_production | ||
94 | { | ||
95 | struct task_struct* child; /* task that receives tokens */ | ||
96 | int production_idx; /* consumption constraint index */ | ||
97 | int nr_tokens; /* num tokens to generate */ | ||
98 | }; | ||
99 | |||
100 | struct pgm_produce | ||
101 | { | ||
102 | unsigned long nr_productions; /* num productions/children */ | ||
103 | struct pgm_production produce[0]; /* array of productions */ | ||
104 | }; | ||
105 | |||
106 | struct pgm_consumption | ||
107 | { | ||
108 | unsigned long required; /* number tokens required before firing */ | ||
109 | long nr_tokens; /* constraint met when >= required */ | ||
110 | }; | ||
111 | |||
112 | struct pgm_consume | ||
113 | { | ||
114 | spinlock_t lock; | ||
115 | unsigned long nr_consumptions; /* num of consumption constraints */ | ||
116 | unsigned long unsatisfied[NR_FAN_CHUNKS]; /* bit-array of unsatisfied constraints */ | ||
117 | struct pgm_consumption consume[0]; /* array of consumption constraints */ | ||
118 | //atomic_t nr_pending_release; | ||
119 | }; | ||
120 | |||
121 | struct rt_pgm { | ||
122 | struct pgm_produce *produce; /* output and current state */ | ||
123 | struct pgm_consume *consume; /* input constraints and current state */ | ||
124 | struct task_struct *src; /* only not NULL if task is sink */ | ||
125 | }; | ||
126 | |||
127 | #endif /* end PGM */ | ||
128 | |||
121 | struct rt_job { | 129 | struct rt_job { |
122 | /* Time instant the the job was or will be released. */ | 130 | /* Time instant the the job was or will be released. */ |
123 | lt_t release; | 131 | lt_t release; |
diff --git a/litmus/Makefile b/litmus/Makefile index 4650d332fb11..40f7c97f7c0c 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -28,3 +28,5 @@ obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o | |||
28 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o | 28 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o |
29 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o | 29 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o |
30 | obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o | 30 | obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o |
31 | |||
32 | obj-$(CONFIG_PGM) += pgm.o | ||
diff --git a/litmus/pgm.c b/litmus/pgm.c new file mode 100644 index 000000000000..6710644eae8e --- /dev/null +++ b/litmus/pgm.c | |||
@@ -0,0 +1,131 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <linux/bitops.h> | ||
3 | #include <linux/spinlock.h> | ||
4 | |||
5 | #include <litmus/litmus.h> | ||
6 | #include <litmus/sched_plugin.h> | ||
7 | #include <litmus/rt_param.h> | ||
8 | |||
9 | |||
10 | static inline int __is_pgm_satisfied(struct task_struct* t) | ||
11 | { | ||
12 | unsigned long unsatisfied = | ||
13 | find_first_bit(tsk_rt(t)->pgm_params.consume->unsatisfied, | ||
14 | tsk_rt(t)->pgm_params.consume->nr_consumptions); | ||
15 | |||
16 | return (unsatisfied == tsk_rt(t)->pgm_params.consume->nr_consumptions); | ||
17 | } | ||
18 | |||
19 | int is_pgm_satisfied(struct task_struct* t) | ||
20 | { | ||
21 | int is_satisfied; | ||
22 | unsigned long flags; | ||
23 | |||
24 | BUG_ON(!t); | ||
25 | BUG_ON(!is_realtime(t)); | ||
26 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | ||
27 | |||
28 | spin_lock_irqsave(&tsk_rt(t)->pgm_params.consume->lock, flags); | ||
29 | |||
30 | is_satisfied = __is_pgm_satisfied(t); | ||
31 | |||
32 | spin_unlock_irqrestore(&tsk_rt(t)->pgm_params.consume->lock, flags); | ||
33 | |||
34 | return (is_satisfied); | ||
35 | } | ||
36 | |||
37 | void pgm_produce(struct task_struct* t) | ||
38 | { | ||
39 | unsigned long i; | ||
40 | struct pgm_produce *prod; | ||
41 | |||
42 | BUG_ON(!t); | ||
43 | BUG_ON(!is_realtime(t)); | ||
44 | BUG_ON(!is_pgm(t) || is_pgm_sink(t)); | ||
45 | |||
46 | prod = tsk_rt(t)->pgm_params.produce; | ||
47 | |||
48 | for(i = 0; i < prod->nr_productions; ++i) { | ||
49 | struct pgm_production *to_produce = &prod->produce[i]; | ||
50 | struct task_struct *child = to_produce->child; | ||
51 | struct pgm_consumption *child_input; | ||
52 | int unsatisfied; | ||
53 | unsigned long flags; | ||
54 | |||
55 | |||
56 | BUG_ON(!is_pgm(child) || is_pgm_src(child)); | ||
57 | |||
58 | child_input = &(tsk_rt(child)->pgm_params.consume->consume[to_produce->production_idx]); | ||
59 | |||
60 | spin_lock_irqsave(&tsk_rt(child)->pgm_params.consume->lock, flags); | ||
61 | |||
62 | child_input->nr_tokens += to_produce->nr_tokens; | ||
63 | |||
64 | if(child_input->nr_tokens >= child_input->required) { | ||
65 | unsatisfied = __test_and_clear_bit(to_produce->production_idx, | ||
66 | tsk_rt(child)->pgm_params.consume->unsatisfied); | ||
67 | |||
68 | if(unsatisfied) { | ||
69 | /* we satisfied the child's requirement */ | ||
70 | if(__is_pgm_satisfied(child)) { | ||
71 | /* all requirements met: release the child */ | ||
72 | |||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | spin_unlock_irqrestore(&tsk_rt(child)->pgm_params.consume->lock, flags); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | void pgm_consume(struct task_struct* t) | ||
82 | { | ||
83 | struct pgm_consume* cons; | ||
84 | unsigned long i; | ||
85 | unsigned long flags; | ||
86 | |||
87 | BUG_ON(!t); | ||
88 | BUG_ON(!is_realtime(t)); | ||
89 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | ||
90 | |||
91 | cons = tsk_rt(t)->pgm_params.consume; | ||
92 | |||
93 | spin_lock_irqsave(&cons->lock, flags); | ||
94 | |||
95 | for(i = 0; i < cons->nr_consumptions; ++i) { | ||
96 | cons->consume[i].nr_tokens -= cons->consume[i].required; | ||
97 | } | ||
98 | |||
99 | spin_unlock_irqrestore(&cons->lock, flags); | ||
100 | } | ||
101 | |||
102 | int pgm_complete(struct task_struct* t) | ||
103 | { | ||
104 | struct pgm_consume* cons; | ||
105 | unsigned long i; | ||
106 | unsigned long flags; | ||
107 | int keep_going = 0; | ||
108 | |||
109 | BUG_ON(!t); | ||
110 | BUG_ON(!is_realtime(t)); | ||
111 | BUG_ON(!is_pgm(t) || is_pgm_src(t)); | ||
112 | |||
113 | cons = tsk_rt(t)->pgm_params.consume; | ||
114 | |||
115 | spin_lock_irqsave(&cons->lock, flags); | ||
116 | |||
117 | for(i = 0; i < cons->nr_consumptions; ++i) { | ||
118 | if(cons->consume[i].nr_tokens <= cons->consume[i].required) { | ||
119 | __set_bit(i, cons->unsatisfied); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | keep_going = __is_pgm_satisfied(t); | ||
124 | |||
125 | spin_unlock_irqrestore(&cons->lock, flags); | ||
126 | |||
127 | return(keep_going); | ||
128 | } | ||
129 | |||
130 | |||
131 | |||