replace setjmp/longjmp with swtch
This commit is contained in:
parent
b52dea08bc
commit
818fc0125e
19
Makefile
19
Makefile
|
@ -14,9 +14,9 @@ OBJS = \
|
||||||
picirq.o\
|
picirq.o\
|
||||||
pipe.o\
|
pipe.o\
|
||||||
proc.o\
|
proc.o\
|
||||||
setjmp.o\
|
|
||||||
spinlock.o\
|
spinlock.o\
|
||||||
string.o\
|
string.o\
|
||||||
|
swtch.o\
|
||||||
syscall.o\
|
syscall.o\
|
||||||
sysfile.o\
|
sysfile.o\
|
||||||
sysproc.o\
|
sysproc.o\
|
||||||
|
@ -67,7 +67,7 @@ initcode: initcode.S
|
||||||
kernel: $(OBJS) bootother initcode
|
kernel: $(OBJS) bootother initcode
|
||||||
$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary initcode bootother
|
$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary initcode bootother
|
||||||
$(OBJDUMP) -S kernel > kernel.asm
|
$(OBJDUMP) -S kernel > kernel.asm
|
||||||
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* //' > kernel.sym
|
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
|
||||||
|
|
||||||
tags: $(OBJS) bootother.S _init
|
tags: $(OBJS) bootother.S _init
|
||||||
etags *.S *.c
|
etags *.S *.c
|
||||||
|
@ -80,7 +80,7 @@ ULIB = ulib.o usys.o printf.o umalloc.o
|
||||||
_%: %.o $(ULIB)
|
_%: %.o $(ULIB)
|
||||||
$(LD) -N -e main -Ttext 0 -o $@ $^
|
$(LD) -N -e main -Ttext 0 -o $@ $^
|
||||||
$(OBJDUMP) -S $@ > $*.asm
|
$(OBJDUMP) -S $@ > $*.asm
|
||||||
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* //' > $*.sym
|
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
|
||||||
|
|
||||||
_forktest: forktest.o $(ULIB)
|
_forktest: forktest.o $(ULIB)
|
||||||
# forktest has less library code linked in - needs to be small
|
# forktest has less library code linked in - needs to be small
|
||||||
|
@ -119,18 +119,7 @@ clean:
|
||||||
$(UPROGS)
|
$(UPROGS)
|
||||||
|
|
||||||
# make a printout
|
# make a printout
|
||||||
PRINT = \
|
PRINT = runoff.list $(shell grep -v '^\#' runoff.list)
|
||||||
runoff.list \
|
|
||||||
README\
|
|
||||||
types.h param.h defs.h x86.h asm.h elf.h mmu.h spinlock.h\
|
|
||||||
bootasm.S bootother.S main.c init.c spinlock.c\
|
|
||||||
proc.h proc.c setjmp.S kalloc.c\
|
|
||||||
syscall.h trapasm.S traps.h trap.c vectors.pl syscall.c sysproc.c\
|
|
||||||
buf.h dev.h fcntl.h stat.h file.h fs.h fsvar.h file.c fs.c bio.c ide.c sysfile.c\
|
|
||||||
pipe.c exec.c\
|
|
||||||
mp.h ioapic.h mp.c lapic.c ioapic.c picirq.c\
|
|
||||||
console.c\
|
|
||||||
string.c\
|
|
||||||
|
|
||||||
xv6.pdf: $(PRINT)
|
xv6.pdf: $(PRINT)
|
||||||
./runoff
|
./runoff
|
||||||
|
|
7
defs.h
7
defs.h
|
@ -1,7 +1,7 @@
|
||||||
struct buf;
|
struct buf;
|
||||||
|
struct context;
|
||||||
struct file;
|
struct file;
|
||||||
struct inode;
|
struct inode;
|
||||||
struct jmpbuf;
|
|
||||||
struct pipe;
|
struct pipe;
|
||||||
struct proc;
|
struct proc;
|
||||||
struct spinlock;
|
struct spinlock;
|
||||||
|
@ -109,9 +109,8 @@ void userinit(void);
|
||||||
void wakeup(void*);
|
void wakeup(void*);
|
||||||
void yield(void);
|
void yield(void);
|
||||||
|
|
||||||
// setjmp.S
|
// swtch.S
|
||||||
void longjmp(struct jmpbuf*);
|
void swtch(struct context*, struct context*);
|
||||||
int setjmp(struct jmpbuf*);
|
|
||||||
|
|
||||||
// spinlock.c
|
// spinlock.c
|
||||||
void acquire(struct spinlock*);
|
void acquire(struct spinlock*);
|
||||||
|
|
16
proc.c
16
proc.c
|
@ -134,10 +134,10 @@ copyproc(struct proc *p)
|
||||||
np->cwd = idup(p->cwd);
|
np->cwd = idup(p->cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up new jmpbuf to start executing at forkret (see below).
|
// Set up new context to start executing at forkret (see below).
|
||||||
memset(&np->jmpbuf, 0, sizeof(np->jmpbuf));
|
memset(&np->context, 0, sizeof(np->context));
|
||||||
np->jmpbuf.eip = (uint)forkret;
|
np->context.eip = (uint)forkret;
|
||||||
np->jmpbuf.esp = (uint)np->tf - 4;
|
np->context.esp = (uint)np->tf;
|
||||||
|
|
||||||
// Clear %eax so that fork system call returns 0 in child.
|
// Clear %eax so that fork system call returns 0 in child.
|
||||||
np->tf->eax = 0;
|
np->tf->eax = 0;
|
||||||
|
@ -206,8 +206,7 @@ scheduler(void)
|
||||||
setupsegs(p);
|
setupsegs(p);
|
||||||
cp = p;
|
cp = p;
|
||||||
p->state = RUNNING;
|
p->state = RUNNING;
|
||||||
if(setjmp(&cpus[cpu()].jmpbuf) == 0)
|
swtch(&cpus[cpu()].context, &p->context);
|
||||||
longjmp(&p->jmpbuf);
|
|
||||||
|
|
||||||
// Process is done running for now.
|
// Process is done running for now.
|
||||||
// It should have changed its p->state before coming back.
|
// It should have changed its p->state before coming back.
|
||||||
|
@ -232,8 +231,7 @@ sched(void)
|
||||||
if(cpus[cpu()].nlock != 1)
|
if(cpus[cpu()].nlock != 1)
|
||||||
panic("sched locks");
|
panic("sched locks");
|
||||||
|
|
||||||
if(setjmp(&cp->jmpbuf) == 0)
|
swtch(&cp->context, &cpus[cpu()].context);
|
||||||
longjmp(&cpus[cpu()].jmpbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give up the CPU for one scheduling round.
|
// Give up the CPU for one scheduling round.
|
||||||
|
@ -458,7 +456,7 @@ procdump(void)
|
||||||
state = "???";
|
state = "???";
|
||||||
cprintf("%d %s %s", p->pid, state, p->name);
|
cprintf("%d %s %s", p->pid, state, p->name);
|
||||||
if(p->state == SLEEPING) {
|
if(p->state == SLEEPING) {
|
||||||
getcallerpcs((uint*)p->jmpbuf.ebp+2, pc);
|
getcallerpcs((uint*)p->context.ebp+2, pc);
|
||||||
for(j=0; j<10 && pc[j] != 0; j++)
|
for(j=0; j<10 && pc[j] != 0; j++)
|
||||||
cprintf(" %p", pc[j]);
|
cprintf(" %p", pc[j]);
|
||||||
}
|
}
|
||||||
|
|
16
proc.h
16
proc.h
|
@ -10,18 +10,18 @@
|
||||||
// Don't need to save all the %fs etc. segment registers,
|
// Don't need to save all the %fs etc. segment registers,
|
||||||
// because they are constant across kernel contexts.
|
// because they are constant across kernel contexts.
|
||||||
// Save all the regular registers so we don't need to care
|
// Save all the regular registers so we don't need to care
|
||||||
// which are caller save.
|
// which are caller save, but not the return register %eax.
|
||||||
// Don't save %eax, because that's the return register.
|
// (Not saving %eax just simplifies the switching code.)
|
||||||
// The layout of jmpbuf must match code in setjmp.S.
|
// The layout of context must match code in swtch.S.
|
||||||
struct jmpbuf {
|
struct context {
|
||||||
|
int eip;
|
||||||
|
int esp;
|
||||||
int ebx;
|
int ebx;
|
||||||
int ecx;
|
int ecx;
|
||||||
int edx;
|
int edx;
|
||||||
int esi;
|
int esi;
|
||||||
int edi;
|
int edi;
|
||||||
int esp;
|
|
||||||
int ebp;
|
int ebp;
|
||||||
int eip;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
||||||
|
@ -38,7 +38,7 @@ struct proc {
|
||||||
int killed; // If non-zero, have been killed
|
int killed; // If non-zero, have been killed
|
||||||
struct file *ofile[NOFILE]; // Open files
|
struct file *ofile[NOFILE]; // Open files
|
||||||
struct inode *cwd; // Current directory
|
struct inode *cwd; // Current directory
|
||||||
struct jmpbuf jmpbuf; // Jump here to run process
|
struct context context; // Switch here to run process
|
||||||
struct trapframe *tf; // Trap frame for current interrupt
|
struct trapframe *tf; // Trap frame for current interrupt
|
||||||
char name[16]; // Process name (debugging)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
@ -61,7 +61,7 @@ extern struct proc *curproc[NCPU]; // Current (running) process per CPU
|
||||||
// Per-CPU state
|
// Per-CPU state
|
||||||
struct cpu {
|
struct cpu {
|
||||||
uchar apicid; // Local APIC ID
|
uchar apicid; // Local APIC ID
|
||||||
struct jmpbuf jmpbuf; // Jump here to enter scheduler
|
struct context context; // Switch here to enter scheduler
|
||||||
struct taskstate ts; // Used by x86 to find stack for interrupt
|
struct taskstate ts; // Used by x86 to find stack for interrupt
|
||||||
struct segdesc gdt[NSEGS]; // x86 global descriptor table
|
struct segdesc gdt[NSEGS]; // x86 global descriptor table
|
||||||
char mpstack[MPSTACK]; // Per-CPU startup stack
|
char mpstack[MPSTACK]; // Per-CPU startup stack
|
||||||
|
|
|
@ -22,7 +22,7 @@ spinlock.c
|
||||||
# processes
|
# processes
|
||||||
proc.h
|
proc.h
|
||||||
proc.c
|
proc.c
|
||||||
setjmp.S
|
swtch.S
|
||||||
kalloc.c
|
kalloc.c
|
||||||
|
|
||||||
# system calls
|
# system calls
|
||||||
|
|
49
setjmp.S
49
setjmp.S
|
@ -1,49 +0,0 @@
|
||||||
# int setjmp(struct jmpbuf *jmp);
|
|
||||||
# void longjmp(struct jmpbuf *jmp);
|
|
||||||
#
|
|
||||||
# Setjmp saves its stack environment in jmp for later use by longjmp.
|
|
||||||
# It returns 0.
|
|
||||||
#
|
|
||||||
# Longjmp restores the environment saved by the last call of setjmp.
|
|
||||||
# It then causes execution to continue as if the call of setjmp
|
|
||||||
# had just returned 1.
|
|
||||||
#
|
|
||||||
# The caller of setjmp must not itself have returned in the interim.
|
|
||||||
# All accessible data have values as of the time longjmp was called.
|
|
||||||
#
|
|
||||||
# [Description, but not code, borrowed from Plan 9.]
|
|
||||||
|
|
||||||
.globl setjmp
|
|
||||||
setjmp:
|
|
||||||
movl 4(%esp), %eax
|
|
||||||
|
|
||||||
movl %ebx, 0(%eax)
|
|
||||||
movl %ecx, 4(%eax)
|
|
||||||
movl %edx, 8(%eax)
|
|
||||||
movl %esi, 12(%eax)
|
|
||||||
movl %edi, 16(%eax)
|
|
||||||
movl %esp, 20(%eax)
|
|
||||||
movl %ebp, 24(%eax)
|
|
||||||
pushl 0(%esp) # %eip
|
|
||||||
popl 28(%eax)
|
|
||||||
|
|
||||||
movl $0, %eax # return value
|
|
||||||
ret
|
|
||||||
|
|
||||||
.globl longjmp
|
|
||||||
longjmp:
|
|
||||||
movl 4(%esp), %eax
|
|
||||||
|
|
||||||
movl 0(%eax), %ebx
|
|
||||||
movl 4(%eax), %ecx
|
|
||||||
movl 8(%eax), %edx
|
|
||||||
movl 12(%eax), %esi
|
|
||||||
movl 16(%eax), %edi
|
|
||||||
movl 20(%eax), %esp
|
|
||||||
movl 24(%eax), %ebp
|
|
||||||
|
|
||||||
addl $4, %esp # pop and discard %eip
|
|
||||||
pushl 28(%eax) # push new %eip
|
|
||||||
|
|
||||||
movl $1, %eax # return value (appears to come from setjmp!)
|
|
||||||
ret
|
|
32
swtch.S
Normal file
32
swtch.S
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# void swtch(struct context *old, struct context *new);
|
||||||
|
#
|
||||||
|
# Save current register context in old
|
||||||
|
# and then load register context from new.
|
||||||
|
|
||||||
|
.globl swtch
|
||||||
|
swtch:
|
||||||
|
# Save old registers
|
||||||
|
movl 4(%esp), %eax
|
||||||
|
|
||||||
|
popl 0(%eax) # %eip
|
||||||
|
movl %esp, 4(%eax)
|
||||||
|
movl %ebx, 8(%eax)
|
||||||
|
movl %ecx, 12(%eax)
|
||||||
|
movl %edx, 16(%eax)
|
||||||
|
movl %esi, 20(%eax)
|
||||||
|
movl %edi, 24(%eax)
|
||||||
|
movl %ebp, 28(%eax)
|
||||||
|
|
||||||
|
# Load new registers
|
||||||
|
movl 4(%esp), %eax # not 8(%esp) - popped return address above
|
||||||
|
|
||||||
|
movl 28(%eax), %ebp
|
||||||
|
movl 24(%eax), %edi
|
||||||
|
movl 20(%eax), %esi
|
||||||
|
movl 16(%eax), %edx
|
||||||
|
movl 12(%eax), %ecx
|
||||||
|
movl 8(%eax), %ebx
|
||||||
|
movl 4(%eax), %esp
|
||||||
|
pushl 0(%eax) # %eip
|
||||||
|
|
||||||
|
ret
|
Loading…
Reference in a new issue