diff options
-rw-r--r-- | include/litmus/edf_common.h | 8 | ||||
-rw-r--r-- | include/litmus/prio_sem.h | 31 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 35 | ||||
-rw-r--r-- | litmus/Makefile | 2 | ||||
-rw-r--r-- | litmus/edf_common.c | 19 | ||||
-rw-r--r-- | litmus/fmlp.c | 2 | ||||
-rw-r--r-- | litmus/prio_sem.c | 183 |
7 files changed, 265 insertions, 15 deletions
diff --git a/include/litmus/edf_common.h b/include/litmus/edf_common.h index 80d4321cc87e..b6081553d901 100644 --- a/include/litmus/edf_common.h +++ b/include/litmus/edf_common.h | |||
@@ -22,6 +22,10 @@ int edf_ready_order(struct bheap_node* a, struct bheap_node* b); | |||
22 | 22 | ||
23 | int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t); | 23 | int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t); |
24 | 24 | ||
25 | int edf_set_hp_task(struct pi_semaphore *sem); | 25 | #ifdef CONFIG_FMLP |
26 | int edf_set_hp_cpu_task(struct pi_semaphore *sem, int cpu); | 26 | int edf_set_hp_task(struct fmlp_semaphore *sem); |
27 | int edf_set_hp_cpu_task(struct fmlp_semaphore *sem, int cpu); | ||
27 | #endif | 28 | #endif |
29 | |||
30 | #endif | ||
31 | |||
diff --git a/include/litmus/prio_sem.h b/include/litmus/prio_sem.h new file mode 100644 index 000000000000..eb54c670947a --- /dev/null +++ b/include/litmus/prio_sem.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* Operations and structures for dealing with generic priority inheritance. */ | ||
2 | |||
3 | #ifndef _LINUX_PI_H_ | ||
4 | #include <linux/sched.h> | ||
5 | |||
6 | /* forward declaration */ | ||
7 | struct pi_semaphore; | ||
8 | |||
9 | /* stack operations */ | ||
10 | void push_pi_sem( | ||
11 | struct task_struct *tsk, | ||
12 | struct task_struct *inh, | ||
13 | struct pi_semaphore *sem); | ||
14 | |||
15 | void pop_pi_sem(struct task_struct *tsk); | ||
16 | |||
17 | pi_sem_record_t* peek_pi_sem(struct task_struct *tsk); | ||
18 | |||
19 | /* non-stack operations */ | ||
20 | int update_pi_sem( | ||
21 | struct task_struct *tsk, | ||
22 | struct task_struct *inh, | ||
23 | struct pi_semaphore *sem); | ||
24 | |||
25 | int remove_pi_sem( | ||
26 | struct task_struct *tsk, | ||
27 | struct pi_semaphore *sem); | ||
28 | |||
29 | int has_pi_sem(struct task_struct *tsk); | ||
30 | |||
31 | #endif | ||
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index 6f40b52f0802..9e2f06951d4b 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -102,7 +102,7 @@ struct rt_job { | |||
102 | * acquired. | 102 | * acquired. |
103 | */ | 103 | */ |
104 | struct pi_sem_record { | 104 | struct pi_sem_record { |
105 | /* Pointer to inheritance-donating job. | 105 | /* Task from which task inherits. |
106 | * May be set to "self" if there is no active | 106 | * May be set to "self" if there is no active |
107 | * inheritance from this semaphore. | 107 | * inheritance from this semaphore. |
108 | */ | 108 | */ |
@@ -136,13 +136,34 @@ struct rt_param { | |||
136 | /* timing parameters */ | 136 | /* timing parameters */ |
137 | struct rt_job job_params; | 137 | struct rt_job job_params; |
138 | 138 | ||
139 | /* task representing the current "inherited" task | 139 | #ifdef CONFIG_PI_SEMAPHORES |
140 | * priority, assigned by inherit_priority and | 140 | /* Stack of tasks representing the inheritance from |
141 | * return priority in the scheduler plugins. | 141 | * nested priority inheriting semaphores. Also provides |
142 | * could point to self if PI does not result in | 142 | * a list of currently held pi-inheriting semaphores. |
143 | * an increased task priority. | 143 | * |
144 | * End of List = Stack Top | ||
145 | * | ||
146 | * If a semaphore provides no inheritance, then record | ||
147 | * pointing to self should be pushed onto the stack (so | ||
148 | * inheritance record may be updated at a later time | ||
149 | * if a higher-priority job blocks). | ||
150 | * | ||
151 | * Other protocols may require additional information if | ||
152 | * a task can inherit multiple parameters from several other | ||
153 | * tasks. | ||
144 | */ | 154 | */ |
145 | struct task_struct* inh_task; | 155 | struct list_head pi_sem_stack; |
156 | |||
157 | /* It is useful to cache the highest priority inherited from | ||
158 | * all held locks (as recored by pi_sem_stack). eff_priority | ||
159 | * is this cache. Further, a protocol may not use traditional | ||
160 | * nesting, such as FMLP-Long. Such protocols may forgo the | ||
161 | * the use of pi_sem_stack and use eff_priority to track inheritance | ||
162 | * alone. | ||
163 | */ | ||
164 | struct task_struct* eff_priority; | ||
165 | #endif | ||
166 | |||
146 | 167 | ||
147 | #ifdef CONFIG_NP_SECTION | 168 | #ifdef CONFIG_NP_SECTION |
148 | /* For the FMLP under PSN-EDF, it is required to make the task | 169 | /* For the FMLP under PSN-EDF, it is required to make the task |
diff --git a/litmus/Makefile b/litmus/Makefile index 30369787ece2..1cf2b6267ae3 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -18,6 +18,8 @@ obj-y = sched_plugin.o litmus.o \ | |||
18 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o | 18 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o |
19 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o | 19 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o |
20 | 20 | ||
21 | obj-$(CONFIG_PI_SEMAPHORES) += prio_sem.o | ||
22 | |||
21 | obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o | 23 | obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o |
22 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o | 24 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o |
23 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o | 25 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o |
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 06daec66c984..1e91848a71dd 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -18,6 +18,12 @@ | |||
18 | * than second. Deadline ties are broken by PID. | 18 | * than second. Deadline ties are broken by PID. |
19 | * | 19 | * |
20 | * both first and second may be NULL | 20 | * both first and second may be NULL |
21 | * | ||
22 | * WARNING: Assumes rt_param.eff_priority holds the effective | ||
23 | * priority if PI semaphores are in use. PI protocols should | ||
24 | * cache the highest priority received through all held locks | ||
25 | * in rt_param.eff_priority (or use a different edf_higher_prio() | ||
26 | * function). | ||
21 | */ | 27 | */ |
22 | int edf_higher_prio(struct task_struct* first, | 28 | int edf_higher_prio(struct task_struct* first, |
23 | struct task_struct* second) | 29 | struct task_struct* second) |
@@ -32,14 +38,15 @@ int edf_higher_prio(struct task_struct* first, | |||
32 | return 0; | 38 | return 0; |
33 | } | 39 | } |
34 | 40 | ||
35 | 41 | #ifdef CONFIG_PI_SEMAPHORES | |
36 | /* Check for inherited priorities. Change task | 42 | /* Check for inherited priorities. Change task |
37 | * used for comparison in such a case. | 43 | * used for comparison in such a case. |
38 | */ | 44 | */ |
39 | if (first && first->rt_param.inh_task) | 45 | if (first && (first->rt_param.eff_priority != first)) |
40 | first_task = first->rt_param.inh_task; | 46 | first_task = first->rt_param.eff_priority; |
41 | if (second && second->rt_param.inh_task) | 47 | if (second && (second->rt_param.eff_priority != second)) |
42 | second_task = second->rt_param.inh_task; | 48 | second_task = second->rt_param.eff_priority; |
49 | #endif | ||
43 | 50 | ||
44 | return | 51 | return |
45 | /* it has to exist in order to have higher priority */ | 52 | /* it has to exist in order to have higher priority */ |
@@ -65,7 +72,7 @@ int edf_higher_prio(struct task_struct* first, | |||
65 | * priority wins. | 72 | * priority wins. |
66 | */ | 73 | */ |
67 | (first_task->pid == second_task->pid && | 74 | (first_task->pid == second_task->pid && |
68 | !second->rt_param.inh_task)))); | 75 | (second == second_task))))); |
69 | } | 76 | } |
70 | 77 | ||
71 | int edf_ready_order(struct bheap_node* a, struct bheap_node* b) | 78 | int edf_ready_order(struct bheap_node* a, struct bheap_node* b) |
diff --git a/litmus/fmlp.c b/litmus/fmlp.c index de46e626f43f..36965efe37e5 100644 --- a/litmus/fmlp.c +++ b/litmus/fmlp.c | |||
@@ -36,8 +36,10 @@ static void* create_fmlp_semaphore(void) | |||
36 | for (i = 0; i < NR_CPUS; i++) | 36 | for (i = 0; i < NR_CPUS; i++) |
37 | sem->pi.hp.cpu_task[i] = NULL; | 37 | sem->pi.hp.cpu_task[i] = NULL; |
38 | 38 | ||
39 | /* FMLP-Long does not use semaphore stack. | ||
39 | sem->pi.stack_node.inh_task = NULL; | 40 | sem->pi.stack_node.inh_task = NULL; |
40 | INIT_LIST_HEAD(&sem->pi.stack_node.list); | 41 | INIT_LIST_HEAD(&sem->pi.stack_node.list); |
42 | */ | ||
41 | 43 | ||
42 | return sem; | 44 | return sem; |
43 | } | 45 | } |
diff --git a/litmus/prio_sem.c b/litmus/prio_sem.c new file mode 100644 index 000000000000..3c436656a8b4 --- /dev/null +++ b/litmus/prio_sem.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* Operations and structures for dealing with generic priority inheritance. */ | ||
2 | |||
3 | #include <litmus/litmus.h> | ||
4 | #include <litmus/prio_sem.h> | ||
5 | |||
6 | #include <litmus/sched_plugin.h> | ||
7 | |||
8 | /* Add a record to the pi sem history stack. | ||
9 | * | ||
10 | * Recommend that inh == tsk for "no inheritance", though this | ||
11 | * is up to the pi sem protocol implementation. inh could be | ||
12 | * NULL as long as the protocol implementation expects it. | ||
13 | */ | ||
14 | void push_pi_sem( | ||
15 | struct task_struct *tsk, | ||
16 | struct task_struct *inh, | ||
17 | struct pi_semaphore *sem) | ||
18 | { | ||
19 | sem->stack_node.inh_task = inh; | ||
20 | |||
21 | /* list_add() needs node to be initialized properly. Node may | ||
22 | * not be initialized yet. | ||
23 | */ | ||
24 | INIT_LIST_HEAD(&sem->stack_node.list); | ||
25 | |||
26 | list_add_tail(&tsk->rt_param.pi_sem_stack, &sem->stack_node.list); | ||
27 | |||
28 | TRACE_TASK(tsk, | ||
29 | "Pushed semaphore %p with inheritance from task %d\n", | ||
30 | sem, inh->pid); | ||
31 | } | ||
32 | |||
33 | /* Removes the last semaphore record. */ | ||
34 | void pop_pi_sem(struct task_struct *tsk) | ||
35 | { | ||
36 | int empty = list_empty(&tsk->rt_param.pi_sem_stack); | ||
37 | |||
38 | WARN_ON(empty); | ||
39 | |||
40 | if(!empty) | ||
41 | { | ||
42 | pi_sem_record_t *rec = | ||
43 | list_entry(tsk->rt_param.pi_sem_stack.prev, pi_sem_record_t, list); | ||
44 | list_del(&rec->list); | ||
45 | |||
46 | TRACE_TASK(tsk, "Popped sem/inh record %p / %d.\n", | ||
47 | container_of(rec, struct pi_semaphore, stack_node), | ||
48 | rec->inh_task->pid); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /* Get a pointer to the last semaphore pushed on to the stack. | ||
53 | * Returns NULL if there is no record. | ||
54 | */ | ||
55 | pi_sem_record_t* peek_pi_sem(struct task_struct *tsk) | ||
56 | { | ||
57 | if(!list_empty(&tsk->rt_param.pi_sem_stack)) | ||
58 | { | ||
59 | pi_sem_record_t *rec = | ||
60 | list_entry(tsk->rt_param.pi_sem_stack.prev, | ||
61 | pi_sem_record_t, list); | ||
62 | return rec; | ||
63 | } | ||
64 | return NULL; | ||
65 | } | ||
66 | |||
67 | |||
68 | /* Update priority inheritance. */ | ||
69 | int update_pi_sem( | ||
70 | struct task_struct *tsk, | ||
71 | struct task_struct *inh, | ||
72 | struct pi_semaphore *sem) | ||
73 | { | ||
74 | int success = 0; | ||
75 | struct list_head *pos, *next; | ||
76 | pi_sem_record_t *rec; | ||
77 | |||
78 | /* Though we have a reference to the semaphore (sem), we need | ||
79 | * to search through tsk's stack to validate that tsk actually | ||
80 | * holds sem. If tsk holds sem, then sem will be in its stack. | ||
81 | * | ||
82 | * TODO: Add function pointer hooks to pi_semaphore for operations | ||
83 | * such as "int is_holder(struct task_struct *tsk)". pi_semaphore | ||
84 | * does not track its holder(s), though concrete protocols may, | ||
85 | * providing more efficient validation methods than this stack search. | ||
86 | * Another function may be "pi_sem_record_t* get_record(...)" if the | ||
87 | * semaphore protocol supports multiple holders (though | ||
88 | * pi_semaphore.stack_node will probably go unused or replaced in | ||
89 | * such cases). | ||
90 | */ | ||
91 | |||
92 | /* Assuming a sane locking order, the lock we're looking for | ||
93 | * is probably towards (at) the end. | ||
94 | */ | ||
95 | list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack) | ||
96 | { | ||
97 | struct pi_semaphore* which_sem; | ||
98 | rec = list_entry(pos, pi_sem_record_t, list); | ||
99 | |||
100 | which_sem = container_of(rec, struct pi_semaphore, stack_node); | ||
101 | if(which_sem == sem) | ||
102 | { | ||
103 | TRACE_TASK(tsk, "Updating inheritance from %d to %d on sem %p\n", | ||
104 | rec->inh_task->pid, inh->pid, sem); | ||
105 | |||
106 | rec->inh_task = inh; | ||
107 | success = 1; | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | if(!success) | ||
113 | { | ||
114 | TRACE_TASK(tsk, "Could not find record for sem %p to update inheritance.\n", | ||
115 | sem); | ||
116 | } | ||
117 | |||
118 | return success; | ||
119 | } | ||
120 | |||
121 | /* Removes a record from the semaphore stack if it exists. | ||
122 | * | ||
123 | * Note: pop_pi_sem() may be more appropriate if total ordering can be | ||
124 | * guaranteed. | ||
125 | */ | ||
126 | int remove_pi_sem(struct task_struct *tsk, struct pi_semaphore *sem) | ||
127 | { | ||
128 | int success = 0; | ||
129 | struct list_head *pos, *next; | ||
130 | pi_sem_record_t *rec; | ||
131 | |||
132 | /* Though we have a reference to the semaphore (sem), we need | ||
133 | * to search through tsk's stack to validate that tsk actually | ||
134 | * holds sem. If tsk holds sem, then sem will be in its stack. | ||
135 | * | ||
136 | * TODO: Add function pointer hooks to pi_semaphore for operations | ||
137 | * such as "int is_holder(struct task_struct *tsk)". pi_semaphore | ||
138 | * does not track its holder(s), though concrete protocols may, | ||
139 | * providing more efficient validation methods than this stack search. | ||
140 | * Another function may be "pi_sem_record_t* get_record(...)" if the | ||
141 | * semaphore protocol supports multiple holders (though | ||
142 | * pi_semaphore.stack_node will probably go unused or replaced in | ||
143 | * such cases). | ||
144 | */ | ||
145 | |||
146 | /* Assuming a sane locking order, the lock we're looking for | ||
147 | * is probably towards (at) the end. | ||
148 | */ | ||
149 | list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack) | ||
150 | { | ||
151 | struct pi_semaphore* which_sem; | ||
152 | rec = list_entry(pos, pi_sem_record_t, list); | ||
153 | |||
154 | which_sem = container_of(rec, struct pi_semaphore, stack_node); | ||
155 | if(which_sem == sem) | ||
156 | { | ||
157 | TRACE_TASK(tsk, "Removing semaphore stack record from %d with sem %p\n", | ||
158 | rec->inh_task->pid, sem); | ||
159 | |||
160 | list_del(&rec->list); | ||
161 | success = 1; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | if(!success) | ||
167 | { | ||
168 | TRACE_TASK(tsk, "Could not find record for sem %p to remove.\n", | ||
169 | sem); | ||
170 | } | ||
171 | |||
172 | return success; | ||
173 | } | ||
174 | |||
175 | /* Returns true of tsk holds ANY pi semaphores (as reportable by the stack). | ||
176 | * Function will return false if the protocol in use does not use the stack, | ||
177 | * such as FMLP-Long, which uses rt_params.eff_priority. | ||
178 | */ | ||
179 | int has_pi_sem(struct task_struct *tsk) | ||
180 | { | ||
181 | return !list_empty(&tsk->rt_param.pi_sem_stack); | ||
182 | } | ||
183 | |||