This repository has been archived by the owner on Nov 8, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
schedos-kern.c
264 lines (215 loc) · 7.37 KB
/
schedos-kern.c
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
#include "schedos-app.h"
#include "schedos-kern.h"
#include "x86.h"
#include "lib.h"
/*****************************************************************************
* schedos-kern
*
* This is the schedos's kernel.
* It sets up process descriptors for the 4 applications, then runs
* them in some schedule.
*
*****************************************************************************/
// The program loader loads 4 processes, starting at PROC1_START, allocating
// 1 MB to each process.
// Each process's stack grows down from the top of its memory space.
// (But note that SchedOS processes, like MiniprocOS processes, are not fully
// isolated: any process could modify any part of memory.)
#define NPROCS 5
#define PROC1_START 0x200000
#define PROC_SIZE 0x100000
// +---------+-----------------------+--------+---------------------+---------/
// | Base | Kernel Kernel | Shared | App 0 App 0 | App 1
// | Memory | Code + Data Stack | Data | Code + Data Stack | Code ...
// +---------+-----------------------+--------+---------------------+---------/
// 0x0 0x100000 0x198000 0x200000 0x300000
//
// The program loader puts each application's starting instruction pointer
// at the very top of its stack.
//
// System-wide global variables shared among the kernel and the four
// applications are stored in memory from 0x198000 to 0x200000. Currently
// there is just one variable there, 'cursorpos', which occupies the four
// bytes of memory 0x198000-0x198003. You can add more variables by defining
// their addresses in schedos-symbols.ld; make sure they do not overlap!
// A process descriptor for each process.
// Note that proc_array[0] is never used.
// The first application process descriptor is proc_array[1].
static process_t proc_array[NPROCS];
// A pointer to the currently running process.
// This is kept up to date by the run() function, in mpos-x86.c.
process_t *current;
// The preferred scheduling algorithm.
int scheduling_algorithm;
/*****************************************************************************
* start
*
* Initialize the hardware and process descriptors, then run
* the first process.
*
*****************************************************************************/
void
start(void)
{
int i;
// Set up hardware (schedos-x86.c)
segments_init();
interrupt_controller_init(1);
console_clear();
// Initialize process descriptors as empty
memset(proc_array, 0, sizeof(proc_array));
for (i = 0; i < NPROCS; i++) {
proc_array[i].p_pid = i;
proc_array[i].p_state = P_EMPTY;
}
// Set up process descriptors (the proc_array[])
for (i = 1; i < NPROCS; i++) {
process_t *proc = &proc_array[i];
uint32_t stack_ptr = PROC1_START + i * PROC_SIZE;
// Initialize proportional scheduling vars
proc->p_share = 1;
proc->p_run_t = 0;
// Initialize the process descriptor
special_registers_init(proc);
// Set ESP
proc->p_registers.reg_esp = stack_ptr;
// Load process and set EIP, based on ELF image
program_loader(i - 1, &proc->p_registers.reg_eip);
// Mark the process as runnable!
proc->p_state = P_RUNNABLE;
}
// Initialize the cursor-position shared variable to point to the
// console's first character (the upper left).
cursorpos = (uint16_t *) 0xB8000;
// Initialize the scheduling algorithm.
scheduling_algorithm = 0;
// Switch to the first process.
run(&proc_array[1]);
// Should never get here!
while (1)
/* do nothing */;
}
/*****************************************************************************
* interrupt
*
* This is the weensy interrupt and system call handler.
* The current handler handles 4 different system calls (two of which
* do nothing), plus the clock interrupt.
*
* Note that we will never receive clock interrupts while in the kernel.
*
*****************************************************************************/
void
interrupt(registers_t *reg)
{
// Save the current process's register state
// into its process descriptor
current->p_registers = *reg;
switch (reg->reg_intno) {
case INT_SYS_YIELD:
// The 'sys_yield' system call asks the kernel to schedule
// the next process.
schedule();
case INT_SYS_EXIT:
// 'sys_exit' exits the current process: it is marked as
// non-runnable.
// The application stored its exit status in the %eax register
// before calling the system call. The %eax register has
// changed by now, but we can read the application's value
// out of the 'reg' argument.
// (This shows you how to transfer arguments to system calls!)
current->p_state = P_ZOMBIE;
current->p_exit_status = reg->reg_eax;
schedule();
case INT_SYS_SETPRIORITY:
current->p_priority = reg->reg_eax;
run(current);
case INT_SYS_SETSHARE:
current->p_share = reg->reg_eax;
run(current);
case INT_SYS_PRINT:
*cursorpos++ = reg->reg_eax;
run(current);
case INT_CLOCK:
// A clock interrupt occurred (so an application exhausted its
// time quantum).
// Switch to the next runnable process.
schedule();
default:
while (1)
/* do nothing */;
}
}
/*****************************************************************************
* schedule
*
* This is the weensy process scheduler.
* It picks a runnable process, then context-switches to that process.
* If there are no runnable processes, it spins forever.
*
* This function implements multiple scheduling algorithms, depending on
* the value of 'scheduling_algorithm'. We've provided one; in the problem
* set you will provide at least one more.
*
*****************************************************************************/
void
schedule(void)
{
pid_t pid = current->p_pid;
unsigned int lowest = 0xffffffff; // initialized to INTMAX
switch (scheduling_algorithm) {
case 0: // round-robin scheduling
while (1) {
pid = (pid + 1) % NPROCS;
// Run the selected process, but skip
// non-runnable processes.
// Note that the 'run' function does not return.
if (proc_array[pid].p_state == P_RUNNABLE)
run(&proc_array[pid]);
}
break;
case 1: // pid-priority scheduling
while (1) {
// run highest-priority, runnable process
for (pid = 0; pid < NPROCS; pid++)
if (proc_array[pid].p_state == P_RUNNABLE)
run(&proc_array[pid]);
}
break;
case 2: // set-priority scheduling
while (1) {
// get highest-priority number
pid_t i;
for (i = 0; i < NPROCS; i++)
if (proc_array[i].p_state == P_RUNNABLE &&
proc_array[i].p_priority < lowest)
lowest = proc_array[i].p_priority;
// search first highest-priority task
pid = (pid + 1) % NPROCS; // to alternate, start with next proc
if (proc_array[pid].p_state == P_RUNNABLE &&
proc_array[pid].p_priority <= lowest)
run(&proc_array[pid]);
}
break;
case 3: // proportional-share scheduling
while (1) {
if (proc_array[pid].p_state == P_RUNNABLE) {
// skip if run more than share
if (proc_array[pid].p_run_t >= proc_array[pid].p_share) {
proc_array[pid].p_run_t = 0;
}
else {
proc_array[pid].p_run_t++;
run(&proc_array[pid]);
}
}
pid = (pid + 1) % NPROCS; // don't change procs until share up
}
break;
default: break;
};
// If we get here, we are running an unknown scheduling algorithm.
cursorpos = console_printf(cursorpos, 0x100, "\nUnknown scheduling algorithm %d\n", scheduling_algorithm);
while (1)
/* do nothing */;
}