/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- pinit
- allocproc
- userinit
- growproc
- fork
- exit
- wait
- scheduler
- sched
- yield
- forkret
- sleep
- wakeup1
- wakeup
- kill
- procdump
1 #include "types.h"
2 #include "defs.h"
3 #include "param.h"
4 #include "memlayout.h"
5 #include "mmu.h"
6 #include "x86.h"
7 #include "proc.h"
8 #include "spinlock.h"
9
10 struct {
11 struct spinlock lock;
12 struct proc proc[NPROC];
13 } ptable;
14
15 static struct proc *initproc;
16
17 int nextpid = 1;
18 extern void forkret(void);
19 extern void trapret(void);
20
21 static void wakeup1(void *chan);
22
23 void
24 pinit(void)
25 {
26 initlock(&ptable.lock, "ptable");
27 }
28
29 //PAGEBREAK: 32
30 // Look in the process table for an UNUSED proc.
31 // If found, change state to EMBRYO and initialize
32 // state required to run in the kernel.
33 // Otherwise return 0.
34 static struct proc*
35 allocproc(void)
36 {
37 struct proc *p;
38 char *sp;
39
40 acquire(&ptable.lock);
41 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
42 if(p->state == UNUSED)
43 goto found;
44 release(&ptable.lock);
45 return 0;
46
47 found:
48 p->state = EMBRYO;
49 p->pid = nextpid++;
50 release(&ptable.lock);
51
52 // Allocate kernel stack.
53 if((p->kstack = kalloc()) == 0){
54 p->state = UNUSED;
55 return 0;
56 }
57 sp = p->kstack + KSTACKSIZE;
58
59 // Leave room for trap frame.
60 sp -= sizeof *p->tf;
61 p->tf = (struct trapframe*)sp;
62
63 // Set up new context to start executing at forkret,
64 // which returns to trapret.
65 sp -= 4;
66 *(uint*)sp = (uint)trapret;
67
68 sp -= sizeof *p->context;
69 p->context = (struct context*)sp;
70 memset(p->context, 0, sizeof *p->context);
71 p->context->eip = (uint)forkret;
72
73 return p;
74 }
75
76 //PAGEBREAK: 32
77 // Set up first user process.
78 void
79 userinit(void)
80 {
81 struct proc *p;
82 extern char _binary_initcode_start[], _binary_initcode_size[];
83
84 p = allocproc();
85 initproc = p;
86 if((p->pgdir = setupkvm()) == 0)
87 panic("userinit: out of memory?");
88 inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
89 p->sz = PGSIZE;
90 memset(p->tf, 0, sizeof(*p->tf));
91 p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
92 p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
93 p->tf->es = p->tf->ds;
94 p->tf->ss = p->tf->ds;
95 p->tf->eflags = FL_IF;
96 p->tf->esp = PGSIZE;
97 p->tf->eip = 0; // beginning of initcode.S
98
99 safestrcpy(p->name, "initcode", sizeof(p->name));
100 p->cwd = namei("/");
101
102 p->state = RUNNABLE;
103 }
104
105 // Grow current process's memory by n bytes.
106 // Return 0 on success, -1 on failure.
107 int
108 growproc(int n)
109 {
110 uint sz;
111
112 sz = proc->sz;
113 if(n > 0){
114 if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0)
115 return -1;
116 } else if(n < 0){
117 if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0)
118 return -1;
119 }
120 proc->sz = sz;
121 switchuvm(proc);
122 return 0;
123 }
124
125 // Create a new process copying p as the parent.
126 // Sets up stack to return as if from system call.
127 // Caller must set state of returned proc to RUNNABLE.
128 int
129 fork(void)
130 {
131 int i, pid;
132 struct proc *np;
133
134 // Allocate process.
135 if((np = allocproc()) == 0)
136 return -1;
137
138 // Copy process state from p.
139 if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){
140 kfree(np->kstack);
141 np->kstack = 0;
142 np->state = UNUSED;
143 return -1;
144 }
145 np->sz = proc->sz;
146 np->parent = proc;
147 *np->tf = *proc->tf;
148
149 // Clear %eax so that fork returns 0 in the child.
150 np->tf->eax = 0;
151
152 for(i = 0; i < NOFILE; i++)
153 if(proc->ofile[i])
154 np->ofile[i] = filedup(proc->ofile[i]);
155 np->cwd = idup(proc->cwd);
156
157 safestrcpy(np->name, proc->name, sizeof(proc->name));
158
159 pid = np->pid;
160
161 // lock to force the compiler to emit the np->state write last.
162 acquire(&ptable.lock);
163 np->state = RUNNABLE;
164 release(&ptable.lock);
165
166 return pid;
167 }
168
169 // Exit the current process. Does not return.
170 // An exited process remains in the zombie state
171 // until its parent calls wait() to find out it exited.
172 void
173 exit(void)
174 {
175 struct proc *p;
176 int fd;
177
178 if(proc == initproc)
179 panic("init exiting");
180
181 // Close all open files.
182 for(fd = 0; fd < NOFILE; fd++){
183 if(proc->ofile[fd]){
184 fileclose(proc->ofile[fd]);
185 proc->ofile[fd] = 0;
186 }
187 }
188
189 begin_op();
190 iput(proc->cwd);
191 end_op();
192 proc->cwd = 0;
193
194 acquire(&ptable.lock);
195
196 // Parent might be sleeping in wait().
197 wakeup1(proc->parent);
198
199 // Pass abandoned children to init.
200 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
201 if(p->parent == proc){
202 p->parent = initproc;
203 if(p->state == ZOMBIE)
204 wakeup1(initproc);
205 }
206 }
207
208 // Jump into the scheduler, never to return.
209 proc->state = ZOMBIE;
210 sched();
211 panic("zombie exit");
212 }
213
214 // Wait for a child process to exit and return its pid.
215 // Return -1 if this process has no children.
216 int
217 wait(void)
218 {
219 struct proc *p;
220 int havekids, pid;
221
222 acquire(&ptable.lock);
223 for(;;){
224 // Scan through table looking for zombie children.
225 havekids = 0;
226 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
227 if(p->parent != proc)
228 continue;
229 havekids = 1;
230 if(p->state == ZOMBIE){
231 // Found one.
232 pid = p->pid;
233 kfree(p->kstack);
234 p->kstack = 0;
235 freevm(p->pgdir);
236 p->state = UNUSED;
237 p->pid = 0;
238 p->parent = 0;
239 p->name[0] = 0;
240 p->killed = 0;
241 release(&ptable.lock);
242 return pid;
243 }
244 }
245
246 // No point waiting if we don't have any children.
247 if(!havekids || proc->killed){
248 release(&ptable.lock);
249 return -1;
250 }
251
252 // Wait for children to exit. (See wakeup1 call in proc_exit.)
253 sleep(proc, &ptable.lock); //DOC: wait-sleep
254 }
255 }
256
257 //PAGEBREAK: 42
258 // Per-CPU process scheduler.
259 // Each CPU calls scheduler() after setting itself up.
260 // Scheduler never returns. It loops, doing:
261 // - choose a process to run
262 // - swtch to start running that process
263 // - eventually that process transfers control
264 // via swtch back to the scheduler.
265 void
266 scheduler(void)
267 {
268 struct proc *p;
269
270 for(;;){
271 // Enable interrupts on this processor.
272 sti();
273
274 // Loop over process table looking for process to run.
275 acquire(&ptable.lock);
276 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
277 if(p->state != RUNNABLE)
278 continue;
279
280 // Switch to chosen process. It is the process's job
281 // to release ptable.lock and then reacquire it
282 // before jumping back to us.
283 proc = p;
284 switchuvm(p);
285 p->state = RUNNING;
286 swtch(&cpu->scheduler, proc->context);
287 switchkvm();
288
289 // Process is done running for now.
290 // It should have changed its p->state before coming back.
291 proc = 0;
292 }
293 release(&ptable.lock);
294
295 }
296 }
297
298 // Enter scheduler. Must hold only ptable.lock
299 // and have changed proc->state.
300 void
301 sched(void)
302 {
303 int intena;
304
305 if(!holding(&ptable.lock))
306 panic("sched ptable.lock");
307 if(cpu->ncli != 1)
308 panic("sched locks");
309 if(proc->state == RUNNING)
310 panic("sched running");
311 if(readeflags()&FL_IF)
312 panic("sched interruptible");
313 intena = cpu->intena;
314 swtch(&proc->context, cpu->scheduler);
315 cpu->intena = intena;
316 }
317
318 // Give up the CPU for one scheduling round.
319 void
320 yield(void)
321 {
322 acquire(&ptable.lock); //DOC: yieldlock
323 proc->state = RUNNABLE;
324 sched();
325 release(&ptable.lock);
326 }
327
328 // A fork child's very first scheduling by scheduler()
329 // will swtch here. "Return" to user space.
330 void
331 forkret(void)
332 {
333 static int first = 1;
334 // Still holding ptable.lock from scheduler.
335 release(&ptable.lock);
336
337 if (first) {
338 // Some initialization functions must be run in the context
339 // of a regular process (e.g., they call sleep), and thus cannot
340 // be run from main().
341 first = 0;
342 iinit(ROOTDEV);
343 initlog(ROOTDEV);
344 }
345
346 // Return to "caller", actually trapret (see allocproc).
347 }
348
349 // Atomically release lock and sleep on chan.
350 // Reacquires lock when awakened.
351 void
352 sleep(void *chan, struct spinlock *lk)
353 {
354 if(proc == 0)
355 panic("sleep");
356
357 if(lk == 0)
358 panic("sleep without lk");
359
360 // Must acquire ptable.lock in order to
361 // change p->state and then call sched.
362 // Once we hold ptable.lock, we can be
363 // guaranteed that we won't miss any wakeup
364 // (wakeup runs with ptable.lock locked),
365 // so it's okay to release lk.
366 if(lk != &ptable.lock){ //DOC: sleeplock0
367 acquire(&ptable.lock); //DOC: sleeplock1
368 release(lk);
369 }
370
371 // Go to sleep.
372 proc->chan = chan;
373 proc->state = SLEEPING;
374 sched();
375
376 // Tidy up.
377 proc->chan = 0;
378
379 // Reacquire original lock.
380 if(lk != &ptable.lock){ //DOC: sleeplock2
381 release(&ptable.lock);
382 acquire(lk);
383 }
384 }
385
386 //PAGEBREAK!
387 // Wake up all processes sleeping on chan.
388 // The ptable lock must be held.
389 static void
390 wakeup1(void *chan)
391 {
392 struct proc *p;
393
394 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
395 if(p->state == SLEEPING && p->chan == chan)
396 p->state = RUNNABLE;
397 }
398
399 // Wake up all processes sleeping on chan.
400 void
401 wakeup(void *chan)
402 {
403 acquire(&ptable.lock);
404 wakeup1(chan);
405 release(&ptable.lock);
406 }
407
408 // Kill the process with the given pid.
409 // Process won't exit until it returns
410 // to user space (see trap in trap.c).
411 int
412 kill(int pid)
413 {
414 struct proc *p;
415
416 acquire(&ptable.lock);
417 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
418 if(p->pid == pid){
419 p->killed = 1;
420 // Wake process from sleep if necessary.
421 if(p->state == SLEEPING)
422 p->state = RUNNABLE;
423 release(&ptable.lock);
424 return 0;
425 }
426 }
427 release(&ptable.lock);
428 return -1;
429 }
430
431 //PAGEBREAK: 36
432 // Print a process listing to console. For debugging.
433 // Runs when user types ^P on console.
434 // No lock to avoid wedging a stuck machine further.
435 void
436 procdump(void)
437 {
438 static char *states[] = {
439 [UNUSED] "unused",
440 [EMBRYO] "embryo",
441 [SLEEPING] "sleep ",
442 [RUNNABLE] "runble",
443 [RUNNING] "run ",
444 [ZOMBIE] "zombie"
445 };
446 int i;
447 struct proc *p;
448 char *state;
449 uint pc[10];
450
451 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
452 if(p->state == UNUSED)
453 continue;
454 if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
455 state = states[p->state];
456 else
457 state = "???";
458 cprintf("%d %s %s", p->pid, state, p->name);
459 if(p->state == SLEEPING){
460 getcallerpcs((uint*)p->context->ebp+2, pc);
461 for(i=0; i<10 && pc[i] != 0; i++)
462 cprintf(" %p", pc[i]);
463 }
464 cprintf("\n");
465 }
466 }