From 818fc0125e7d73fdf4f1a94f178254e5d05c9831 Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 28 Aug 2007 12:48:33 +0000 Subject: [PATCH] replace setjmp/longjmp with swtch --- Makefile | 19 ++++--------------- defs.h | 7 +++---- proc.c | 16 +++++++--------- proc.h | 16 ++++++++-------- runoff.list | 2 +- setjmp.S | 49 ------------------------------------------------- swtch.S | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 55 insertions(+), 86 deletions(-) delete mode 100644 setjmp.S create mode 100644 swtch.S diff --git a/Makefile b/Makefile index a27ec5f..0e2bc0f 100644 --- a/Makefile +++ b/Makefile @@ -14,9 +14,9 @@ OBJS = \ picirq.o\ pipe.o\ proc.o\ - setjmp.o\ spinlock.o\ string.o\ + swtch.o\ syscall.o\ sysfile.o\ sysproc.o\ @@ -67,7 +67,7 @@ initcode: initcode.S kernel: $(OBJS) bootother initcode $(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary initcode bootother $(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 etags *.S *.c @@ -80,7 +80,7 @@ ULIB = ulib.o usys.o printf.o umalloc.o _%: %.o $(ULIB) $(LD) -N -e main -Ttext 0 -o $@ $^ $(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 has less library code linked in - needs to be small @@ -119,18 +119,7 @@ clean: $(UPROGS) # make a printout -PRINT = \ - 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\ +PRINT = runoff.list $(shell grep -v '^\#' runoff.list) xv6.pdf: $(PRINT) ./runoff diff --git a/defs.h b/defs.h index a72ecaf..35323ea 100644 --- a/defs.h +++ b/defs.h @@ -1,7 +1,7 @@ struct buf; +struct context; struct file; struct inode; -struct jmpbuf; struct pipe; struct proc; struct spinlock; @@ -109,9 +109,8 @@ void userinit(void); void wakeup(void*); void yield(void); -// setjmp.S -void longjmp(struct jmpbuf*); -int setjmp(struct jmpbuf*); +// swtch.S +void swtch(struct context*, struct context*); // spinlock.c void acquire(struct spinlock*); diff --git a/proc.c b/proc.c index eb7d1f8..46a38bf 100644 --- a/proc.c +++ b/proc.c @@ -134,10 +134,10 @@ copyproc(struct proc *p) np->cwd = idup(p->cwd); } - // Set up new jmpbuf to start executing at forkret (see below). - memset(&np->jmpbuf, 0, sizeof(np->jmpbuf)); - np->jmpbuf.eip = (uint)forkret; - np->jmpbuf.esp = (uint)np->tf - 4; + // Set up new context to start executing at forkret (see below). + memset(&np->context, 0, sizeof(np->context)); + np->context.eip = (uint)forkret; + np->context.esp = (uint)np->tf; // Clear %eax so that fork system call returns 0 in child. np->tf->eax = 0; @@ -206,8 +206,7 @@ scheduler(void) setupsegs(p); cp = p; p->state = RUNNING; - if(setjmp(&cpus[cpu()].jmpbuf) == 0) - longjmp(&p->jmpbuf); + swtch(&cpus[cpu()].context, &p->context); // Process is done running for now. // It should have changed its p->state before coming back. @@ -232,8 +231,7 @@ sched(void) if(cpus[cpu()].nlock != 1) panic("sched locks"); - if(setjmp(&cp->jmpbuf) == 0) - longjmp(&cpus[cpu()].jmpbuf); + swtch(&cp->context, &cpus[cpu()].context); } // Give up the CPU for one scheduling round. @@ -458,7 +456,7 @@ procdump(void) state = "???"; cprintf("%d %s %s", p->pid, state, p->name); 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++) cprintf(" %p", pc[j]); } diff --git a/proc.h b/proc.h index 84dc57d..f76e264 100644 --- a/proc.h +++ b/proc.h @@ -10,18 +10,18 @@ // Don't need to save all the %fs etc. segment registers, // because they are constant across kernel contexts. // Save all the regular registers so we don't need to care -// which are caller save. -// Don't save %eax, because that's the return register. -// The layout of jmpbuf must match code in setjmp.S. -struct jmpbuf { +// which are caller save, but not the return register %eax. +// (Not saving %eax just simplifies the switching code.) +// The layout of context must match code in swtch.S. +struct context { + int eip; + int esp; int ebx; int ecx; int edx; int esi; int edi; - int esp; int ebp; - int eip; }; enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; @@ -38,7 +38,7 @@ struct proc { int killed; // If non-zero, have been killed struct file *ofile[NOFILE]; // Open files 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 char name[16]; // Process name (debugging) }; @@ -61,7 +61,7 @@ extern struct proc *curproc[NCPU]; // Current (running) process per CPU // Per-CPU state struct cpu { 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 segdesc gdt[NSEGS]; // x86 global descriptor table char mpstack[MPSTACK]; // Per-CPU startup stack diff --git a/runoff.list b/runoff.list index 80c8f35..cbc8fca 100644 --- a/runoff.list +++ b/runoff.list @@ -22,7 +22,7 @@ spinlock.c # processes proc.h proc.c -setjmp.S +swtch.S kalloc.c # system calls diff --git a/setjmp.S b/setjmp.S deleted file mode 100644 index 3fe23c5..0000000 --- a/setjmp.S +++ /dev/null @@ -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 diff --git a/swtch.S b/swtch.S new file mode 100644 index 0000000..786e9ac --- /dev/null +++ b/swtch.S @@ -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