aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/litmus/edf_common.h8
-rw-r--r--include/litmus/prio_sem.h31
-rw-r--r--include/litmus/rt_param.h35
-rw-r--r--litmus/Makefile2
-rw-r--r--litmus/edf_common.c19
-rw-r--r--litmus/fmlp.c2
-rw-r--r--litmus/prio_sem.c183
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
23int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t); 23int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t);
24 24
25int edf_set_hp_task(struct pi_semaphore *sem); 25#ifdef CONFIG_FMLP
26int edf_set_hp_cpu_task(struct pi_semaphore *sem, int cpu); 26int edf_set_hp_task(struct fmlp_semaphore *sem);
27int 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 */
7struct pi_semaphore;
8
9/* stack operations */
10void push_pi_sem(
11 struct task_struct *tsk,
12 struct task_struct *inh,
13 struct pi_semaphore *sem);
14
15void pop_pi_sem(struct task_struct *tsk);
16
17pi_sem_record_t* peek_pi_sem(struct task_struct *tsk);
18
19/* non-stack operations */
20int update_pi_sem(
21 struct task_struct *tsk,
22 struct task_struct *inh,
23 struct pi_semaphore *sem);
24
25int remove_pi_sem(
26 struct task_struct *tsk,
27 struct pi_semaphore *sem);
28
29int 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 */
104struct pi_sem_record { 104struct 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 \
18obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o 18obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o
19obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o 19obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o
20 20
21obj-$(CONFIG_PI_SEMAPHORES) += prio_sem.o
22
21obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o 23obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o
22obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o 24obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o
23obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o 25obj-$(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 */
22int edf_higher_prio(struct task_struct* first, 28int 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
71int edf_ready_order(struct bheap_node* a, struct bheap_node* b) 78int 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 */
14void 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. */
34void 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 */
55pi_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. */
69int 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 */
126int 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 */
179int has_pi_sem(struct task_struct *tsk)
180{
181 return !list_empty(&tsk->rt_param.pi_sem_stack);
182}
183