1 /* This file contains the scheduling policy for SCHED
3 * The entry points are:
4 * do_noquantum: Called on behalf of process' that run out of quantum
5 * do_start_scheduling Request to start scheduling a proc
6 * do_stop_scheduling Request to stop scheduling a proc
7 * do_nice Request to change the nice level on a proc
8 * init_scheduling Called from main.c to set up/prepare scheduling
11 #include "schedproc.h"
13 #include <minix/com.h>
14 #include <machine/archtypes.h>
16 static unsigned balance_timeout
;
18 #define BALANCE_TIMEOUT 5 /* how often to balance queues in seconds */
20 static int schedule_process(struct schedproc
* rmp
, unsigned flags
);
22 #define SCHEDULE_CHANGE_PRIO 0x1
23 #define SCHEDULE_CHANGE_QUANTUM 0x2
24 #define SCHEDULE_CHANGE_CPU 0x4
26 #define SCHEDULE_CHANGE_ALL ( \
27 SCHEDULE_CHANGE_PRIO | \
28 SCHEDULE_CHANGE_QUANTUM | \
32 #define schedule_process_local(p) \
33 schedule_process(p, SCHEDULE_CHANGE_PRIO | SCHEDULE_CHANGE_QUANTUM)
34 #define schedule_process_migrate(p) \
35 schedule_process(p, SCHEDULE_CHANGE_CPU)
39 #define cpu_is_available(c) (cpu_proc[c] >= 0)
41 #define DEFAULT_USER_TIME_SLICE 200
43 /* processes created by RS are sysytem processes */
44 #define is_system_proc(p) ((p)->parent == RS_PROC_NR)
46 static unsigned cpu_proc
[CONFIG_MAX_CPUS
];
48 static void pick_cpu(struct schedproc
* proc
)
52 unsigned cpu_load
= (unsigned) -1;
54 if (machine
.processors_count
== 1) {
55 proc
->cpu
= machine
.bsp_id
;
59 /* schedule sysytem processes only on the boot cpu */
60 if (is_system_proc(proc
)) {
61 proc
->cpu
= machine
.bsp_id
;
65 /* if no other cpu available, try BSP */
67 for (c
= 0; c
< machine
.processors_count
; c
++) {
69 if (!cpu_is_available(c
))
71 if (c
!= machine
.bsp_id
&& cpu_load
> cpu_proc
[c
]) {
72 cpu_load
= cpu_proc
[c
];
83 /*===========================================================================*
85 *===========================================================================*/
87 int do_noquantum(message
*m_ptr
)
89 register struct schedproc
*rmp
;
92 if (sched_isokendpt(m_ptr
->m_source
, &proc_nr_n
) != OK
) {
93 printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",
98 rmp
= &schedproc
[proc_nr_n
];
99 if (rmp
->priority
< MIN_USER_Q
) {
100 rmp
->priority
+= 1; /* lower priority */
103 if ((rv
= schedule_process_local(rmp
)) != OK
) {
109 /*===========================================================================*
110 * do_stop_scheduling *
111 *===========================================================================*/
112 int do_stop_scheduling(message
*m_ptr
)
114 register struct schedproc
*rmp
;
117 /* check who can send you requests */
118 if (!accept_message(m_ptr
))
121 if (sched_isokendpt(m_ptr
->m_lsys_sched_scheduling_stop
.endpoint
,
123 printf("SCHED: WARNING: got an invalid endpoint in OOQ msg "
124 "%d\n", m_ptr
->m_lsys_sched_scheduling_stop
.endpoint
);
128 rmp
= &schedproc
[proc_nr_n
];
130 cpu_proc
[rmp
->cpu
]--;
132 rmp
->flags
= 0; /*&= ~IN_USE;*/
137 /*===========================================================================*
138 * do_start_scheduling *
139 *===========================================================================*/
140 int do_start_scheduling(message
*m_ptr
)
142 register struct schedproc
*rmp
;
143 int rv
, proc_nr_n
, parent_nr_n
;
145 /* we can handle two kinds of messages here */
146 assert(m_ptr
->m_type
== SCHEDULING_START
||
147 m_ptr
->m_type
== SCHEDULING_INHERIT
);
149 /* check who can send you requests */
150 if (!accept_message(m_ptr
))
153 /* Resolve endpoint to proc slot. */
154 if ((rv
= sched_isemtyendpt(m_ptr
->m_lsys_sched_scheduling_start
.endpoint
,
155 &proc_nr_n
)) != OK
) {
158 rmp
= &schedproc
[proc_nr_n
];
160 /* Populate process slot */
161 rmp
->endpoint
= m_ptr
->m_lsys_sched_scheduling_start
.endpoint
;
162 rmp
->parent
= m_ptr
->m_lsys_sched_scheduling_start
.parent
;
163 rmp
->max_priority
= m_ptr
->m_lsys_sched_scheduling_start
.maxprio
;
164 if (rmp
->max_priority
>= NR_SCHED_QUEUES
) {
168 /* Inherit current priority and time slice from parent. Since there
169 * is currently only one scheduler scheduling the whole system, this
170 * value is local and we assert that the parent endpoint is valid */
171 if (rmp
->endpoint
== rmp
->parent
) {
172 /* We have a special case here for init, which is the first
173 process scheduled, and the parent of itself. */
174 rmp
->priority
= USER_Q
;
175 rmp
->time_slice
= DEFAULT_USER_TIME_SLICE
;
178 * Since kernel never changes the cpu of a process, all are
179 * started on the BSP and the userspace scheduling hasn't
180 * changed that yet either, we can be sure that BSP is the
181 * processor where the processes run now.
184 rmp
->cpu
= machine
.bsp_id
;
185 /* FIXME set the cpu mask */
189 switch (m_ptr
->m_type
) {
191 case SCHEDULING_START
:
192 /* We have a special case here for system processes, for which
193 * quanum and priority are set explicitly rather than inherited
195 rmp
->priority
= rmp
->max_priority
;
196 rmp
->time_slice
= m_ptr
->m_lsys_sched_scheduling_start
.quantum
;
199 case SCHEDULING_INHERIT
:
200 /* Inherit current priority and time slice from parent. Since there
201 * is currently only one scheduler scheduling the whole system, this
202 * value is local and we assert that the parent endpoint is valid */
203 if ((rv
= sched_isokendpt(m_ptr
->m_lsys_sched_scheduling_start
.parent
,
204 &parent_nr_n
)) != OK
)
207 rmp
->priority
= schedproc
[parent_nr_n
].priority
;
208 rmp
->time_slice
= schedproc
[parent_nr_n
].time_slice
;
216 /* Take over scheduling the process. The kernel reply message populates
217 * the processes current priority and its time slice */
218 if ((rv
= sys_schedctl(0, rmp
->endpoint
, 0, 0, 0)) != OK
) {
219 printf("Sched: Error taking over scheduling for %d, kernel said %d\n",
225 /* Schedule the process, giving it some quantum */
227 while ((rv
= schedule_process(rmp
, SCHEDULE_CHANGE_ALL
)) == EBADCPU
) {
228 /* don't try this CPU ever again */
229 cpu_proc
[rmp
->cpu
] = CPU_DEAD
;
234 printf("Sched: Error while scheduling process, kernel replied %d\n",
239 /* Mark ourselves as the new scheduler.
240 * By default, processes are scheduled by the parents scheduler. In case
241 * this scheduler would want to delegate scheduling to another
242 * scheduler, it could do so and then write the endpoint of that
243 * scheduler into the "scheduler" field.
246 m_ptr
->m_sched_lsys_scheduling_start
.scheduler
= SCHED_PROC_NR
;
251 /*===========================================================================*
253 *===========================================================================*/
254 int do_nice(message
*m_ptr
)
256 struct schedproc
*rmp
;
259 unsigned new_q
, old_q
, old_max_q
;
261 /* check who can send you requests */
262 if (!accept_message(m_ptr
))
265 if (sched_isokendpt(m_ptr
->m_pm_sched_scheduling_set_nice
.endpoint
, &proc_nr_n
) != OK
) {
266 printf("SCHED: WARNING: got an invalid endpoint in OoQ msg "
267 "%d\n", m_ptr
->m_pm_sched_scheduling_set_nice
.endpoint
);
271 rmp
= &schedproc
[proc_nr_n
];
272 new_q
= m_ptr
->m_pm_sched_scheduling_set_nice
.maxprio
;
273 if (new_q
>= NR_SCHED_QUEUES
) {
277 /* Store old values, in case we need to roll back the changes */
278 old_q
= rmp
->priority
;
279 old_max_q
= rmp
->max_priority
;
281 /* Update the proc entry and reschedule the process */
282 rmp
->max_priority
= rmp
->priority
= new_q
;
284 if ((rv
= schedule_process_local(rmp
)) != OK
) {
285 /* Something went wrong when rescheduling the process, roll
286 * back the changes to proc struct */
287 rmp
->priority
= old_q
;
288 rmp
->max_priority
= old_max_q
;
294 /*===========================================================================*
296 *===========================================================================*/
297 static int schedule_process(struct schedproc
* rmp
, unsigned flags
)
300 int new_prio
, new_quantum
, new_cpu
, niced
;
304 if (flags
& SCHEDULE_CHANGE_PRIO
)
305 new_prio
= rmp
->priority
;
309 if (flags
& SCHEDULE_CHANGE_QUANTUM
)
310 new_quantum
= rmp
->time_slice
;
314 if (flags
& SCHEDULE_CHANGE_CPU
)
319 niced
= (rmp
->max_priority
> USER_Q
);
321 if ((err
= sys_schedule(rmp
->endpoint
, new_prio
,
322 new_quantum
, new_cpu
, niced
)) != OK
) {
323 printf("PM: An error occurred when trying to schedule %d: %d\n",
331 /*===========================================================================*
333 *===========================================================================*/
334 void init_scheduling(void)
338 balance_timeout
= BALANCE_TIMEOUT
* sys_hz();
340 if ((r
= sys_setalarm(balance_timeout
, 0)) != OK
)
341 panic("sys_setalarm failed: %d", r
);
344 /*===========================================================================*
346 *===========================================================================*/
348 /* This function in called every N ticks to rebalance the queues. The current
349 * scheduler bumps processes down one priority when ever they run out of
350 * quantum. This function will find all proccesses that have been bumped down,
351 * and pulls them back up. This default policy will soon be changed.
353 void balance_queues(void)
355 struct schedproc
*rmp
;
358 for (proc_nr
=0, rmp
=schedproc
; proc_nr
< NR_PROCS
; proc_nr
++, rmp
++) {
359 if (rmp
->flags
& IN_USE
) {
360 if (rmp
->priority
> rmp
->max_priority
) {
361 rmp
->priority
-= 1; /* increase priority */
362 schedule_process_local(rmp
);
367 if ((r
= sys_setalarm(balance_timeout
, 0)) != OK
)
368 panic("sys_setalarm failed: %d", r
);