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>
15 #include "kernel/proc.h" /* for queue constants */
17 static minix_timer_t sched_timer
;
18 static unsigned balance_timeout
;
20 #define BALANCE_TIMEOUT 5 /* how often to balance queues in seconds */
22 static int schedule_process(struct schedproc
* rmp
, unsigned flags
);
23 static void balance_queues(minix_timer_t
*tp
);
25 #define SCHEDULE_CHANGE_PRIO 0x1
26 #define SCHEDULE_CHANGE_QUANTUM 0x2
27 #define SCHEDULE_CHANGE_CPU 0x4
29 #define SCHEDULE_CHANGE_ALL ( \
30 SCHEDULE_CHANGE_PRIO | \
31 SCHEDULE_CHANGE_QUANTUM | \
35 #define schedule_process_local(p) \
36 schedule_process(p, SCHEDULE_CHANGE_PRIO | SCHEDULE_CHANGE_QUANTUM)
37 #define schedule_process_migrate(p) \
38 schedule_process(p, SCHEDULE_CHANGE_CPU)
42 #define cpu_is_available(c) (cpu_proc[c] >= 0)
44 #define DEFAULT_USER_TIME_SLICE 200
46 /* processes created by RS are sysytem processes */
47 #define is_system_proc(p) ((p)->parent == RS_PROC_NR)
49 static unsigned cpu_proc
[CONFIG_MAX_CPUS
];
51 static void pick_cpu(struct schedproc
* proc
)
55 unsigned cpu_load
= (unsigned) -1;
57 if (machine
.processors_count
== 1) {
58 proc
->cpu
= machine
.bsp_id
;
62 /* schedule sysytem processes only on the boot cpu */
63 if (is_system_proc(proc
)) {
64 proc
->cpu
= machine
.bsp_id
;
68 /* if no other cpu available, try BSP */
70 for (c
= 0; c
< machine
.processors_count
; c
++) {
72 if (!cpu_is_available(c
))
74 if (c
!= machine
.bsp_id
&& cpu_load
> cpu_proc
[c
]) {
75 cpu_load
= cpu_proc
[c
];
86 /*===========================================================================*
88 *===========================================================================*/
90 int do_noquantum(message
*m_ptr
)
92 register struct schedproc
*rmp
;
95 if (sched_isokendpt(m_ptr
->m_source
, &proc_nr_n
) != OK
) {
96 printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",
101 rmp
= &schedproc
[proc_nr_n
];
102 if (rmp
->priority
< MIN_USER_Q
) {
103 rmp
->priority
+= 1; /* lower priority */
106 if ((rv
= schedule_process_local(rmp
)) != OK
) {
112 /*===========================================================================*
113 * do_stop_scheduling *
114 *===========================================================================*/
115 int do_stop_scheduling(message
*m_ptr
)
117 register struct schedproc
*rmp
;
120 /* check who can send you requests */
121 if (!accept_message(m_ptr
))
124 if (sched_isokendpt(m_ptr
->m_lsys_sched_scheduling_stop
.endpoint
,
126 printf("SCHED: WARNING: got an invalid endpoint in OOQ msg "
127 "%d\n", m_ptr
->m_lsys_sched_scheduling_stop
.endpoint
);
131 rmp
= &schedproc
[proc_nr_n
];
133 cpu_proc
[rmp
->cpu
]--;
135 rmp
->flags
= 0; /*&= ~IN_USE;*/
140 /*===========================================================================*
141 * do_start_scheduling *
142 *===========================================================================*/
143 int do_start_scheduling(message
*m_ptr
)
145 register struct schedproc
*rmp
;
146 int rv
, proc_nr_n
, parent_nr_n
;
148 /* we can handle two kinds of messages here */
149 assert(m_ptr
->m_type
== SCHEDULING_START
||
150 m_ptr
->m_type
== SCHEDULING_INHERIT
);
152 /* check who can send you requests */
153 if (!accept_message(m_ptr
))
156 /* Resolve endpoint to proc slot. */
157 if ((rv
= sched_isemtyendpt(m_ptr
->m_lsys_sched_scheduling_start
.endpoint
,
158 &proc_nr_n
)) != OK
) {
161 rmp
= &schedproc
[proc_nr_n
];
163 /* Populate process slot */
164 rmp
->endpoint
= m_ptr
->m_lsys_sched_scheduling_start
.endpoint
;
165 rmp
->parent
= m_ptr
->m_lsys_sched_scheduling_start
.parent
;
166 rmp
->max_priority
= m_ptr
->m_lsys_sched_scheduling_start
.maxprio
;
167 if (rmp
->max_priority
>= NR_SCHED_QUEUES
) {
171 /* Inherit current priority and time slice from parent. Since there
172 * is currently only one scheduler scheduling the whole system, this
173 * value is local and we assert that the parent endpoint is valid */
174 if (rmp
->endpoint
== rmp
->parent
) {
175 /* We have a special case here for init, which is the first
176 process scheduled, and the parent of itself. */
177 rmp
->priority
= USER_Q
;
178 rmp
->time_slice
= DEFAULT_USER_TIME_SLICE
;
181 * Since kernel never changes the cpu of a process, all are
182 * started on the BSP and the userspace scheduling hasn't
183 * changed that yet either, we can be sure that BSP is the
184 * processor where the processes run now.
187 rmp
->cpu
= machine
.bsp_id
;
188 /* FIXME set the cpu mask */
192 switch (m_ptr
->m_type
) {
194 case SCHEDULING_START
:
195 /* We have a special case here for system processes, for which
196 * quanum and priority are set explicitly rather than inherited
198 rmp
->priority
= rmp
->max_priority
;
199 rmp
->time_slice
= m_ptr
->m_lsys_sched_scheduling_start
.quantum
;
202 case SCHEDULING_INHERIT
:
203 /* Inherit current priority and time slice from parent. Since there
204 * is currently only one scheduler scheduling the whole system, this
205 * value is local and we assert that the parent endpoint is valid */
206 if ((rv
= sched_isokendpt(m_ptr
->m_lsys_sched_scheduling_start
.parent
,
207 &parent_nr_n
)) != OK
)
210 rmp
->priority
= schedproc
[parent_nr_n
].priority
;
211 rmp
->time_slice
= schedproc
[parent_nr_n
].time_slice
;
219 /* Take over scheduling the process. The kernel reply message populates
220 * the processes current priority and its time slice */
221 if ((rv
= sys_schedctl(0, rmp
->endpoint
, 0, 0, 0)) != OK
) {
222 printf("Sched: Error taking over scheduling for %d, kernel said %d\n",
228 /* Schedule the process, giving it some quantum */
230 while ((rv
= schedule_process(rmp
, SCHEDULE_CHANGE_ALL
)) == EBADCPU
) {
231 /* don't try this CPU ever again */
232 cpu_proc
[rmp
->cpu
] = CPU_DEAD
;
237 printf("Sched: Error while scheduling process, kernel replied %d\n",
242 /* Mark ourselves as the new scheduler.
243 * By default, processes are scheduled by the parents scheduler. In case
244 * this scheduler would want to delegate scheduling to another
245 * scheduler, it could do so and then write the endpoint of that
246 * scheduler into the "scheduler" field.
249 m_ptr
->m_sched_lsys_scheduling_start
.scheduler
= SCHED_PROC_NR
;
254 /*===========================================================================*
256 *===========================================================================*/
257 int do_nice(message
*m_ptr
)
259 struct schedproc
*rmp
;
262 unsigned new_q
, old_q
, old_max_q
;
264 /* check who can send you requests */
265 if (!accept_message(m_ptr
))
268 if (sched_isokendpt(m_ptr
->m_pm_sched_scheduling_set_nice
.endpoint
, &proc_nr_n
) != OK
) {
269 printf("SCHED: WARNING: got an invalid endpoint in OoQ msg "
270 "%d\n", m_ptr
->m_pm_sched_scheduling_set_nice
.endpoint
);
274 rmp
= &schedproc
[proc_nr_n
];
275 new_q
= m_ptr
->m_pm_sched_scheduling_set_nice
.maxprio
;
276 if (new_q
>= NR_SCHED_QUEUES
) {
280 /* Store old values, in case we need to roll back the changes */
281 old_q
= rmp
->priority
;
282 old_max_q
= rmp
->max_priority
;
284 /* Update the proc entry and reschedule the process */
285 rmp
->max_priority
= rmp
->priority
= new_q
;
287 if ((rv
= schedule_process_local(rmp
)) != OK
) {
288 /* Something went wrong when rescheduling the process, roll
289 * back the changes to proc struct */
290 rmp
->priority
= old_q
;
291 rmp
->max_priority
= old_max_q
;
297 /*===========================================================================*
299 *===========================================================================*/
300 static int schedule_process(struct schedproc
* rmp
, unsigned flags
)
303 int new_prio
, new_quantum
, new_cpu
;
307 if (flags
& SCHEDULE_CHANGE_PRIO
)
308 new_prio
= rmp
->priority
;
312 if (flags
& SCHEDULE_CHANGE_QUANTUM
)
313 new_quantum
= rmp
->time_slice
;
317 if (flags
& SCHEDULE_CHANGE_CPU
)
322 if ((err
= sys_schedule(rmp
->endpoint
, new_prio
,
323 new_quantum
, new_cpu
)) != OK
) {
324 printf("PM: An error occurred when trying to schedule %d: %d\n",
332 /*===========================================================================*
334 *===========================================================================*/
336 void init_scheduling(void)
338 balance_timeout
= BALANCE_TIMEOUT
* sys_hz();
339 init_timer(&sched_timer
);
340 set_timer(&sched_timer
, balance_timeout
, balance_queues
, 0);
343 /*===========================================================================*
345 *===========================================================================*/
347 /* This function in called every 100 ticks to rebalance the queues. The current
348 * scheduler bumps processes down one priority when ever they run out of
349 * quantum. This function will find all proccesses that have been bumped down,
350 * and pulls them back up. This default policy will soon be changed.
352 static void balance_queues(minix_timer_t
*tp
)
354 struct schedproc
*rmp
;
357 for (proc_nr
=0, rmp
=schedproc
; proc_nr
< NR_PROCS
; proc_nr
++, rmp
++) {
358 if (rmp
->flags
& IN_USE
) {
359 if (rmp
->priority
> rmp
->max_priority
) {
360 rmp
->priority
-= 1; /* increase priority */
361 schedule_process_local(rmp
);
366 set_timer(&sched_timer
, balance_timeout
, balance_queues
, 0);