This repository was archived by the owner on Sep 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathschedproc.cpp
More file actions
379 lines (307 loc) · 9.2 KB
/
Copy pathschedproc.cpp
File metadata and controls
379 lines (307 loc) · 9.2 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#include "sched.h"
#include "schedproc.h"
#include <assert.h>
#include <minix/com.h>
#include <timers.h>
#include <machine/archtypes.h>
#include <sys/resource.h> /* for PRIO_MAX & PRIO_MIN */
#include "kernel/proc.h" /* for queue constants */
#define SCHEDULE_CHANGE_PRIO 0x1
#define SCHEDULE_CHANGE_QUANTUM 0x2
#define SCHEDULE_CHANGE_CPU 0x4
#define SCHEDULE_CHANGE_ALL ( \
SCHEDULE_CHANGE_PRIO | \
SCHEDULE_CHANGE_QUANTUM | \
SCHEDULE_CHANGE_CPU \
)
#define CPU_DEAD -1
#define DEFAULT_USER_TIME_SLICE 200
#define INC_PER_QUEUE 10
unsigned cpu_proc[CONFIG_MAX_CPUS];
#define cpu_is_available(c) (cpu_proc[c] >= 0)
#define is_system_proc(p) ((p)->parent == RS_PROC_NR)
extern "C" int call_minix_sys_schedule(endpoint_t proc_ep, int priority, int quantum, int cpu);
extern "C" int call_minix_sys_schedctl(unsigned flags, endpoint_t proc_ep, int priority, int quantum, int cpu);
extern "C" int accept_message(message *m_ptr);
extern "C" int no_sys(int who_e, int call_nr);
int sched_isokendpt(int endpoint, int *proc);
int sched_isemptyendpt(int endpoint, int *proc);
void Schedproc::pick_cpu()
{
#ifdef CONFIG_SMP
unsigned cpu, c;
unsigned cpu_load = (unsigned) -1;
if (machine.processors_count == 1) {
this->cpu = machine.bsp_id;
return;
}
if (is_system_proc(this)) {
this->cpu = machine.bsp_id;
return;
}
cpu = machine.bsp_id;
for (c = 0; c < machine.processors_count; c++) {
if (!cpu_is_available(c))
continue;
if (c != machine.bsp_id && cpu_load > cpu_proc[c]) {
cpu_load = cpu_proc[c];
cpu = c;
}
}
this->cpu = cpu;
cpu_proc[cpu]++;
#else
this->cpu = 0;
#endif
}
extern "C" int do_noquantum(message *m_ptr)
{
Schedproc *rmp;
int rv, proc_nr_n;
unsigned ipc, burst, queue_bump;
short load;
if (sched_isokendpt(m_ptr->m_source, &proc_nr_n) != OK) {
printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",m_ptr->m_source);
return EBADEPT;
}
rmp = &schedproc[proc_nr_n];
ipc = (unsigned)m_ptr->SCHEDULING_ACNT_IPC_ASYNC + (unsigned)m_ptr->SCHEDULING_ACNT_IPC_SYNC + 1;
load = m_ptr->SCHEDULING_ACNT_CPU_LOAD;
burst = (rmp->time_slice * 1000 / ipc) / 100;
burst = rmp->burst_smooth(burst);
queue_bump = burst/INC_PER_QUEUE;
if (rmp->max_priority + queue_bump > MIN_USER_Q) {
queue_bump = MIN_USER_Q - rmp->max_priority;
}
rmp->priority = rmp->max_priority + queue_bump;
rmp->time_slice = rmp->base_time_slice + 2 * queue_bump * (rmp->base_time_slice/10);
if ((rv = rmp->schedule_process(SCHEDULE_CHANGE_PRIO | SCHEDULE_CHANGE_QUANTUM)) != OK) {
return rv;
}
return OK;
}
int Schedproc::burst_smooth(unsigned burst)
{
int i;
unsigned avg_burst = 0;
this->burst_history[this->burst_hist_cnt++ %
BURST_HISTORY_LENGTH] = burst;
for (i=0; i<BURST_HISTORY_LENGTH; i++)
{
if (i >= this->burst_hist_cnt) {
break;
}
avg_burst += this->burst_history[i];
}
avg_burst /= i;
return avg_burst;
}
extern "C" int do_stop_scheduling(message *m_ptr)
{
Schedproc *rmp;
int proc_nr_n;
/* check who can send you requests */
if (!accept_message(m_ptr))
return EPERM;
if (sched_isokendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n) != OK) {
printf("SCHED: WARNING: got an invalid endpoint in OOQ msg "
"%ld\n", m_ptr->SCHEDULING_ENDPOINT);
return EBADEPT;
}
rmp = &schedproc[proc_nr_n];
#ifdef CONFIG_SMP
cpu_proc[rmp->cpu]--;
#endif
rmp->flags = 0; /*&= ~IN_USE;*/
return OK;
}
int sched_isokendpt(int endpoint, int *proc)
{
*proc = _ENDPOINT_P(endpoint);
if (*proc < 0)
return (EBADEPT); /* Don't schedule tasks */
if(*proc >= NR_PROCS)
return (EINVAL);
if(endpoint != schedproc[*proc].endpoint)
return (EDEADEPT);
if(!(schedproc[*proc].flags & IN_USE))
return (EDEADEPT);
return (OK);
}
int sched_isemtyendpt(int endpoint, int *proc)
{
*proc = _ENDPOINT_P(endpoint);
if (*proc < 0)
return (EBADEPT); /* Don't schedule tasks */
if(*proc >= NR_PROCS)
return (EINVAL);
if(schedproc[*proc].flags & IN_USE)
return (EDEADEPT);
return (OK);
}
extern "C" int do_nice(message *m_ptr)
{
Schedproc *rmp;
int rv;
int proc_nr_n;
unsigned new_q, old_q, old_max_q;
/* check who can send you requests */
if (accept_message(m_ptr))
return EPERM;
if (sched_isokendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n) != OK) {
printf("SCHED: WARNING: got an invalid endpoint in OOQ msg ""%ld\n", m_ptr->SCHEDULING_ENDPOINT);
return EBADEPT;
}
rmp = &schedproc[proc_nr_n];
new_q = (unsigned) m_ptr->SCHEDULING_MAXPRIO;
if (new_q >= NR_SCHED_QUEUES) {
return EINVAL;
}
/* Store old values, in case we need to roll back the changes */
old_q = rmp->priority;
old_max_q = rmp->max_priority;
/* Update the proc entry and reschedule the process */
rmp->max_priority = rmp->priority = new_q;
if ((rv = rmp->schedule_process(SCHEDULE_CHANGE_PRIO | SCHEDULE_CHANGE_QUANTUM)) != OK)
{
rmp->priority = old_q;
rmp->max_priority = old_max_q;
}
return rv;
}
int Schedproc::schedule_process(unsigned flags)
{
int err;
int new_prio, new_quantum, new_cpu;
this->pick_cpu();
if (flags & SCHEDULE_CHANGE_PRIO)
new_prio = this->priority;
else
new_prio = -1;
if (flags & SCHEDULE_CHANGE_QUANTUM)
new_quantum = this->time_slice;
else
new_quantum = -1;
if (flags & SCHEDULE_CHANGE_CPU)
new_cpu = this->cpu;
else
new_cpu = -1;
if ((err = call_minix_sys_schedule(this->endpoint, new_prio,
new_quantum, new_cpu)) != OK) {
printf("PM: An error occurred when trying to schedule %d: %d\n",this->endpoint, err);
}
return err;
}
extern "C" int do_start_scheduling(message *m_ptr)
{
Schedproc *rmp;
int rv, proc_nr_n, parent_nr_n;
/* we can handle two kinds of messages here */
assert(m_ptr->m_type == SCHEDULING_START ||
m_ptr->m_type == SCHEDULING_INHERIT);
/* check who can send you requests */
if (!accept_message(m_ptr))
return EPERM;
/* Resolve endpoint to proc slot. */
if ((rv = sched_isemtyendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n))
!= OK) {
return rv;
}
rmp = &schedproc[proc_nr_n];
/* Populate process slot */
rmp->endpoint = m_ptr->SCHEDULING_ENDPOINT;
rmp->parent = m_ptr->SCHEDULING_PARENT;
rmp->max_priority = (unsigned) m_ptr->SCHEDULING_MAXPRIO;
rmp->burst_hist_cnt = 0;
if (rmp->max_priority >= NR_SCHED_QUEUES) {
return EINVAL;
}
/* Inherit current priority and time slice from parent. Since there
* is currently only one scheduler scheduling the whole system, this
* value is local and we assert that the parent endpoint is valid */
if (rmp->endpoint == rmp->parent) {
/* We have a special case here for init, which is the first
process scheduled, and the parent of itself. */
rmp->priority = USER_Q;
rmp->time_slice = DEFAULT_USER_TIME_SLICE;
/*
* Since kernel never changes the cpu of a process, all are
* started on the BSP and the userspace scheduling hasn't
* changed that yet either, we can be sure that BSP is the
* processor where the processes run now.
*/
#ifdef CONFIG_SMP
rmp->cpu = machine.bsp_id;
/* FIXME set the cpu mask */
#endif
}
switch (m_ptr->m_type) {
case SCHEDULING_START:
/* We have a special case here for system processes, for which
* quanum and priority are set explicitly rather than inherited
* from the parent */
rmp->priority = rmp->max_priority;
rmp->time_slice = (unsigned) m_ptr->SCHEDULING_QUANTUM;
rmp->base_time_slice = rmp->time_slice;
break;
case SCHEDULING_INHERIT:
/* Inherit current priority and time slice from parent. Since there
* is currently only one scheduler scheduling the whole system, this
* value is local and we assert that the parent endpoint is valid */
if ((rv = sched_isokendpt(m_ptr->SCHEDULING_PARENT,
&parent_nr_n)) != OK)
return rv;
rmp->priority = schedproc[parent_nr_n].priority;
rmp->time_slice = schedproc[parent_nr_n].time_slice;
rmp->base_time_slice = rmp->time_slice;
break;
default:
/* not reachable */
assert(0);
}
/* Take over scheduling the process. The kernel reply message populates
* the processes current priority and its time slice */
if ((rv = call_minix_sys_schedctl(0, rmp->endpoint, 0, 0, 0)) != OK) {
printf("Sched: Error taking over scheduling for %d, kernel said %d\n",
rmp->endpoint, rv);
return rv;
}
rmp->flags = IN_USE;
/* Schedule the process, giving it some quantum */
rmp->pick_cpu();
while ((rv = rmp->schedule_process(SCHEDULE_CHANGE_ALL)) == EBADCPU) {
/* don't try this CPU ever again */
cpu_proc[rmp->cpu] = CPU_DEAD;
rmp->pick_cpu();
}
if (rv != OK) {
printf("Sched: Error while scheduling process, kernel replied %d\n",
rv);
return rv;
}
/* Mark ourselves as the new scheduler.
* By default, processes are scheduled by the parents scheduler. In case
* this scheduler would want to delegate scheduling to another
* scheduler, it could do so and then write the endpoint of that
* scheduler into SCHEDULING_SCHEDULER
*/
m_ptr->SCHEDULING_SCHEDULER = SCHED_PROC_NR;
return OK;
}
extern "C" int no_sys(int who_e, int call_nr)
{
/* A system call number not implemented by PM has been requested. */
printf("SCHED: in no_sys, call nr %d from %d\n", call_nr, who_e);
return(ENOSYS);
}
extern "C" int accept_message(message *m_ptr)
{
/* accept all messages from PM and RS */
switch (m_ptr->m_source) {
case PM_PROC_NR:
case RS_PROC_NR:
return 1;
}
/* no other messages are allowable */
return 0;
}