sched-rt.c 6.53 KB
Newer Older
1
/*
Philippe Gerum's avatar
Philippe Gerum committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * Copyright (C) 2008 Philippe Gerum <rpm@xenomai.org>.
 *
 * Xenomai is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * Xenomai is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Xenomai; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
19
#include <cobalt/kernel/sched.h>
Philippe Gerum's avatar
Philippe Gerum committed
20
21
22

static void xnsched_rt_init(struct xnsched *sched)
{
23
	xnsched_initq(&sched->rt.runnable);
Philippe Gerum's avatar
Philippe Gerum committed
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
}

static void xnsched_rt_requeue(struct xnthread *thread)
{
	/*
	 * Put back at same place: i.e. requeue to head of current
	 * priority group (i.e. LIFO, used for preemption handling).
	 */
	__xnsched_rt_requeue(thread);
}

static void xnsched_rt_enqueue(struct xnthread *thread)
{
	/*
	 * Enqueue for next pick: i.e. move to end of current priority
	 * group (i.e. FIFO).
	 */
	__xnsched_rt_enqueue(thread);
}

static void xnsched_rt_dequeue(struct xnthread *thread)
{
	/*
	 * Pull from the runnable thread queue.
	 */
	__xnsched_rt_dequeue(thread);
}

52
53
static void xnsched_rt_rotate(struct xnsched *sched,
			      const union xnsched_policy_param *p)
Philippe Gerum's avatar
Philippe Gerum committed
54
{
55
	struct xnthread *thread, *curr;
Philippe Gerum's avatar
Philippe Gerum committed
56

57
	if (xnsched_emptyq_p(&sched->rt.runnable))
Philippe Gerum's avatar
Philippe Gerum committed
58
59
		return;	/* No runnable thread in this class. */

60
61
62
63
64
	curr = sched->curr;

	if (p->rt.prio == XNSCHED_RUNPRIO)
		thread = curr;
	else {
65
		thread = xnsched_findq(&sched->rt.runnable, p->rt.prio);
66
		if (thread == NULL)
Philippe Gerum's avatar
Philippe Gerum committed
67
68
			return;
	}
69

70
71
	/*
	 * In case we picked the current thread, we have to make sure
72
	 * not to move it back to the run queue if it was blocked
73
74
75
	 * before we were called. The same goes if the current thread
	 * holds the scheduler lock.
	 */
76
77
78
79
	if (thread != curr ||
	    (!xnthread_test_state(curr, XNTHREAD_BLOCK_BITS) &&
	     curr->lock_count == 0))
		xnsched_putback(thread);
Philippe Gerum's avatar
Philippe Gerum committed
80
81
}

82
void xnsched_rt_tick(struct xnsched *sched)
Philippe Gerum's avatar
Philippe Gerum committed
83
84
{
	/*
85
86
	 * The round-robin time credit is only consumed by a running
	 * thread that neither holds the scheduler lock nor was
87
88
	 * blocked before entering this callback. As the time slice is
	 * exhausted for the running thread, move it back to the
89
	 * run queue at the end of its priority group.
Philippe Gerum's avatar
Philippe Gerum committed
90
	 */
91
	xnsched_putback(sched->curr);
Philippe Gerum's avatar
Philippe Gerum committed
92
93
}

94
95
static bool xnsched_rt_setparam(struct xnthread *thread,
				const union xnsched_policy_param *p)
96
{
97
	return __xnsched_rt_setparam(thread, p);
98
99
}

100
101
static void xnsched_rt_getparam(struct xnthread *thread,
				union xnsched_policy_param *p)
102
103
104
105
{
	__xnsched_rt_getparam(thread, p);
}

106
107
static void xnsched_rt_trackprio(struct xnthread *thread,
				 const union xnsched_policy_param *p)
108
109
110
111
{
	__xnsched_rt_trackprio(thread, p);
}

112
static void xnsched_rt_protectprio(struct xnthread *thread, int prio)
113
114
115
116
{
	__xnsched_rt_protectprio(thread, prio);
}

117
#ifdef CONFIG_XENO_OPT_VFILE
118

119
120
121
struct xnvfile_directory sched_rt_vfroot;

struct vfile_sched_rt_priv {
122
	struct xnthread *curr;
123
124
125
126
127
128
129
130
};

struct vfile_sched_rt_data {
	int cpu;
	pid_t pid;
	char name[XNOBJECT_NAME_LEN];
	xnticks_t period;
	int cprio;
131
132
};

133
134
135
136
137
static struct xnvfile_snapshot_ops vfile_sched_rt_ops;

static struct xnvfile_snapshot vfile_sched_rt = {
	.privsz = sizeof(struct vfile_sched_rt_priv),
	.datasz = sizeof(struct vfile_sched_rt_data),
138
	.tag = &nkthreadlist_tag,
139
140
141
142
	.ops = &vfile_sched_rt_ops,
};

static int vfile_sched_rt_rewind(struct xnvfile_snapshot_iterator *it)
143
{
144
145
	struct vfile_sched_rt_priv *priv = xnvfile_iterator_priv(it);
	int nrthreads = xnsched_class_rt.nthreads;
146

147
148
	if (nrthreads == 0)
		return -ESRCH;
149

150
	priv->curr = list_first_entry(&nkthreadq, struct xnthread, glink);
151

152
	return nrthreads;
153
154
}

155
156
static int vfile_sched_rt_next(struct xnvfile_snapshot_iterator *it,
			       void *data)
157
{
158
159
160
	struct vfile_sched_rt_priv *priv = xnvfile_iterator_priv(it);
	struct vfile_sched_rt_data *p = data;
	struct xnthread *thread;
161

162
163
	if (priv->curr == NULL)
		return 0;	/* All done. */
164

165
	thread = priv->curr;
166
	if (list_is_last(&thread->glink, &nkthreadq))
167
168
169
		priv->curr = NULL;
	else
		priv->curr = list_next_entry(thread, glink);
170

171
172
	if (thread->base_class != &xnsched_class_rt ||
	    xnthread_test_state(thread, XNWEAK))
173
		return VFILE_SEQ_SKIP;
174

175
	p->cpu = xnsched_cpu(thread->sched);
176
	p->pid = xnthread_host_pid(thread);
177
178
179
180
181
	memcpy(p->name, thread->name, sizeof(p->name));
	p->cprio = thread->cprio;
	p->period = xnthread_get_period(thread);

	return 1;
182
183
}

184
185
static int vfile_sched_rt_show(struct xnvfile_snapshot_iterator *it,
			       void *data)
186
{
187
	struct vfile_sched_rt_data *p = data;
188
189
	char pribuf[16], ptbuf[16];

190
191
192
	if (p == NULL)
		xnvfile_printf(it, "%-3s  %-6s %-8s %-10s %s\n",
			       "CPU", "PID", "PRI", "PERIOD", "NAME");
193
	else {
194
		ksformat(pribuf, sizeof(pribuf), "%3d", p->cprio);
195
		xntimer_format_time(p->period, ptbuf, sizeof(ptbuf));
196
197
198
199
200
201
		xnvfile_printf(it, "%3u  %-6d %-8s %-10s %s\n",
			       p->cpu,
			       p->pid,
			       pribuf,
			       ptbuf,
			       p->name);
202
203
204
205
206
	}

	return 0;
}

207
208
209
210
static struct xnvfile_snapshot_ops vfile_sched_rt_ops = {
	.rewind = vfile_sched_rt_rewind,
	.next = vfile_sched_rt_next,
	.show = vfile_sched_rt_show,
211
212
};

213
214
static int xnsched_rt_init_vfile(struct xnsched_class *schedclass,
				 struct xnvfile_directory *vfroot)
215
{
216
	int ret;
217

218
219
	ret = xnvfile_init_dir(schedclass->name, &sched_rt_vfroot, vfroot);
	if (ret)
220
221
		return ret;

222
223
	return xnvfile_init_snapshot("threads", &vfile_sched_rt,
				     &sched_rt_vfroot);
224
225
}

226
static void xnsched_rt_cleanup_vfile(struct xnsched_class *schedclass)
227
{
228
229
	xnvfile_destroy_snapshot(&vfile_sched_rt);
	xnvfile_destroy_dir(&sched_rt_vfroot);
230
231
}

232
#endif /* CONFIG_XENO_OPT_VFILE */
233

Philippe Gerum's avatar
Philippe Gerum committed
234
struct xnsched_class xnsched_class_rt = {
235
236
237
238
239
240
241
	.sched_init		=	xnsched_rt_init,
	.sched_enqueue		=	xnsched_rt_enqueue,
	.sched_dequeue		=	xnsched_rt_dequeue,
	.sched_requeue		=	xnsched_rt_requeue,
	.sched_pick		=	xnsched_rt_pick,
	.sched_tick		=	xnsched_rt_tick,
	.sched_rotate		=	xnsched_rt_rotate,
242
	.sched_forget		=	NULL,
243
	.sched_kick		=	NULL,
244
	.sched_declare		=	NULL,
245
246
	.sched_setparam		=	xnsched_rt_setparam,
	.sched_trackprio	=	xnsched_rt_trackprio,
247
	.sched_protectprio	=	xnsched_rt_protectprio,
248
	.sched_getparam		=	xnsched_rt_getparam,
249
#ifdef CONFIG_XENO_OPT_VFILE
250
251
	.sched_init_vfile	=	xnsched_rt_init_vfile,
	.sched_cleanup_vfile	=	xnsched_rt_cleanup_vfile,
Philippe Gerum's avatar
Philippe Gerum committed
252
#endif
253
	.weight			=	XNSCHED_CLASS_WEIGHT(4),
254
	.policy			=	SCHED_FIFO,
255
	.name			=	"rt"
Philippe Gerum's avatar
Philippe Gerum committed
256
};
257
EXPORT_SYMBOL_GPL(xnsched_class_rt);