summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proc.c172
-rw-r--r--proc.h59
-rw-r--r--runoff.spec15
3 files changed, 126 insertions, 120 deletions
diff --git a/proc.c b/proc.c
index 375b1bb..8197377 100644
--- a/proc.c
+++ b/proc.c
@@ -193,6 +193,92 @@ fork(void)
return pid;
}
+// Exit the current process. Does not return.
+// An exited process remains in the zombie state
+// until its parent calls wait() to find out it exited.
+void
+exit(void)
+{
+ struct proc *p;
+ int fd;
+
+ if(proc == initproc)
+ panic("init exiting");
+
+ // Close all open files.
+ for(fd = 0; fd < NOFILE; fd++){
+ if(proc->ofile[fd]){
+ fileclose(proc->ofile[fd]);
+ proc->ofile[fd] = 0;
+ }
+ }
+
+ iput(proc->cwd);
+ proc->cwd = 0;
+
+ acquire(&ptable.lock);
+
+ // Parent might be sleeping in wait().
+ wakeup1(proc->parent);
+
+ // Pass abandoned children to init.
+ for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+ if(p->parent == proc){
+ p->parent = initproc;
+ if(p->state == ZOMBIE)
+ wakeup1(initproc);
+ }
+ }
+
+ // Jump into the scheduler, never to return.
+ proc->state = ZOMBIE;
+ sched();
+ panic("zombie exit");
+}
+
+// Wait for a child process to exit and return its pid.
+// Return -1 if this process has no children.
+int
+wait(void)
+{
+ struct proc *p;
+ int havekids, pid;
+
+ acquire(&ptable.lock);
+ for(;;){
+ // Scan through table looking for zombie children.
+ havekids = 0;
+ for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+ if(p->parent != proc)
+ continue;
+ havekids = 1;
+ if(p->state == ZOMBIE){
+ // Found one.
+ pid = p->pid;
+ kfree(p->kstack);
+ p->kstack = 0;
+ freevm(p->pgdir);
+ p->state = UNUSED;
+ p->pid = 0;
+ p->parent = 0;
+ p->name[0] = 0;
+ p->killed = 0;
+ release(&ptable.lock);
+ return pid;
+ }
+ }
+
+ // No point waiting if we don't have any children.
+ if(!havekids || proc->killed){
+ release(&ptable.lock);
+ return -1;
+ }
+
+ // Wait for children to exit. (See wakeup1 call in proc_exit.)
+ sleep(proc, &ptable.lock); //DOC: wait-sleep
+ }
+}
+
//PAGEBREAK: 42
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
@@ -357,89 +443,3 @@ kill(int pid)
return -1;
}
-// Exit the current process. Does not return.
-// An exited process remains in the zombie state
-// until its parent calls wait() to find out it exited.
-void
-exit(void)
-{
- struct proc *p;
- int fd;
-
- if(proc == initproc)
- panic("init exiting");
-
- // Close all open files.
- for(fd = 0; fd < NOFILE; fd++){
- if(proc->ofile[fd]){
- fileclose(proc->ofile[fd]);
- proc->ofile[fd] = 0;
- }
- }
-
- iput(proc->cwd);
- proc->cwd = 0;
-
- acquire(&ptable.lock);
-
- // Parent might be sleeping in wait().
- wakeup1(proc->parent);
-
- // Pass abandoned children to init.
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->parent == proc){
- p->parent = initproc;
- if(p->state == ZOMBIE)
- wakeup1(initproc);
- }
- }
-
- // Jump into the scheduler, never to return.
- proc->state = ZOMBIE;
- sched();
- panic("zombie exit");
-}
-
-// Wait for a child process to exit and return its pid.
-// Return -1 if this process has no children.
-int
-wait(void)
-{
- struct proc *p;
- int havekids, pid;
-
- acquire(&ptable.lock);
- for(;;){
- // Scan through table looking for zombie children.
- havekids = 0;
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->parent != proc)
- continue;
- havekids = 1;
- if(p->state == ZOMBIE){
- // Found one.
- pid = p->pid;
- kfree(p->kstack);
- p->kstack = 0;
- freevm(p->pgdir);
- p->state = UNUSED;
- p->pid = 0;
- p->parent = 0;
- p->name[0] = 0;
- p->killed = 0;
- release(&ptable.lock);
- return pid;
- }
- }
-
- // No point waiting if we don't have any children.
- if(!havekids || proc->killed){
- release(&ptable.lock);
- return -1;
- }
-
- // Wait for children to exit. (See wakeup1 call in proc_exit.)
- sleep(proc, &ptable.lock); //DOC: wait-sleep
- }
-}
-
diff --git a/proc.h b/proc.h
index 8799668..4a80a28 100644
--- a/proc.h
+++ b/proc.h
@@ -8,6 +8,36 @@
#define SEG_TSS 6 // this process's task state
#define NSEGS 7
+// Per-CPU state
+struct cpu {
+ uchar id; // Local APIC ID; index into cpus[] below
+ struct context *scheduler; // Switch here to enter scheduler
+ struct taskstate ts; // Used by x86 to find stack for interrupt
+ struct segdesc gdt[NSEGS]; // x86 global descriptor table
+ volatile uint booted; // Has the CPU started?
+ int ncli; // Depth of pushcli nesting.
+ int intena; // Were interrupts enabled before pushcli?
+
+ // Cpu-local storage variables; see below
+ struct cpu *cpu;
+ struct proc *proc;
+};
+
+extern struct cpu cpus[NCPU];
+extern int ncpu;
+
+// Per-CPU variables, holding pointers to the
+// current cpu and to the current process.
+// The asm suffix tells gcc to use "%gs:0" to refer to cpu
+// and "%gs:4" to refer to proc. ksegment sets up the
+// %gs segment register so that %gs refers to the memory
+// holding those two variables in the local cpu's struct cpu.
+// This is similar to how thread-local variables are implemented
+// in thread libraries such as Linux pthreads.
+extern struct cpu *cpu asm("%gs:0"); // This cpu.
+extern struct proc *proc asm("%gs:4"); // Current proc on this cpu.
+
+//PAGEBREAK: 17
// Saved registers for kernel context switches.
// Don't need to save all the segment registers (%cs, etc),
// because they are constant across kernel contexts.
@@ -50,32 +80,3 @@ struct proc {
// original data and bss
// fixed-size stack
// expandable heap
-
-// Per-CPU state
-struct cpu {
- uchar id; // Local APIC ID; index into cpus[] below
- struct context *scheduler; // Switch here to enter scheduler
- struct taskstate ts; // Used by x86 to find stack for interrupt
- struct segdesc gdt[NSEGS]; // x86 global descriptor table
- volatile uint booted; // Has the CPU started?
- int ncli; // Depth of pushcli nesting.
- int intena; // Were interrupts enabled before pushcli?
-
- // Cpu-local storage variables; see below
- struct cpu *cpu;
- struct proc *proc;
-};
-
-extern struct cpu cpus[NCPU];
-extern int ncpu;
-
-// Per-CPU variables, holding pointers to the
-// current cpu and to the current process.
-// The asm suffix tells gcc to use "%gs:0" to refer to cpu
-// and "%gs:4" to refer to proc. ksegment sets up the
-// %gs segment register so that %gs refers to the memory
-// holding those two variables in the local cpu's struct cpu.
-// This is similar to how thread-local variables are implemented
-// in thread libraries such as Linux pthreads.
-extern struct cpu *cpu asm("%gs:0"); // This cpu.
-extern struct proc *proc asm("%gs:4"); // Current proc on this cpu.
diff --git a/runoff.spec b/runoff.spec
index fe960ce..9d87528 100644
--- a/runoff.spec
+++ b/runoff.spec
@@ -20,22 +20,27 @@ sheet1: left
even: bootasm.S # mild preference
even: bootother.S # mild preference
-even: bootmain.S # mild preference
+even: bootmain.c # mild preference
even: main.c
# mp.c don't care at all
# even: initcode.S
# odd: init.c
# spinlock.h either
-left: spinlock.c # mild preference
-even: proc.h # mild preference
+left: spinlock.h # mild preference
+even: spinlock.h # mild preference
+
+# This gets struct proc and allocproc on the same spread
+right: proc.h
+odd: proc.h
# goal is to have two action-packed 2-page spreads,
# one with
-# allocproc userinit growproc fork
+# userinit growproc fork exit wait
# and another with
# scheduler sched yield forkret sleep wakeup1 wakeup
-right: proc.c # VERY important
+left: proc.c # VERY important
+odd: proc.c # VERY important
# setjmp.S either
# vm.c either