summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <[email protected]>2009-07-12 18:33:37 -0700
committerRuss Cox <[email protected]>2009-07-12 18:33:37 -0700
commit00e571155ce6f836a7f78e7a725c1b3de7868b5a (patch)
treeda28e68cf21f6f12669f497f98907b758edab34e
parent2c5f7aba38f8e7207a81fdef36d7720bda9dc4e5 (diff)
downloadxv6-labs-00e571155ce6f836a7f78e7a725c1b3de7868b5a.tar.gz
xv6-labs-00e571155ce6f836a7f78e7a725c1b3de7868b5a.tar.bz2
xv6-labs-00e571155ce6f836a7f78e7a725c1b3de7868b5a.zip
more doc tweaks
-rw-r--r--TRICKS26
-rw-r--r--pipe.c40
-rw-r--r--proc.c38
-rw-r--r--web/l-coordination.html2
4 files changed, 52 insertions, 54 deletions
diff --git a/TRICKS b/TRICKS
index b538834..0338279 100644
--- a/TRICKS
+++ b/TRICKS
@@ -4,6 +4,9 @@ might be worth pointing out in a longer explanation or in class.
---
+[2009/07/12: No longer relevant; forkret1 changed
+and this is now cleaner.]
+
forkret1 in trapasm.S is called with a tf argument.
In order to use it, forkret1 copies the tf pointer into
%esp and then jumps to trapret, which pops the
@@ -45,21 +48,21 @@ always.
There is a (harmless) race in pushcli, which does
- eflags = read_eflags();
+ eflags = readeflags();
cli();
- if(cpus[cpu()].ncli++ == 0)
- cpus[cpu()].intena = eflags & FL_IF;
+ if(c->ncli++ == 0)
+ c->intena = eflags & FL_IF;
Consider a bottom-level pushcli.
If interrupts are disabled already, then the right thing
happens: read_eflags finds that FL_IF is not set,
-and intena = 1. If interrupts are enabled, then
+and intena = 0. If interrupts are enabled, then
it is less clear that the right thing happens:
-the read_eflags can execute, then the process
+the readeflags can execute, then the process
can get preempted and rescheduled on another cpu,
and then once it starts running, perhaps with
interrupts disabled (can happen since the scheduler
-only disables interrupts once per scheduling loop,
+only enables interrupts once per scheduling loop,
not every time it schedules a process), it will
incorrectly record that interrupts *were* enabled.
This doesn't matter, because if it was safe to be
@@ -112,17 +115,13 @@ processors will need it.
---
-The code in sys_fork needs to read np->pid before
+The code in fork needs to read np->pid before
setting np->state to RUNNABLE.
int
- sys_fork(void)
+ fork(void)
{
- int pid;
- struct proc *np;
-
- if((np = copyproc(cp)) == 0)
- return -1;
+ ...
pid = np->pid;
np->state = RUNNABLE;
return pid;
@@ -134,3 +133,4 @@ get reused for a different process (with a new pid), all
before the return statement. So it's not safe to just do
"return np->pid;".
+This works because proc.h marks the pid as volatile.
diff --git a/pipe.c b/pipe.c
index 7f18e98..3032775 100644
--- a/pipe.c
+++ b/pipe.c
@@ -9,12 +9,12 @@
#define PIPESIZE 512
struct pipe {
- int readopen; // read fd is still open
- int writeopen; // write fd is still open
- uint writep; // next index to write
- uint readp; // next index to read
struct spinlock lock;
char data[PIPESIZE];
+ uint nread; // number of bytes read
+ uint nwrite; // number of bytes written
+ int readopen; // read fd is still open
+ int writeopen; // write fd is still open
};
int
@@ -30,8 +30,8 @@ pipealloc(struct file **f0, struct file **f1)
goto bad;
p->readopen = 1;
p->writeopen = 1;
- p->writep = 0;
- p->readp = 0;
+ p->nwrite = 0;
+ p->nread = 0;
initlock(&p->lock, "pipe");
(*f0)->type = FD_PIPE;
(*f0)->readable = 1;
@@ -60,10 +60,10 @@ pipeclose(struct pipe *p, int writable)
acquire(&p->lock);
if(writable){
p->writeopen = 0;
- wakeup(&p->readp);
+ wakeup(&p->nread);
} else {
p->readopen = 0;
- wakeup(&p->writep);
+ wakeup(&p->nwrite);
}
if(p->readopen == 0 && p->writeopen == 0) {
release(&p->lock);
@@ -80,19 +80,19 @@ pipewrite(struct pipe *p, char *addr, int n)
acquire(&p->lock);
for(i = 0; i < n; i++){
- while(p->writep == p->readp + PIPESIZE) {
+ while(p->nwrite == p->nread + PIPESIZE) { //DOC: pipewrite-full
if(p->readopen == 0 || cp->killed){
release(&p->lock);
return -1;
}
- wakeup(&p->readp);
- sleep(&p->writep, &p->lock);
+ wakeup(&p->nread);
+ sleep(&p->nwrite, &p->lock); //DOC: pipewrite-sleep
}
- p->data[p->writep++ % PIPESIZE] = addr[i];
+ p->data[p->nwrite++ % PIPESIZE] = addr[i];
}
- wakeup(&p->readp);
+ wakeup(&p->nread); //DOC: pipewrite-wakeup1
release(&p->lock);
- return i;
+ return n;
}
int
@@ -101,19 +101,19 @@ piperead(struct pipe *p, char *addr, int n)
int i;
acquire(&p->lock);
- while(p->readp == p->writep && p->writeopen){
+ while(p->nread == p->nwrite && p->writeopen){ //DOC: pipe-empty
if(cp->killed){
release(&p->lock);
return -1;
}
- sleep(&p->readp, &p->lock);
+ sleep(&p->nread, &p->lock); //DOC: piperead-sleep
}
- for(i = 0; i < n; i++){
- if(p->readp == p->writep)
+ for(i = 0; i < n; i++){ //DOC: piperead-copy
+ if(p->nread == p->nwrite)
break;
- addr[i] = p->data[p->readp++ % PIPESIZE];
+ addr[i] = p->data[p->nread++ % PIPESIZE];
}
- wakeup(&p->writep);
+ wakeup(&p->nwrite); //DOC: piperead-wakeup
release(&p->lock);
return i;
}
diff --git a/proc.c b/proc.c
index aa6c4ec..4333512 100644
--- a/proc.c
+++ b/proc.c
@@ -290,8 +290,8 @@ sleep(void *chan, struct spinlock *lk)
// guaranteed that we won't miss any wakeup
// (wakeup runs with ptable.lock locked),
// so it's okay to release lk.
- if(lk != &ptable.lock){
- acquire(&ptable.lock);
+ if(lk != &ptable.lock){ //DOC: sleeplock0
+ acquire(&ptable.lock); //DOC: sleeplock1
release(lk);
}
@@ -304,7 +304,7 @@ sleep(void *chan, struct spinlock *lk)
cp->chan = 0;
// Reacquire original lock.
- if(lk != &ptable.lock){
+ if(lk != &ptable.lock){ //DOC: sleeplock2
release(&ptable.lock);
acquire(lk);
}
@@ -393,7 +393,6 @@ exit(void)
}
// Jump into the scheduler, never to return.
- cp->killed = 0;
cp->state = ZOMBIE;
sched();
panic("zombie exit");
@@ -412,22 +411,21 @@ wait(void)
// Scan through table looking for zombie children.
havekids = 0;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->state == UNUSED)
+ if(p->parent != cp)
continue;
- if(p->parent == cp){
- havekids = 1;
- if(p->state == ZOMBIE){
- // Found one.
- kfree(p->mem, p->sz);
- kfree(p->kstack, KSTACKSIZE);
- pid = p->pid;
- p->state = UNUSED;
- p->pid = 0;
- p->parent = 0;
- p->name[0] = 0;
- release(&ptable.lock);
- return pid;
- }
+ havekids = 1;
+ if(p->state == ZOMBIE){
+ // Found one.
+ pid = p->pid;
+ kfree(p->mem, p->sz);
+ kfree(p->kstack, KSTACKSIZE);
+ p->state = UNUSED;
+ p->pid = 0;
+ p->parent = 0;
+ p->name[0] = 0;
+ p->killed = 0;
+ release(&ptable.lock);
+ return pid;
}
}
@@ -438,7 +436,7 @@ wait(void)
}
// Wait for children to exit. (See wakeup1 call in proc_exit.)
- sleep(cp, &ptable.lock);
+ sleep(cp, &ptable.lock); //DOC: wait-sleep
}
}
diff --git a/web/l-coordination.html b/web/l-coordination.html
index b2f9f0d..79b578b 100644
--- a/web/l-coordination.html
+++ b/web/l-coordination.html
@@ -47,7 +47,7 @@
<h3>Sleep and wakeup - usage</h3>
Let's consider implementing a producer/consumer queue
-(like a pipe) that can be used to hold a single non-null char pointer:
+(like a pipe) that can be used to hold a single non-null pointer:
<pre>
struct pcq {