提交 69db41a0 创建 作者: Silas Boyd-Wickizer's avatar Silas Boyd-Wickizer

Add a timeout to condvars.

Waking up a process after the its wait time expires might livelock core 0, but it's unlikely.
上级 9cd75414
...@@ -8,15 +8,60 @@ ...@@ -8,15 +8,60 @@
#include "kernel.h" #include "kernel.h"
#include "cpu.h" #include "cpu.h"
void struct spinlock tickslock __mpalign__;
initcondvar(struct condvar *cv, char *n) struct condvar cv_ticks __mpalign__;
u64 ticks __mpalign__;
LIST_HEAD(sleepers, proc) sleepers __mpalign__;
struct spinlock sleepers_lock;
static void
wakeup(struct proc *p)
{ {
initlock(&cv->lock, n); LIST_REMOVE(p, cv_waiters);
cv->waiters = 0; p->oncv = 0;
addrun(p);
p->state = RUNNABLE;
} }
void void
cv_sleep(struct condvar *cv, struct spinlock *lk) cv_tick(void)
{
struct proc *p, *tmp;
int again;
u64 now;
acquire(&tickslock);
ticks++;
cv_wakeup(&cv_ticks);
release(&tickslock);
now = nsectime();
again = 0;
do {
acquire(&sleepers_lock);
LIST_FOREACH_SAFE(p, &sleepers, cv_sleep, tmp) {
if (p->cv_wakeup <= now) {
if (tryacquire(&p->lock)) {
if (tryacquire(&p->oncv->lock)) {
LIST_REMOVE(p, cv_sleep);
p->cv_wakeup = 0;
wakeup(p);
release(&p->lock);
release(&p->oncv->lock);
continue;
} else {
release(&p->lock);
}
}
again = 1;
}
}
release(&sleepers_lock);
} while (again);
}
void cv_sleepto(struct condvar *cv, struct spinlock *lk, u64 timeout)
{ {
if(myproc() == 0) if(myproc() == 0)
panic("sleep"); panic("sleep");
...@@ -31,44 +76,61 @@ cv_sleep(struct condvar *cv, struct spinlock *lk) ...@@ -31,44 +76,61 @@ cv_sleep(struct condvar *cv, struct spinlock *lk)
acquire(&myproc()->lock); acquire(&myproc()->lock);
if(myproc()->cv_next || myproc()->oncv) if(myproc()->oncv)
panic("cv_sleep cv_next"); panic("cv_sleep oncv");
myproc()->cv_next = cv->waiters;
cv->waiters = myproc(); LIST_INSERT_HEAD(&cv->waiters, myproc(), cv_waiters);
myproc()->state = SLEEPING;
myproc()->oncv = cv; myproc()->oncv = cv;
myproc()->state = SLEEPING;
if (timeout) {
acquire(&sleepers_lock);
myproc()->cv_wakeup = timeout;
LIST_INSERT_HEAD(&sleepers, myproc(), cv_sleep);
release(&sleepers_lock);
}
release(&cv->lock); release(&cv->lock);
sched(); sched();
release(&myproc()->lock); release(&myproc()->lock);
// Reacquire original lock. // Reacquire original lock.
acquire(lk); acquire(lk);
} }
void
cv_sleep(struct condvar *cv, struct spinlock *lk)
{
cv_sleepto(cv, lk, 0);
}
// Wake up all processes sleeping on this condvar. // Wake up all processes sleeping on this condvar.
void void
cv_wakeup(struct condvar *cv) cv_wakeup(struct condvar *cv)
{ {
// XXX race with cv_sleep() struct proc *p, *tmp;
// if (!cv->waiters)
// return;
acquire(&cv->lock); acquire(&cv->lock);
while(cv->waiters) { LIST_FOREACH_SAFE(p, &cv->waiters, cv_waiters, tmp) {
struct proc *p = cv->waiters;
acquire(&p->lock); acquire(&p->lock);
if(p->state != SLEEPING || p->oncv != cv) if(p->state != SLEEPING || p->oncv != cv)
panic("cv_wakeup"); panic("cv_wakeup");
struct proc *nxt = p->cv_next; if (p->cv_wakeup) {
p->cv_next = 0; acquire(&sleepers_lock);
p->oncv = 0; LIST_REMOVE(p, cv_sleep);
addrun(p); p->cv_wakeup = 0;
p->state = RUNNABLE; release(&sleepers_lock);
}
wakeup(p);
release(&p->lock); release(&p->lock);
cv->waiters = nxt;
} }
release(&cv->lock); release(&cv->lock);
} }
void
initcondvar(struct condvar *cv, char *n)
{
initlock(&cv->lock, n);
LIST_INIT(&cv->waiters);
}
#include "queue.h"
struct condvar { struct condvar {
struct spinlock lock; struct spinlock lock;
struct proc *waiters; LIST_HEAD(waiters, proc) waiters;
}; };
...@@ -55,9 +55,14 @@ void tree_test(void); ...@@ -55,9 +55,14 @@ void tree_test(void);
void cgaputc(int c); void cgaputc(int c);
// condvar.c // condvar.c
extern u64 ticks;
extern struct spinlock tickslock;
extern struct condvar cv_ticks;
void initcondvar(struct condvar *, char *); void initcondvar(struct condvar *, char *);
void cv_sleep(struct condvar *cv, struct spinlock*); void cv_sleep(struct condvar *cv, struct spinlock*);
void cv_sleepto(struct condvar *cv, struct spinlock*, u64);
void cv_wakeup(struct condvar *cv); void cv_wakeup(struct condvar *cv);
void cv_tick(void);
// console.c // console.c
void cprintf(const char*, ...); void cprintf(const char*, ...);
...@@ -279,9 +284,6 @@ void swtch(struct context**, struct context*); ...@@ -279,9 +284,6 @@ void swtch(struct context**, struct context*);
// trap.c // trap.c
extern struct segdesc bootgdt[NSEGS]; extern struct segdesc bootgdt[NSEGS];
extern u64 ticks;
extern struct spinlock tickslock;
extern struct condvar cv_ticks;
// uart.c // uart.c
void uartputc(char c); void uartputc(char c);
......
...@@ -42,8 +42,6 @@ struct proc { ...@@ -42,8 +42,6 @@ struct proc {
struct proc *parent; // Parent process struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall struct trapframe *tf; // Trap frame for current syscall
struct context *context; // swtch() here to run process struct context *context; // swtch() here to run process
struct condvar *oncv; // Where it is sleeping, for kill()
struct proc *cv_next; // Linked list of processes waiting for oncv
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
...@@ -66,6 +64,11 @@ struct proc { ...@@ -66,6 +64,11 @@ struct proc {
struct runq *runq; struct runq *runq;
struct wqframe wqframe; struct wqframe wqframe;
STAILQ_ENTRY(proc) runqlink; STAILQ_ENTRY(proc) runqlink;
struct condvar *oncv; // Where it is sleeping, for kill()
u64 cv_wakeup; // Wakeup time for this process
LIST_ENTRY(proc) cv_waiters; // Linked list of processes waiting for oncv
LIST_ENTRY(proc) cv_sleep; // Linked list of processes sleeping on a cv
}; };
extern struct ns *nspid; extern struct ns *nspid;
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
#include "kmtrace.h" #include "kmtrace.h"
#include "bits.h" #include "bits.h"
u64 ticks __mpalign__;
struct spinlock tickslock __mpalign__;
struct condvar cv_ticks __mpalign__;
struct segdesc __attribute__((aligned(16))) bootgdt[NSEGS] = { struct segdesc __attribute__((aligned(16))) bootgdt[NSEGS] = {
// null // null
[0]=SEGDESC(0, 0, 0), [0]=SEGDESC(0, 0, 0),
...@@ -76,12 +71,8 @@ trap(struct trapframe *tf) ...@@ -76,12 +71,8 @@ trap(struct trapframe *tf)
switch(tf->trapno){ switch(tf->trapno){
case T_IRQ0 + IRQ_TIMER: case T_IRQ0 + IRQ_TIMER:
if(mycpu()->id == 0){ if (mycpu()->id == 0)
acquire(&tickslock); cv_tick();
ticks++;
cv_wakeup(&cv_ticks);
release(&tickslock);
}
lapiceoi(); lapiceoi();
break; break;
case T_IRQ0 + IRQ_IDE: case T_IRQ0 + IRQ_IDE:
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论