comparison src/proc.cbc @ 52:214d21c891c7

rename to cbc __ncode is not handled as interfaces
author kono
date Mon, 03 Jun 2019 18:12:44 +0900
parents src/proc.c@fb3e5a2f76c1
children
comparison
equal deleted inserted replaced
51:fadfd62d6b14 52:214d21c891c7
1 #include "types.h"
2 #include "defs.h"
3 #include "param.h"
4 #include "memlayout.h"
5 #include "mmu.h"
6 #include "arm.h"
7 #include "proc.h"
8 #include "spinlock.h"
9
10 #define __ncode __code
11
12 //
13 // Process initialization:
14 // process initialize is somewhat tricky.
15 // 1. We need to fake the kernel stack of a new process as if the process
16 // has been interrupt (a trapframe on the stack), this would allow us
17 // to "return" to the correct user instruction.
18 // 2. We also need to fake the kernel execution for this new process. When
19 // swtch switches to this (new) process, it will switch to its stack,
20 // and reload registers with the saved context. We use forkret as the
21 // return address (in lr register). (In x86, it will be the return address
22 // pushed on the stack by the process.)
23 //
24 // The design of context switch in xv6 is interesting: after initialization,
25 // each CPU executes in the scheduler() function. The context switch is not
26 // between two processes, but instead, between the scheduler. Think of scheduler
27 // as the idle process.
28 //
29 struct {
30 struct spinlock lock;
31 struct proc proc[NPROC];
32 } ptable;
33
34 static struct proc *initproc;
35 struct proc *proc;
36
37 int nextpid = 1;
38 extern void forkret(void);
39 extern void trapret(void);
40
41 static void wakeup1(void *chan);
42
43 void pinit(void)
44 {
45 initlock(&ptable.lock, "ptable");
46 }
47
48 //PAGEBREAK: 32
49 // Look in the process table for an UNUSED proc.
50 // If found, change state to EMBRYO and initialize
51 // state required to run in the kernel.
52 // Otherwise return 0.
53 static struct proc* allocproc(void)
54 {
55 struct proc *p;
56 char *sp;
57
58 acquire(&ptable.lock);
59
60 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
61 if(p->state == UNUSED) {
62 goto found;
63 }
64
65 }
66
67 release(&ptable.lock);
68 return 0;
69
70 found:
71 p->state = EMBRYO;
72 p->pid = nextpid++;
73 release(&ptable.lock);
74
75 // Allocate kernel stack.
76 if((p->kstack = alloc_page ()) == 0){
77 p->state = UNUSED;
78 return 0;
79 }
80
81 sp = p->kstack + KSTACKSIZE;
82
83 // Leave room for trap frame.
84 sp -= sizeof (*p->tf);
85 p->tf = (struct trapframe*)sp;
86
87 // Set up new context to start executing at forkret,
88 // which returns to trapret.
89 sp -= 4;
90 *(uint*)sp = (uint)trapret;
91
92 sp -= 4;
93 *(uint*)sp = (uint)p->kstack + KSTACKSIZE;
94
95 sp -= sizeof (*p->context);
96 p->context = (struct context*)sp;
97 memset(p->context, 0, sizeof(*p->context));
98
99 // skip the push {fp, lr} instruction in the prologue of forkret.
100 // This is different from x86, in which the harderware pushes return
101 // address before executing the callee. In ARM, return address is
102 // loaded into the lr register, and push to the stack by the callee
103 // (if and when necessary). We need to skip that instruction and let
104 // it use our implementation.
105 p->context->lr = (uint)forkret+4;
106
107 return p;
108 }
109
110 void error_init ()
111 {
112 panic ("failed to craft first process\n");
113 }
114
115
116 //PAGEBREAK: 32
117 // hand-craft the first user process. We link initcode.S into the kernel
118 // as a binary, the linker will generate __binary_initcode_start/_size
119 void userinit(void)
120 {
121 struct proc *p;
122 extern char _binary_initcode_start[], _binary_initcode_size[];
123
124 p = allocproc();
125 initproc = p;
126
127 if((p->pgdir = kpt_alloc()) == NULL) {
128 panic("userinit: out of memory?");
129 }
130
131 inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
132
133 p->sz = PTE_SZ;
134
135 // craft the trapframe as if
136 memset(p->tf, 0, sizeof(*p->tf));
137
138 p->tf->r14_svc = (uint)error_init;
139 p->tf->spsr = spsr_usr ();
140 p->tf->sp_usr = PTE_SZ; // set the user stack
141 p->tf->lr_usr = 0;
142
143 // set the user pc. The actual pc loaded into r15_usr is in
144 // p->tf, the trapframe.
145 p->tf->pc = 0; // beginning of initcode.S
146
147 safestrcpy(p->name, "initcode", sizeof(p->name));
148 p->cwd = namei("/");
149
150 p->state = RUNNABLE;
151 }
152
153 // Grow current process's memory by n bytes.
154 // Return 0 on success, -1 on failure.
155 int growproc(int n)
156 {
157 uint sz;
158
159 sz = proc->sz;
160
161 if(n > 0){
162 if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0) {
163 return -1;
164 }
165
166 } else if(n < 0){
167 if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0) {
168 return -1;
169 }
170 }
171
172 proc->sz = sz;
173 switchuvm(proc);
174
175 return 0;
176 }
177
178 // Create a new process copying p as the parent.
179 // Sets up stack to return as if from system call.
180 // Caller must set state of returned proc to RUNNABLE.
181 int fork(void)
182 {
183 int i, pid;
184 struct proc *np;
185
186 // Allocate process.
187 if((np = allocproc()) == 0) {
188 return -1;
189 }
190
191 // Copy process state from p.
192 if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){
193 free_page(np->kstack);
194 np->kstack = 0;
195 np->state = UNUSED;
196 return -1;
197 }
198
199 np->sz = proc->sz;
200 np->parent = proc;
201 // *np->tf = *proc->tf; // This generate memcpy4 which is not in libgcc.a
202 memmove(np->tf, proc->tf, sizeof(*np->tf));
203
204 // Clear r0 so that fork returns 0 in the child.
205 np->tf->r0 = 0;
206
207 for(i = 0; i < NOFILE; i++) {
208 if(proc->ofile[i]) {
209 np->ofile[i] = filedup(proc->ofile[i]);
210 }
211 }
212
213 np->cwd = idup(proc->cwd);
214
215 pid = np->pid;
216 np->state = RUNNABLE;
217 safestrcpy(np->name, proc->name, sizeof(proc->name));
218
219 return pid;
220 }
221
222 // Exit the current process. Does not return.
223 // An exited process remains in the zombie state
224 // until its parent calls wait() to find out it exited.
225 void exit(void)
226 {
227 struct proc *p;
228 int fd;
229
230 if(proc == initproc) {
231 panic("init exiting");
232 }
233
234 // Close all open files.
235 for(fd = 0; fd < NOFILE; fd++){
236 if(proc->ofile[fd]){
237 fileclose(proc->ofile[fd]);
238 proc->ofile[fd] = 0;
239 }
240 }
241
242 iput(proc->cwd);
243 proc->cwd = 0;
244
245 acquire(&ptable.lock);
246
247 // Parent might be sleeping in wait().
248 wakeup1(proc->parent);
249
250 // Pass abandoned children to init.
251 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
252 if(p->parent == proc){
253 p->parent = initproc;
254
255 if(p->state == ZOMBIE) {
256 wakeup1(initproc);
257 }
258 }
259 }
260
261 // Jump into the scheduler, never to return.
262 proc->state = ZOMBIE;
263 sched();
264
265 panic("zombie exit");
266 }
267
268 // Wait for a child process to exit and return its pid.
269 // Return -1 if this process has no children.
270 int wait(void)
271 {
272 struct proc *p;
273 int havekids, pid;
274
275 acquire(&ptable.lock);
276
277 for(;;){
278 // Scan through table looking for zombie children.
279 havekids = 0;
280
281 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
282 if(p->parent != proc) {
283 continue;
284 }
285
286 havekids = 1;
287
288 if(p->state == ZOMBIE){
289 // Found one.
290 pid = p->pid;
291 free_page(p->kstack);
292 p->kstack = 0;
293 freevm(p->pgdir);
294 p->state = UNUSED;
295 p->pid = 0;
296 p->parent = 0;
297 p->name[0] = 0;
298 p->killed = 0;
299 release(&ptable.lock);
300
301 return pid;
302 }
303 }
304
305 // No point waiting if we don't have any children.
306 if(!havekids || proc->killed){
307 release(&ptable.lock);
308 return -1;
309 }
310
311 // Wait for children to exit. (See wakeup1 call in proc_exit.)
312 sleep(proc, &ptable.lock); //DOC: wait-sleep
313 }
314 }
315
316 //PAGEBREAK: 42
317 // Per-CPU process scheduler.
318 // Each CPU calls scheduler() after setting itself up.
319 // Scheduler never returns. It loops, doing:
320 // - choose a process to run
321 // - swtch to start running that process
322 // - eventually that process transfers control
323 // via swtch back to the scheduler.
324 void scheduler(void)
325 {
326 struct proc *p;
327
328 for(;;){
329 // Enable interrupts on this processor.
330 sti();
331
332 // Loop over process table looking for process to run.
333 acquire(&ptable.lock);
334
335 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
336 if(p->state != RUNNABLE) {
337 continue;
338 }
339
340 // Switch to chosen process. It is the process's job
341 // to release ptable.lock and then reacquire it
342 // before jumping back to us.
343 proc = p;
344 switchuvm(p);
345
346 p->state = RUNNING;
347
348 swtch(&cpu->scheduler, proc->context);
349 // Process is done running for now.
350 // It should have changed its p->state before coming back.
351 proc = 0;
352 }
353
354 release(&ptable.lock);
355 }
356 }
357
358 __ncode cbc_sched(__code(*next)())
359 {
360 int intena;
361
362 if(!holding(&ptable.lock)) {
363 panic("sched ptable.lock");
364 }
365
366 if(cpu->ncli != 1) {
367 panic("sched locks");
368 }
369
370 if(proc->state == RUNNING) {
371 panic("sched running");
372 }
373
374 if(int_enabled ()) {
375 panic("sched interruptible");
376 }
377
378 intena = cpu->intena;
379 swtch(&proc->context, cpu->scheduler);
380 cpu->intena = intena;
381
382 goto next();
383 }
384
385
386 // Enter scheduler. Must hold only ptable.lock
387 // and have changed proc->state.
388 void sched(void)
389 {
390 int intena;
391
392 //show_callstk ("sched");
393
394 if(!holding(&ptable.lock)) {
395 panic("sched ptable.lock");
396 }
397
398 if(cpu->ncli != 1) {
399 panic("sched locks");
400 }
401
402 if(proc->state == RUNNING) {
403 panic("sched running");
404 }
405
406 if(int_enabled ()) {
407 panic("sched interruptible");
408 }
409
410 intena = cpu->intena;
411 swtch(&proc->context, cpu->scheduler);
412 cpu->intena = intena;
413 }
414
415 // Give up the CPU for one scheduling round.
416 void yield(void)
417 {
418 acquire(&ptable.lock); //DOC: yieldlock
419 proc->state = RUNNABLE;
420 sched();
421 release(&ptable.lock);
422 }
423
424 // A fork child's very first scheduling by scheduler()
425 // will swtch here. "Return" to user space.
426 void forkret(void)
427 {
428 static int first = 1;
429
430 // Still holding ptable.lock from scheduler.
431 release(&ptable.lock);
432
433 if (first) {
434 // Some initialization functions must be run in the context
435 // of a regular process (e.g., they call sleep), and thus cannot
436 // be run from main().
437 first = 0;
438 initlog();
439 }
440
441 // Return to "caller", actually trapret (see allocproc).
442 }
443
444 __ncode cbc_sleep1()
445 {
446 struct spinlock *lk = proc->lk;
447 // Tidy up.
448 proc->chan = 0;
449
450 // Reacquire original lock.
451 if(lk != &ptable.lock){ //DOC: sleeplock2
452 release(&ptable.lock);
453 acquire(lk);
454 }
455 goto proc->cbc_next();
456 }
457
458 __ncode cbc_sleep(void *chan, struct spinlock *lk, __code(*next1)())
459 {
460 //show_callstk("sleep");
461
462 if(proc == 0) {
463 panic("sleep");
464 }
465
466 if(lk == 0) {
467 panic("sleep without lk");
468 }
469
470 if(lk != &ptable.lock){ //DOC: sleeplock0
471 acquire(&ptable.lock); //DOC: sleeplock1
472 release(lk);
473 }
474 proc->chan = chan;
475 proc->state = SLEEPING;
476 proc->lk = lk;
477 proc->cbc_next = next1;
478
479 goto cbc_sched(cbc_sleep1);
480 }
481
482 // Atomically release lock and sleep on chan.
483 // Reacquires lock when awakened.
484 void sleep(void *chan, struct spinlock *lk)
485 {
486 //show_callstk("sleep");
487
488 if(proc == 0) {
489 panic("sleep");
490 }
491
492 if(lk == 0) {
493 panic("sleep without lk");
494 }
495
496 // Must acquire ptable.lock in order to change p->state and then call
497 // sched. Once we hold ptable.lock, we can be guaranteed that we won't
498 // miss any wakeup (wakeup runs with ptable.lock locked), so it's okay
499 // to release lk.
500 if(lk != &ptable.lock){ //DOC: sleeplock0
501 acquire(&ptable.lock); //DOC: sleeplock1
502 release(lk);
503 }
504
505 // Go to sleep.
506 proc->chan = chan;
507 proc->state = SLEEPING;
508 sched();
509
510 // Tidy up.
511 proc->chan = 0;
512
513 // Reacquire original lock.
514 if(lk != &ptable.lock){ //DOC: sleeplock2
515 release(&ptable.lock);
516 acquire(lk);
517 }
518 }
519
520 //PAGEBREAK!
521 // Wake up all processes sleeping on chan. The ptable lock must be held.
522 static void wakeup1(void *chan)
523 {
524 struct proc *p;
525
526 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
527 if(p->state == SLEEPING && p->chan == chan) {
528 p->state = RUNNABLE;
529 }
530 }
531 }
532
533 __ncode cbc_wakeup1(void *chan)
534 {
535 struct proc *p;
536
537 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
538 if(p->state == SLEEPING && p->chan == chan) {
539 p->state = RUNNABLE;
540 }
541 }
542
543 release(&ptable.lock);
544 goto proc->cbc_next();
545 }
546
547 __ncode cbc_wakeup(void *chan, __code(*next1)())
548 {
549 acquire(&ptable.lock);
550 proc->cbc_next = next1;
551 cbc_wakeup1(chan);
552 }
553
554 // Wake up all processes sleeping on chan.
555 void wakeup(void *chan)
556 {
557 acquire(&ptable.lock);
558 wakeup1(chan);
559 release(&ptable.lock);
560 }
561
562 // Kill the process with the given pid. Process won't exit until it returns
563 // to user space (see trap in trap.c).
564 int kill(int pid)
565 {
566 struct proc *p;
567
568 acquire(&ptable.lock);
569
570 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
571 if(p->pid == pid){
572 p->killed = 1;
573
574 // Wake process from sleep if necessary.
575 if(p->state == SLEEPING) {
576 p->state = RUNNABLE;
577 }
578
579 release(&ptable.lock);
580 return 0;
581 }
582 }
583
584 release(&ptable.lock);
585 return -1;
586 }
587
588 //PAGEBREAK: 36
589 // Print a process listing to console. For debugging. Runs when user
590 // types ^P on console. No lock to avoid wedging a stuck machine further.
591 void procdump(void)
592 {
593 static char *states[] = {
594 [UNUSED] ="unused",
595 [EMBRYO] ="embryo",
596 [SLEEPING] ="sleep ",
597 [RUNNABLE] ="runble",
598 [RUNNING] ="run ",
599 [ZOMBIE] ="zombie"
600 };
601
602 struct proc *p;
603 char *state;
604
605 for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
606 if(p->state == UNUSED) {
607 continue;
608 }
609
610 if(p->state >= 0 && p->state < NELEM(states) && states[p->state]) {
611 state = states[p->state];
612 } else {
613 state = "???";
614 }
615
616 cprintf("%d %s %d:%s %d\n", p->pid, state, p->pid, p->name, p->parent->pid);
617 }
618
619 show_callstk("procdump: \n");
620 }
621
622