aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2010-07-12 15:25:40 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2010-08-03 12:42:59 -0400
commitcf08bf1004f77f25569fa7a6f9fbe3d18e9d98aa (patch)
tree6e7f944df756033465b8e2389fde850dcb03e31d
parenta0c6241d44317b55c790131d3215d52061ce4add (diff)
Implement the pi semaphore stack.
This patch continues the work to implement a generic pi framework. Under this framework, each task_struct maintains a stack of held locks, in the order they are acquired. This stack is mainly used to determine the proper inheritance when a lock is released. On release, the releasing job iterates through its semaphore stack to determine if it blocks a higher priority job and inherits the proper priority as needed. The stack is needed since a blocked job cannot push this information to the lock holder because the inheritance may not take place immediately when the job is blocked. Stack operations include push, pop, update, and peek. The semaphore stack is really only useful to protocols that support traditional nesting. Protocols that do not use traditional nesting, such as FMLP-Long, do not need a stack to track inheritance. So, struct rt_param now also has a task_struct pointer, eff_priority. eff_priority is used in almost the same way was rt_param.inh_task was used in the original FMLP implementation. The slight difference is that eff_priority is set to equal to self when a job acquires a semaphore with no inheritance. This is stylistically similar to FMLP using a semaphore stack. Note that FMLP-Long completely forgoes the use of semaphore stack and only uses eff_priority. Finally, it is intended that eff_priority also be used with nested protocols. A job using a nested protocol would set eff_priority equal to the highest priority received from all held locks. Thus, eff_priority caches the priority a job inherits (the semaphore stack does not need to be iterated through each time the job's priority is required).
-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