Rearrange proc.h and proc.c to get our action-packed spreads back (mostly). They also make sense in this order, so it's not just for page layout.
This commit is contained in:
parent
dd3ecd42cd
commit
d8828817d7
172
proc.c
172
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
59
proc.h
59
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.
|
||||
|
|
15
runoff.spec
15
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
|
||||
|
|
Loading…
Reference in a new issue