提交 46a37cb9 创建 作者: Frans Kaashoek's avatar Frans Kaashoek

condvars

上级 0d948cbd
OBJS = \ OBJS = \
bio.o\ bio.o\
condvar.o\
console.o\ console.o\
exec.o\ exec.o\
file.o\ file.o\
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "defs.h" #include "defs.h"
#include "param.h" #include "param.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "buf.h" #include "buf.h"
struct { struct {
...@@ -53,6 +54,7 @@ binit(void) ...@@ -53,6 +54,7 @@ binit(void)
b->dev = -1; b->dev = -1;
bcache.head.next->prev = b; bcache.head.next->prev = b;
bcache.head.next = b; bcache.head.next = b;
initlock(&b->cv.lock, "bache");
} }
} }
...@@ -75,7 +77,7 @@ bget(uint dev, uint sector) ...@@ -75,7 +77,7 @@ bget(uint dev, uint sector)
release(&bcache.lock); release(&bcache.lock);
return b; return b;
} }
sleep(b, &bcache.lock); cv_sleep(&b->cv, &bcache.lock);
goto loop; goto loop;
} }
} }
...@@ -132,7 +134,7 @@ brelse(struct buf *b) ...@@ -132,7 +134,7 @@ brelse(struct buf *b)
bcache.head.next = b; bcache.head.next = b;
b->flags &= ~B_BUSY; b->flags &= ~B_BUSY;
wakeup(b); cv_wakeup(&b->cv);
release(&bcache.lock); release(&bcache.lock);
} }
......
...@@ -5,6 +5,7 @@ struct buf { ...@@ -5,6 +5,7 @@ struct buf {
struct buf *prev; // LRU cache list struct buf *prev; // LRU cache list
struct buf *next; struct buf *next;
struct buf *qnext; // disk queue struct buf *qnext; // disk queue
struct condvar cv;
uchar data[512]; uchar data[512];
}; };
#define B_BUSY 0x1 // buffer is locked by some process #define B_BUSY 0x1 // buffer is locked by some process
......
#include "types.h"
#include "defs.h"
#include "param.h"
#include "x86.h"
#include "mmu.h"
#include "spinlock.h"
#include "condvar.h"
#include "proc.h"
void
cv_sleep(struct condvar *cv, struct spinlock *lk)
{
if(proc == 0)
panic("sleep");
if(lk == 0)
panic("sleep without lk");
// Must acquire cv_lock to avoid sleep/wakeup race
acquire(&cv->lock);
cprintf("cv_sleep: 0x%x\n", cv);
release(lk);
if (cv->waiters != 0)
panic("cv_sleep\n");
cv->waiters = proc; // XXX should be queue
delrun(proc);
acquire(&proc->lock);
release(&cv->lock);
proc->state = SLEEPING;
sched();
release(&proc->lock);
acquire(&cv->lock);
// Tidy up.
cv->waiters = 0;
// Reacquire original lock.
cprintf("acquire %s\n", lk->name);
acquire(lk);
release(&cv->lock);
}
void
cv_wakeup(struct condvar *cv)
{
acquire(&cv->lock);
if (cv->waiters != 0) {
cprintf("wakeup 0x%x %d\n", cv, cv->waiters->pid);
addrun(cv->waiters);
}
release(&cv->lock);
}
struct condvar {
char name[MAXNAME];
struct spinlock lock;
struct proc *waiters;
void *chan; // If non-zero, sleeping on chan
};
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "param.h" #include "param.h"
#include "traps.h" #include "traps.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "fs.h" #include "fs.h"
#include "file.h" #include "file.h"
#include "mmu.h" #include "mmu.h"
...@@ -173,6 +174,7 @@ consputc(int c) ...@@ -173,6 +174,7 @@ consputc(int c)
#define INPUT_BUF 128 #define INPUT_BUF 128
struct { struct {
struct spinlock lock; struct spinlock lock;
struct condvar cv;
char buf[INPUT_BUF]; char buf[INPUT_BUF];
uint r; // Read index uint r; // Read index
uint w; // Write index uint w; // Write index
...@@ -212,7 +214,7 @@ consoleintr(int (*getc)(void)) ...@@ -212,7 +214,7 @@ consoleintr(int (*getc)(void))
consputc(c); consputc(c);
if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){ if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
input.w = input.e; input.w = input.e;
wakeup(&input.r); cv_wakeup(&input.cv);
} }
} }
break; break;
...@@ -237,7 +239,7 @@ consoleread(struct inode *ip, char *dst, int n) ...@@ -237,7 +239,7 @@ consoleread(struct inode *ip, char *dst, int n)
ilock(ip); ilock(ip);
return -1; return -1;
} }
sleep(&input.r, &input.lock); cv_sleep(&input.cv, &input.lock);
} }
c = input.buf[input.r++ % INPUT_BUF]; c = input.buf[input.r++ % INPUT_BUF];
if(c == C('D')){ // EOF if(c == C('D')){ // EOF
...@@ -279,6 +281,7 @@ consoleinit(void) ...@@ -279,6 +281,7 @@ consoleinit(void)
{ {
initlock(&cons.lock, "console"); initlock(&cons.lock, "console");
initlock(&input.lock, "input"); initlock(&input.lock, "input");
initlock(&input.cv.lock, "input");
devsw[CONSOLE].write = consolewrite; devsw[CONSOLE].write = consolewrite;
devsw[CONSOLE].read = consoleread; devsw[CONSOLE].read = consoleread;
......
...@@ -5,6 +5,7 @@ struct inode; ...@@ -5,6 +5,7 @@ struct inode;
struct pipe; struct pipe;
struct proc; struct proc;
struct spinlock; struct spinlock;
struct condvar;
struct stat; struct stat;
// bio.c // bio.c
...@@ -13,6 +14,10 @@ struct buf* bread(uint, uint); ...@@ -13,6 +14,10 @@ struct buf* bread(uint, uint);
void brelse(struct buf*); void brelse(struct buf*);
void bwrite(struct buf*); void bwrite(struct buf*);
// condvar.c
void cv_sleep(struct condvar *cv, struct spinlock*);
void cv_wakeup(struct condvar *cv);
// console.c // console.c
void consoleinit(void); void consoleinit(void);
void cprintf(char*, ...); void cprintf(char*, ...);
...@@ -93,7 +98,9 @@ int pipewrite(struct pipe*, char*, int); ...@@ -93,7 +98,9 @@ int pipewrite(struct pipe*, char*, int);
//PAGEBREAK: 16 //PAGEBREAK: 16
// proc.c // proc.c
void addrun(struct proc *);
struct proc* copyproc(struct proc*); struct proc* copyproc(struct proc*);
void delrun(struct proc*);
void exit(void); void exit(void);
int fork(void); int fork(void);
int growproc(int); int growproc(int);
...@@ -103,11 +110,11 @@ void procdump(int); ...@@ -103,11 +110,11 @@ void procdump(int);
void procdumpall(void); void procdumpall(void);
void scheduler(void) __attribute__((noreturn)); void scheduler(void) __attribute__((noreturn));
void sched(void); void sched(void);
void sleep(void*, struct spinlock*);
void userinit(void); void userinit(void);
int wait(void); int wait(void);
void wakeup(void*);
void yield(void); void yield(void);
void wakeup(void*);
void sleep(void*, struct spinlock*);
// swtch.S // swtch.S
void swtch(struct context**, struct context*); void swtch(struct context**, struct context*);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "defs.h" #include "defs.h"
#include "x86.h" #include "x86.h"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "stat.h" #include "stat.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "buf.h" #include "buf.h"
#include "fs.h" #include "fs.h"
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "x86.h" #include "x86.h"
#include "traps.h" #include "traps.h"
...@@ -48,8 +49,8 @@ ideinit(void) ...@@ -48,8 +49,8 @@ ideinit(void)
initlock(&idelock, "ide"); initlock(&idelock, "ide");
picenable(IRQ_IDE); picenable(IRQ_IDE);
// ioapicenable(IRQ_IDE, ncpu - 1); ioapicenable(IRQ_IDE, ncpu - 1);
ioapicenable(IRQ_IDE, 0); // ioapicenable(IRQ_IDE, 0);
idewait(0); idewait(0);
// Check if disk 1 is present // Check if disk 1 is present
...@@ -109,7 +110,7 @@ ideintr(void) ...@@ -109,7 +110,7 @@ ideintr(void)
// Wake process waiting for this buf. // Wake process waiting for this buf.
b->flags |= B_VALID; b->flags |= B_VALID;
b->flags &= ~B_DIRTY; b->flags &= ~B_DIRTY;
wakeup(b); cv_wakeup(&b->cv);
// Start disk on next buf in queue. // Start disk on next buf in queue.
if(idequeue != 0) if(idequeue != 0)
...@@ -149,7 +150,7 @@ iderw(struct buf *b) ...@@ -149,7 +150,7 @@ iderw(struct buf *b)
// Wait for request to finish. // Wait for request to finish.
// Assuming will not sleep too long: ignore proc->killed. // Assuming will not sleep too long: ignore proc->killed.
while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
sleep(b, &idelock); cv_sleep(&b->cv, &idelock);
} }
release(&idelock); release(&idelock);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "kalloc.h" #include "kalloc.h"
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "x86.h" #include "x86.h"
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "x86.h" #include "x86.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
struct cpu cpus[NCPU]; struct cpu cpus[NCPU];
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "fs.h" #include "fs.h"
#include "file.h" #include "file.h"
......
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
#include "mmu.h" #include "mmu.h"
#include "x86.h" #include "x86.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
struct ptable ptables[NCPU]; struct ptable ptables[NCPU];
struct runq runqs[NCPU]; struct runq runqs[NCPU];
struct condvar condvars[NPROC]; struct condtab condtabs[NCPU];
struct spinlock lock_condvars;
static struct proc *initproc; static struct proc *initproc;
int nextpid = 1; int nextpid = 1;
...@@ -31,14 +31,21 @@ pinit(void) ...@@ -31,14 +31,21 @@ pinit(void)
for (i = 0; i < NPROC; i++) { for (i = 0; i < NPROC; i++) {
initlock(&ptables[c].proc[i].lock, ptables[c].proc[i].name); initlock(&ptables[c].proc[i].lock, ptables[c].proc[i].name);
initlock(&ptables[c].proc[i].cv.lock, ptables[c].proc[i].name);
} }
runqs[c].name[0] = (char) (c + '0'); runqs[c].name[0] = (char) (c + '0');
safestrcpy(runqs[c].name+1, "runq", MAXNAME-1); safestrcpy(runqs[c].name+1, "runq", MAXNAME-1);
initlock(&runqs[c].lock, runqs[c].name); initlock(&runqs[c].lock, runqs[c].name);
condtabs[c].name[0] = (char) (c + '0');
safestrcpy(condtabs[c].name+1, "condtab", MAXNAME-1);
initlock(&condtabs[c].lock, condtabs[c].name);
for (i = 0; i < NPROC; i++) {
initlock(&condtabs[c].condtab[i].lock, condtabs[c].condtab[i].name);
}
} }
initlock(&lock_condvars, "condvar");
} }
//PAGEBREAK: 32 //PAGEBREAK: 32
...@@ -105,10 +112,11 @@ addrun1(struct runq *rq, struct proc *p) ...@@ -105,10 +112,11 @@ addrun1(struct runq *rq, struct proc *p)
rq->runq = p; rq->runq = p;
} }
static void void
addrun(struct proc *p) addrun(struct proc *p)
{ {
acquire(&runq->lock); acquire(&runq->lock);
cprintf("%d: addrun %d\n", cpunum(), p->pid);
addrun1(runq, p); addrun1(runq, p);
release(&runq->lock); release(&runq->lock);
} }
...@@ -136,10 +144,11 @@ delrun1(struct runq *rq, struct proc *proc) ...@@ -136,10 +144,11 @@ delrun1(struct runq *rq, struct proc *proc)
} }
void void
delrun(struct proc *proc) delrun(struct proc *p)
{ {
acquire(&runq->lock); acquire(&runq->lock);
delrun1(runq, proc); cprintf("%d: delrun %d\n", cpunum(), p->pid);
delrun1(runq, p);
release(&runq->lock); release(&runq->lock);
} }
...@@ -272,15 +281,15 @@ exit(void) ...@@ -272,15 +281,15 @@ exit(void)
release(&ptables[c].lock); release(&ptables[c].lock);
} }
acquire(&proc->lock);
// Parent might be sleeping in wait(). // Parent might be sleeping in wait().
wakeup(proc->parent); cv_wakeup(&proc->parent->cv);
if (wakeupinit) if (wakeupinit)
wakeup(initproc); cv_wakeup(&initproc->cv);
acquire(&proc->lock);
delrun1(runq, proc); delrun1(runq, proc); // XXX get lock on runq
// Jump into the scheduler, never to return. // Jump into the scheduler, never to return.
proc->state = ZOMBIE; proc->state = ZOMBIE;
...@@ -333,7 +342,7 @@ wait(void) ...@@ -333,7 +342,7 @@ wait(void)
} }
// Wait for children to exit. (See wakeup1 call in proc_exit.) // Wait for children to exit. (See wakeup1 call in proc_exit.)
sleep(proc, &proc->lock); cv_sleep(&proc->cv, &proc->lock);
release(&proc->lock); release(&proc->lock);
} }
...@@ -475,83 +484,7 @@ forkret(void) ...@@ -475,83 +484,7 @@ forkret(void)
// Return to "caller", actually trapret (see allocproc). // Return to "caller", actually trapret (see allocproc).
} }
// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void
sleep(void *chan, struct spinlock *lk)
{
int i;
if(proc == 0)
panic("sleep");
if(lk == 0)
panic("sleep without lk");
// Must acquire lock_condvar in order to
// change p->state and then call sched.
// Once we hold lock_condvar, we can be
// guaranteed that we won't miss any wakeup
// (wakeup runs with lock_condvar locked),
// so it's okay to release lk.
acquire(&lock_condvars);
release(lk);
// find a condvar and record sleeper
// XXX should we check if there is a condvar for chan?
for (i = 0; i < NPROC; i++) {
if (condvars[i].chan == 0) {
break;
}
}
if (i == NPROC)
panic("out of condvars");
// add sleeper
condvars[i].chan = chan;
condvars[i].waiters = proc;
// remove from runqueue
acquire(&proc->lock);
proc->state = SLEEPING;
delrun1(runq, proc);
release(&lock_condvars);
sched();
release(&proc->lock);
acquire(&lock_condvars);
// Tidy up.
condvars[i].chan = 0;
// Reacquire original lock.
cprintf("acquire %s\n", lk->name);
acquire(lk);
release(&lock_condvars);
}
// Wake up all processes sleeping on chan.
void
wakeup(void *chan)
{
int c;
acquire(&lock_condvars);
for (c = 0; c < NPROC; c++) {
if (condvars[c].chan == chan) {
addrun(condvars[c].waiters);
goto done;
}
}
// cprintf("wakeup on 0x%x; no chan; lost wakeup?\n", chan);
done:
release(&lock_condvars);
}
// Kill the process with the given pid. // Kill the process with the given pid.
// Process won't exit until it returns // Process won't exit until it returns
...@@ -635,3 +568,19 @@ procdumpall(void) ...@@ -635,3 +568,19 @@ procdumpall(void)
procdump(c); procdump(c);
} }
} }
//// dead code
// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void
sleep(void *chan, struct spinlock *lk)
{
panic("sleep");
}
// Wake up all processes sleeping on chan.
void
wakeup(void *chan)
{
}
...@@ -47,8 +47,8 @@ struct proc { ...@@ -47,8 +47,8 @@ struct proc {
char name[16]; // Process name (debugging) char name[16]; // Process name (debugging)
struct spinlock lock; struct spinlock lock;
struct proc *runq; struct proc *runq;
struct proc *waiterq;
struct proc *childq; struct proc *childq;
struct condvar cv;
}; };
// Process memory is laid out contiguously, low addresses first: // Process memory is laid out contiguously, low addresses first:
...@@ -73,13 +73,9 @@ struct cpu { ...@@ -73,13 +73,9 @@ struct cpu {
struct ptable *ptable; // The per-core proc table struct ptable *ptable; // The per-core proc table
struct kmem *kmem; // The per-core proc table struct kmem *kmem; // The per-core proc table
struct runq *runq; // The per-core proc table struct runq *runq; // The per-core proc table
struct condtab *contab; // The per-core proc table
}; };
struct condvar {
struct spinlock lock;
struct proc *waiters;
void *chan; // If non-zero, sleeping on chan
};
struct runq { struct runq {
char name[MAXNAME]; char name[MAXNAME];
...@@ -94,9 +90,16 @@ struct ptable { ...@@ -94,9 +90,16 @@ struct ptable {
struct proc *runq; struct proc *runq;
}; };
struct condtab {
char name[MAXNAME];
struct spinlock lock;
struct condvar condtab[NPROC];
};
extern struct ptable ptables[NCPU]; extern struct ptable ptables[NCPU];
extern struct cpu cpus[NCPU]; extern struct cpu cpus[NCPU];
extern struct runq runqs[NCPU]; extern struct runq runqs[NCPU];
extern struct condtab condtabs[NCPU];
extern int ncpu; extern int ncpu;
// Per-CPU variables, holding pointers to the // Per-CPU variables, holding pointers to the
...@@ -112,3 +115,4 @@ extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc ...@@ -112,3 +115,4 @@ extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc
extern struct ptable *ptable asm("%gs:8"); // &ptables[cpunum()] extern struct ptable *ptable asm("%gs:8"); // &ptables[cpunum()]
extern struct kmem *kmem asm("%gs:12"); // &kmems[cpunum()] extern struct kmem *kmem asm("%gs:12"); // &kmems[cpunum()]
extern struct runq *runq asm("%gs:16"); // &runqs[cpunum()] extern struct runq *runq asm("%gs:16"); // &runqs[cpunum()]
extern struct condtab *condtab asm("%gs:20"); // &condtabs[cpunum()]
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "x86.h" #include "x86.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
void void
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "x86.h" #include "x86.h"
#include "syscall.h" #include "syscall.h"
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "stat.h" #include "stat.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "fs.h" #include "fs.h"
#include "file.h" #include "file.h"
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
int int
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "param.h" #include "param.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "x86.h" #include "x86.h"
#include "traps.h" #include "traps.h"
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "fs.h" #include "fs.h"
#include "file.h" #include "file.h"
#include "mmu.h" #include "mmu.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "x86.h" #include "x86.h"
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "x86.h" #include "x86.h"
#include "mmu.h" #include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
#include "condvar.h"
#include "proc.h" #include "proc.h"
#include "elf.h" #include "elf.h"
#include "kalloc.h" #include "kalloc.h"
...@@ -49,6 +50,7 @@ seginit(void) ...@@ -49,6 +50,7 @@ seginit(void)
ptable = &ptables[cpunum()]; ptable = &ptables[cpunum()];
kmem = &kmems[cpunum()]; kmem = &kmems[cpunum()];
runq = &runqs[cpunum()]; runq = &runqs[cpunum()];
condtab = &condtabs[cpunum()];
} }
// Return the address of the PTE in page table pgdir // Return the address of the PTE in page table pgdir
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论