From 65b79dc77d29c842d1a483f20f1648a48ab332da Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 14 May 1998 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1998-05-14 --- pc/trap.c | 7 ++++-- port/proc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/pc/trap.c b/pc/trap.c index 48835905e74128c2bbd6f0bd29c31c413de83ab2..79286fbfb7b74c65c5a5a65c8373a8c8472d0d66 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -143,9 +143,12 @@ trap(Ureg* ureg) { ulong x, y; -x = (ulong)&(m->stack[512]); +if(up) + x = (ulong)(up->kstack); +else + x = (ulong)(m->stack); y = (ulong)&mach; -if(y < x) panic("trap: kstack %lux %lux", m->stack, y); +if(y < x+512) panic("cpu%d: trap: kstack %lux %lux", m->machno, x, y); } v = ureg->trap; diff --git a/port/proc.c b/port/proc.c index 24b450eaa4bf4a0ed4e7915a2d2ed2f0ee21021d..a852c61d0da34ca8ddad9b8d6ce370f7040236dc 100644 --- a/port/proc.c +++ b/port/proc.c @@ -82,6 +82,10 @@ schedinit(void) /* never returns */ sched(); } +/* + * If changing this routine, look also at sleep(). It + * contains a copy of the guts of sched(). + */ void sched(void) { @@ -377,6 +381,57 @@ procinit0(void) /* bad planning - clashes with devproc.c */ p->qnext = 0; } + +/* + * Sleep, postnote, and wakeup are complicated by the + * fact that they at least one of them must indirect + * through an unlocked structure to find the synchronizing + * lock structure. This is because sleep() + * and wakeup() share direct knowledge only of r while + * sleep() and postnote() share knowledge only of p. We've + * chosen to put the synchronization lock in p, i.e., + * p->rlock. Therefore the interaction between sleep() + * and postnote() is completely synchronized by keeping + * p->rlock locked in sleep until the process has + * saved all the information it needs to become dormant. + * + * However, wakeup() can only find what process is sleeping + * by looking at r->p. A wakeup looks like: + * + * 1) set condition that sleep checks with (*f)() + * 2) is p = r->p non zero + * 3) lock(p->rlock) + * 4) check r->p == p + * 5) ... + * + * A sleep looks like + * + * a) lock(p->rlock) + * b) r->p = up + * c) check condition + * d) ... + * + * On a multiprocessor, two processors + * may not see writes occur in the same order. The coherence() + * instruction ensures that a processor has flushed all its + * writes to memory so that those writes will be seen by other + * processors and that the processor will see all writes flushed + * by other processors. + * + * To make the above sequence work on a multiprocessor, we need + * to put a coherence() call between (1) and (2) and between + * (b) and (c). That way we're guaranteed that if (1) and + * (2) occur after (c), the wakeup process will know + * which process is about to sleep and will enter its + * critical section. If it doesn't, the sleep could proceed + * while the waker returns without doing anything. + * Similarly, if (b) and (c) occur after (2), + * the sleeper needs coherence to see that the condition was + * set. Otherwise it could sleep even though the wakeup + * had already decided there was nothing to do. + * + * jmk & presotto + */ void sleep(Rendez *r, int (*f)(void*), void *arg) { @@ -391,10 +446,10 @@ sleep(Rendez *r, int (*f)(void*), void *arg) } /* - * Wakeup only knows there may be something to do by testing - * r->p in order to get something to lock on. - * Flush that information out to memory in case the sleep is - * committed. + * Wakeup only knows there may be something to do by testing + * r->p in order to get something to lock on. + * Flush that information out to memory in case the sleep is + * committed. */ r->p = up; coherence(); @@ -495,7 +550,11 @@ wakeup(Rendez *r) Proc *p; int s, rv; - coherence(); /* force memory state to reflect processor state */ + /* + * this makes sure that the condition sleep checks + * with its (*f)(void) is visible to it + */ + coherence(); rv = 0; p = r->p;