aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/prio_sem.c
blob: 3c436656a8b4346750ef11a128ac6699d2974b34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* Operations and structures for dealing with generic priority inheritance. */

#include <litmus/litmus.h>
#include <litmus/prio_sem.h>

#include <litmus/sched_plugin.h>

/* Add a record to the pi sem history stack.
 *
 * Recommend that inh == tsk for "no inheritance", though this
 * is up to the pi sem protocol implementation.  inh could be
 * NULL as long as the protocol implementation expects it.
 */
void push_pi_sem(
	struct task_struct *tsk,
	struct task_struct *inh,
	struct pi_semaphore *sem)
{
	sem->stack_node.inh_task = inh;

	/* list_add() needs node to be initialized properly.  Node may
	 * not be initialized yet.
	 */
	INIT_LIST_HEAD(&sem->stack_node.list);

	list_add_tail(&tsk->rt_param.pi_sem_stack, &sem->stack_node.list);

	TRACE_TASK(tsk,
		"Pushed semaphore %p with inheritance from task %d\n",
		sem, inh->pid);
}

/* Removes the last semaphore record. */
void pop_pi_sem(struct task_struct *tsk)
{
	int empty = list_empty(&tsk->rt_param.pi_sem_stack);

	WARN_ON(empty);

	if(!empty)
	{
		pi_sem_record_t *rec =
			list_entry(tsk->rt_param.pi_sem_stack.prev, pi_sem_record_t, list);
		list_del(&rec->list);

		TRACE_TASK(tsk, "Popped sem/inh record %p / %d.\n",
				container_of(rec, struct pi_semaphore, stack_node),
				rec->inh_task->pid);
	}
}

/* Get a pointer to the last semaphore pushed on to the stack.
 * Returns NULL if there is no record.
 */
pi_sem_record_t* peek_pi_sem(struct task_struct *tsk)
{
	if(!list_empty(&tsk->rt_param.pi_sem_stack))
	{
		pi_sem_record_t *rec =
			list_entry(tsk->rt_param.pi_sem_stack.prev,
				pi_sem_record_t, list);
		return rec;
	}
	return NULL;
}


/* Update priority inheritance. */
int update_pi_sem(
	struct task_struct *tsk,
	struct task_struct *inh,
	struct pi_semaphore *sem)
{
	int success = 0;
	struct list_head *pos, *next;
	pi_sem_record_t *rec;

	/* Though we have a reference to the semaphore (sem), we need
	 * to search through tsk's stack to validate that tsk actually
	 * holds sem.  If tsk holds sem, then sem will be in its stack.
	 *
	 * TODO: Add function pointer hooks to pi_semaphore for operations
	 * such as "int is_holder(struct task_struct *tsk)".  pi_semaphore
	 * does not track its holder(s), though concrete protocols may,
	 * providing more efficient validation methods than this stack search.
	 * Another function may be "pi_sem_record_t* get_record(...)" if the
	 * semaphore protocol supports multiple holders (though
	 * pi_semaphore.stack_node will probably go unused or replaced in
	 * such cases).
	 */

	/* Assuming a sane locking order, the lock we're looking for
	 * is probably towards (at) the end.
	 */
	list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack)
	{
		struct pi_semaphore* which_sem;
		rec = list_entry(pos, pi_sem_record_t, list);

		which_sem = container_of(rec, struct pi_semaphore, stack_node);
		if(which_sem == sem)
		{
			TRACE_TASK(tsk, "Updating inheritance from %d to %d on sem %p\n",
				rec->inh_task->pid, inh->pid, sem);

			rec->inh_task = inh;
			success = 1;
			break;
		}
	}

	if(!success)
	{
		TRACE_TASK(tsk, "Could not find record for sem %p to update inheritance.\n",
			sem);
	}

	return success;
}

/* Removes a record from the semaphore stack if it exists.
 *
 * Note: pop_pi_sem() may be more appropriate if total ordering can be
 * guaranteed.
 */
int remove_pi_sem(struct task_struct *tsk, struct pi_semaphore *sem)
{
	int success = 0;
	struct list_head *pos, *next;
	pi_sem_record_t *rec;

	/* Though we have a reference to the semaphore (sem), we need
	 * to search through tsk's stack to validate that tsk actually
	 * holds sem.  If tsk holds sem, then sem will be in its stack.
	 *
	 * TODO: Add function pointer hooks to pi_semaphore for operations
	 * such as "int is_holder(struct task_struct *tsk)".  pi_semaphore
	 * does not track its holder(s), though concrete protocols may,
	 * providing more efficient validation methods than this stack search.
	 * Another function may be "pi_sem_record_t* get_record(...)" if the
	 * semaphore protocol supports multiple holders (though
	 * pi_semaphore.stack_node will probably go unused or replaced in
	 * such cases).
	 */

	/* Assuming a sane locking order, the lock we're looking for
	 * is probably towards (at) the end.
	 */
	list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack)
	{   
		struct pi_semaphore* which_sem;
		rec = list_entry(pos, pi_sem_record_t, list);

		which_sem = container_of(rec, struct pi_semaphore, stack_node);
		if(which_sem == sem)
		{
			TRACE_TASK(tsk, "Removing semaphore stack record from %d with sem %p\n",
				rec->inh_task->pid, sem);

			list_del(&rec->list);
			success = 1;
			break;
		}   
	}   

	if(!success)
	{   
		TRACE_TASK(tsk, "Could not find record for sem %p to remove.\n",
			sem);
	}

	return success;	
}

/* Returns true of tsk holds ANY pi semaphores (as reportable by the stack).
 * Function will return false if the protocol in use does not use the stack,
 * such as FMLP-Long, which uses rt_params.eff_priority.
 */
int has_pi_sem(struct task_struct *tsk)
{
	return !list_empty(&tsk->rt_param.pi_sem_stack);
}