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;
|
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
|
//PAGEBREAK: 42
|
||||||
// Per-CPU process scheduler.
|
// Per-CPU process scheduler.
|
||||||
// Each CPU calls scheduler() after setting itself up.
|
// Each CPU calls scheduler() after setting itself up.
|
||||||
|
@ -357,89 +443,3 @@ kill(int pid)
|
||||||
return -1;
|
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 SEG_TSS 6 // this process's task state
|
||||||
#define NSEGS 7
|
#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.
|
// Saved registers for kernel context switches.
|
||||||
// Don't need to save all the segment registers (%cs, etc),
|
// Don't need to save all the segment registers (%cs, etc),
|
||||||
// because they are constant across kernel contexts.
|
// because they are constant across kernel contexts.
|
||||||
|
@ -50,32 +80,3 @@ struct proc {
|
||||||
// original data and bss
|
// original data and bss
|
||||||
// fixed-size stack
|
// fixed-size stack
|
||||||
// expandable heap
|
// 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: bootasm.S # mild preference
|
||||||
even: bootother.S # mild preference
|
even: bootother.S # mild preference
|
||||||
even: bootmain.S # mild preference
|
even: bootmain.c # mild preference
|
||||||
even: main.c
|
even: main.c
|
||||||
# mp.c don't care at all
|
# mp.c don't care at all
|
||||||
# even: initcode.S
|
# even: initcode.S
|
||||||
# odd: init.c
|
# odd: init.c
|
||||||
|
|
||||||
# spinlock.h either
|
# spinlock.h either
|
||||||
left: spinlock.c # mild preference
|
left: spinlock.h # mild preference
|
||||||
even: proc.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,
|
# goal is to have two action-packed 2-page spreads,
|
||||||
# one with
|
# one with
|
||||||
# allocproc userinit growproc fork
|
# userinit growproc fork exit wait
|
||||||
# and another with
|
# and another with
|
||||||
# scheduler sched yield forkret sleep wakeup1 wakeup
|
# 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
|
# setjmp.S either
|
||||||
# vm.c either
|
# vm.c either
|
||||||
|
|
Loading…
Reference in a new issue