M mtx/main.c => mtx/main.c +6 -1
@@ 104,6 104,7 @@ init0(void)
{
// char **p, *q, name[KNAMELEN];
// int n;
+ char buf[2*KNAMELEN];
up->nerrlab = 0;
@@ 121,6 122,8 @@ init0(void)
chandevinit();
if(!waserror()){
+ snprint(buf, sizeof(buf), "power %s mtx", conffile);
+ ksetenv("terminal", buf, 0);
ksetenv("cputype", "power", 0);
if(cpuserver)
ksetenv("service", "cpu", 0);
@@ 137,7 140,9 @@ init0(void)
n = KNAMELEN-1;
memmove(name, p[0], n);
name[n] = 0;
- ksetenv(name, q+1);
+ if(name[0] != '*')
+ ksetenv(name, q+1, 0);
+ ksetenv(name, q+1, 1);
}
*/
poperror();
M pc/devether.c => pc/devether.c +102 -69
@@ 343,87 343,120 @@ parseether(uchar *to, char *from)
return 0;
}
-static void
-etherreset(void)
+static Ether*
+etherprobe(int cardno, int ctlrno)
{
+ int i;
Ether *ether;
- int i, n, ctlrno;
- char name[32], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->tbdf = BUSUNKNOWN;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
- if(isaconfig("ether", ctlrno, ether) == 0)
- continue;
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
+ char buf[128], name[32];
+
+ ether = malloc(sizeof(Ether));
+ memset(ether, 0, sizeof(Ether));
+ ether->ctlrno = ctlrno;
+ ether->tbdf = BUSUNKNOWN;
+ ether->mbps = 10;
+ ether->minmtu = ETHERMINTU;
+ ether->maxmtu = ETHERMAXTU;
+
+ if(cardno < 0){
+ if(isaconfig("ether", ctlrno, ether) == 0){
+ free(ether);
+ return nil;
+ }
+ for(cardno = 0; cards[cardno].type; cardno++){
+ if(cistrcmp(cards[cardno].type, ether->type))
continue;
for(i = 0; i < ether->nopt; i++){
if(strncmp(ether->opt[i], "ea=", 3))
continue;
- if(parseether(ether->ea, ðer->opt[i][3]) == -1)
+ if(parseether(ether->ea, ðer->opt[i][3]))
memset(ether->ea, 0, Eaddrlen);
- }
- if(cards[n].reset(ether))
- break;
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(ether->irq == 2)
- ether->irq = 9;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- /*
- * If ether->irq is 0, it is a hack to indicate no interrupt
- * used by ethersink.
- */
- if(ether->irq > 0)
- intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
-
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
- ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
- if(ether->mem)
- i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
- if(ether->size)
- i += sprint(buf+i, " size 0x%luX", ether->size);
- i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- if(ether->mbps >= 100){
- netifinit(ether, name, Ntypes, 256*1024);
- if(ether->oq == 0)
- ether->oq = qopen(256*1024, 1, 0, 0);
}
- else{
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(65*1024, 1, 0, 0);
- }
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
break;
}
}
- if(ether)
+
+ if(cardno >= MaxEther || cards[cardno].type == nil){
+ free(ether);
+ return nil;
+ }
+ if(cards[cardno].reset(ether) < 0){
free(ether);
+ return nil;
+ }
+
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(ether->irq == 2)
+ ether->irq = 9;
+ snprint(name, sizeof(name), "ether%d", ctlrno);
+
+ /*
+ * If ether->irq is 0, it is a hack to indicate no interrupt
+ * used by ethersink.
+ */
+ if(ether->irq > 0)
+ intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
+
+ i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
+ ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
+ if(ether->mem)
+ i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
+ if(ether->size)
+ i += sprint(buf+i, " size 0x%luX", ether->size);
+ i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
+ ether->ea[0], ether->ea[1], ether->ea[2],
+ ether->ea[3], ether->ea[4], ether->ea[5]);
+ sprint(buf+i, "\n");
+ print(buf);
+
+ if(ether->mbps >= 100){
+ netifinit(ether, name, Ntypes, 256*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(256*1024, 1, 0, 0);
+ }
+ else{
+ netifinit(ether, name, Ntypes, 65*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(65*1024, 1, 0, 0);
+ }
+ if(ether->oq == 0)
+ panic("etherreset %s", name);
+ ether->alen = Eaddrlen;
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ memset(ether->bcast, 0xFF, Eaddrlen);
+
+ return ether;
+}
+
+static void
+etherreset(void)
+{
+ Ether *ether;
+ int cardno, ctlrno;
+
+ for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if((ether = etherprobe(-1, ctlrno)) == nil)
+ continue;
+ etherxx[ctlrno] = ether;
+ }
+
+ cardno = ctlrno = 0;
+ while(cards[cardno].type != nil && ctlrno < MaxEther){
+ if(etherxx[ctlrno] != nil){
+ ctlrno++;
+ continue;
+ }
+ if((ether = etherprobe(cardno, ctlrno)) == nil){
+ cardno++;
+ continue;
+ }
+ etherxx[ctlrno] = ether;
+ ctlrno++;
+ }
}
static void
M pc/devi82365.c => pc/devi82365.c +1 -7
@@ 581,18 581,12 @@ devi82365link(void)
return;
already = 1;
- if (!getconf("pcmcia0"))
+ if(_pcmspecial)
return;
- if (_pcmspecial) {
- print("#y: PCMCIA and CardBus at the same time?\n");
- return;
- }
-
_pcmspecial = pcmcia_pcmspecial;
_pcmspecialclose = pcmcia_pcmspecialclose;
-
/* look for controllers if the ports aren't already taken */
if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
i82365probe(0x3E0, 0x3E1, 0);
M pc/devpccard.c => pc/devpccard.c +4 -9
@@ 507,17 507,9 @@ devpccardlink(void)
return;
initialized = 1;
- if (!getconf("pccard0"))
+ if(_pcmspecial)
return;
- if (_pcmspecial) {
- print("#Y: CardBus and PCMCIA at the same time?\n");
- return;
- }
-
- _pcmspecial = pccard_pcmspecial;
- _pcmspecialclose = pccard_pcmspecialclose;
-
/* Allocate legacy space */
if (ioalloc(LegacyAddr, 2, 0, "i82365.0") < 0)
print("#Y: WARNING: Cannot allocate legacy ports\n");
@@ 628,6 620,9 @@ devpccardlink(void)
if (nslots == 0)
return;
+ _pcmspecial = pccard_pcmspecial;
+ _pcmspecialclose = pccard_pcmspecialclose;
+
for (i = 0; i != nslots; i++) {
Cardbus *cb = &cbslots[i];
M pc/devusb.c => pc/devusb.c +70 -39
@@ 384,55 384,86 @@ usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
return 1;
}
-static void
-usbreset(void)
+static Usbhost*
+usbprobe(int cardno, int ctlrno)
{
- int n, ctlrno;
Usbhost *uh;
- char name[64], buf[128], *p, *ebuf, *type;
+ char buf[128], *ebuf, name[64], *p, *type;
- uh = nil;
- for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){
- if(uh == nil)
- uh = malloc(sizeof(Usbhost));
- memset(uh, 0, sizeof(Usbhost));
- uh->tbdf = BUSUNKNOWN;
- if(isaconfig("usb", ctlrno, uh) == 0)
- continue;
- for(n = 0; usbtypes[n].type; n++){
+ uh = malloc(sizeof(Usbhost));
+ memset(uh, 0, sizeof(Usbhost));
+ uh->tbdf = BUSUNKNOWN;
+
+ if(cardno < 0){
+ if(isaconfig("usb", ctlrno, uh) == 0){
+ free(uh);
+ return nil;
+ }
+ for(cardno = 0; usbtypes[cardno].type; cardno++){
type = uh->type;
- if(type == nil || *type == '\0')
+ if(type==nil || *type==0)
type = "uhci";
- if(cistrcmp(usbtypes[n].type, type))
+ if(cistrcmp(usbtypes[cardno].type, type))
continue;
- if(usbtypes[n].reset(uh))
- break;
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(uh->irq == 2)
- uh->irq = 9;
- snprint(name, sizeof(name), "usb%d", ctlrno);
- intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name);
-
- ebuf = buf + sizeof buf;
- p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %lud", ctlrno, type, uh->port, uh->irq);
- if(uh->mem)
- p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem));
- if(uh->size)
- seprint(p, ebuf, " size 0x%luX", uh->size);
- print("%s\n", buf);
-
- usbhost[ctlrno] = uh;
- uh = nil;
break;
}
}
- if(uh != nil)
+
+ if(cardno >= MaxUsb || usbtypes[cardno].type == nil){
+ free(uh);
+ return nil;
+ }
+ if(usbtypes[cardno].reset(uh) < 0){
free(uh);
+ return nil;
+ }
+
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(uh->irq == 2)
+ uh->irq = 9;
+ snprint(name, sizeof(name), "usb%d", ctlrno);
+ intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name);
+
+ ebuf = buf + sizeof buf;
+ p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %lud", ctlrno, usbtypes[cardno].type, uh->port, uh->irq);
+ if(uh->mem)
+ p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem));
+ if(uh->size)
+ seprint(p, ebuf, " size 0x%luX", uh->size);
+ print("%s\n", buf);
+
+ return uh;
+}
+
+static void
+usbreset(void)
+{
+ int cardno, ctlrno;
+ Usbhost *uh;
+
+ for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){
+ if((uh = usbprobe(-1, ctlrno)) == nil)
+ continue;
+ usbhost[ctlrno] = uh;
+ }
+
+ cardno = ctlrno = 0;
+ while(usbtypes[cardno].type != nil && ctlrno < MaxUsb){
+ if(usbhost[ctlrno] != nil){
+ ctlrno++;
+ continue;
+ }
+ if((uh = usbprobe(cardno, ctlrno)) == nil){
+ cardno++;
+ continue;
+ }
+ usbhost[ctlrno] = uh;
+ ctlrno++;
+ }
}
void
M pc/ether2000.c => pc/ether2000.c +1 -0
@@ 29,6 29,7 @@ enum {
static int
reset(Ether* ether)
{
+ static int first;
ushort buf[16];
ulong port;
Dp8390 *ctlr;
M pc/etherelnk3.c => pc/etherelnk3.c +5 -1
@@ 1257,6 1257,7 @@ typedef struct Adapter {
int tbdf;
int did;
ulong cbfns;
+ int active;
} Adapter;
static Block* adapter;
@@ 1526,7 1527,7 @@ tcm5XXpcmcia(Ether* ether)
int i;
for(i = 0; tcmpcmcia[i] != nil; i++){
- if(!cistrcmp(ether->type, tcmpcmcia[i])){
+ if(ether->type==nil || !cistrcmp(ether->type, tcmpcmcia[i])){
/*
* No need for an ioalloc here, the 589 reset
* code deals with it.
@@ 1805,6 1806,8 @@ etherelnk3reset(Ether* ether)
bpp = &adapter;
for(bp = *bpp; bp; bp = bp->next){
ap = (Adapter*)bp->rp;
+ if(ap->active)
+ continue;
if(ether->port == 0 || ether->port == ap->port){
port = ap->port;
did = ap->did;
@@ 1813,6 1816,7 @@ etherelnk3reset(Ether* ether)
cbfns = ap->cbfns;
// *bpp = bp->next; // HIRO.
// freeb(bp);
+ ap->active = 1;
break;
}
bpp = &bp->next;
M pc/ethersink.c => pc/ethersink.c +2 -0
@@ 42,6 42,8 @@ reset(Ether* ether)
{
uchar ea[Eaddrlen];
+ if(ether->type==nil)
+ return -1;
memset(ea, 0, sizeof ea);
ether->mbps = 1000;
ether->attach = nop;
M pc/etherwavelan.c => pc/etherwavelan.c +5 -3
@@ 27,7 27,7 @@
#include "../port/netif.h"
#include "etherif.h"
-#define DEBUG if(0){}else print
+#define DEBUG if(1){}else print
#define SEEKEYS 0
@@ 479,6 479,7 @@ w_inltv(Ctlr* ctlr, Wltv* ltv)
return -1;
ltv->len = len;
if ((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
+ USED(code);
DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
return -1;
}
@@ 1384,8 1385,8 @@ wavelanpcmciareset(Ether *ether)
ether->irq=WDfltIRQ;
if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
- print("#l%d: port 0x%lx in use\n",
- ether->ctlrno, ether->port);
+ // print("#l%d: port 0x%lx in use\n",
+ // ether->ctlrno, ether->port);
goto abort1;
}
@@ 1495,6 1496,7 @@ wavelanpcireset(Ether *ether)
if(ctlr == nil)
return -1;
+ ctlr->active = 1;
ilock(ctlr);
ether->irq = ctlr->pcidev->intl;
ether->tbdf = ctlr->pcidev->tbdf;
M port/portfns.h => port/portfns.h +1 -1
@@ 149,7 149,7 @@ void ksetenv(char*, char*, int);
void kstrcpy(char*, char*, int);
void kstrdup(char**, char*);
long latin1(Rune*, int);
-void lock(Lock*);
+int lock(Lock*);
void lockinit(void);
void logopen(Log*);
void logclose(Log*);
M port/proc.c => port/proc.c +10 -2
@@ 8,6 8,8 @@
int nrdy;
Ref noteidalloc;
+long delayedscheds; /* statistics */
+
static Ref pidalloc;
static struct Procalloc
@@ 83,14 85,20 @@ schedinit(void) /* never returns */
void
sched(void)
{
- if(up) {
+ if(up){
+ if(up->state == Running && up->nlocks){
+ up->delaysched++;
+ delayedscheds++;
+ return;
+ }
+
splhi();
/* statistics */
m->cs++;
procsave(up);
- if(setlabel(&up->sched)) {
+ if(setlabel(&up->sched)){
procrestore(up);
spllo();
return;
M port/qlock.c => port/qlock.c +7 -7
@@ 19,13 19,13 @@ qlock(QLock *q)
Proc *p, *mp;
lock(&q->use);
-rwstats.qlock++;
+ rwstats.qlock++;
if(!q->locked) {
q->locked = 1;
unlock(&q->use);
return;
}
-rwstats.qlockq++;
+ rwstats.qlockq++;
p = q->tail;
mp = up;
if(mp == nil)
@@ 81,7 81,7 @@ rlock(RWlock *q)
Proc *p, *mp;
lock(&q->use);
-rwstats.rlock++;
+ rwstats.rlock++;
if(q->writer == 0 && q->head == nil){
/* no writer, go for it */
q->readers++;
@@ 89,7 89,7 @@ rwstats.rlock++;
return;
}
-rwstats.rlockq++;
+ rwstats.rlockq++;
p = q->tail;
mp = up;
if(mp == nil)
@@ 134,7 134,7 @@ wlock(RWlock *q)
Proc *p, *mp;
lock(&q->use);
-rwstats.wlock++;
+ rwstats.wlock++;
if(q->readers == 0 && q->writer == 0){
/* noone waiting, go for it */
q->wpc = getcallerpc(&q);
@@ 145,7 145,7 @@ rwstats.wlock++;
}
/* wait */
-rwstats.wlockq++;
+ rwstats.wlockq++;
p = q->tail;
mp = up;
if(mp == nil)
@@ 204,7 204,7 @@ int
canrlock(RWlock *q)
{
lock(&q->use);
-rwstats.rlock++;
+ rwstats.rlock++;
if(q->writer == 0 && q->head == nil){
/* no writer, go for it */
q->readers++;
M port/taslock.c => port/taslock.c +32 -99
@@ 5,51 5,13 @@
#include "fns.h"
#include "../port/error.h"
-struct {
+struct
+{
ulong locks;
ulong glare;
ulong inglare;
} lockstats;
-typedef struct PC {
- ulong pc;
- int count;
-} PC;
-
-PC lpcs[1024];
-
-void
-incpcref(Lock *l)
-{
- int i;
-
- for(i = 0; i < nelem(lpcs)-1; i++){
- if(lpcs[i].pc == l->pc)
- break;
- if(lpcs[i].pc == 0){
- lpcs[i].pc = l->pc;
- break;
- }
- }
- lpcs[i].count++;
-}
-
-void
-decpcref(Lock *l)
-{
- int i;
-
- for(i = 0; i < nelem(lpcs)-1; i++){
- if(lpcs[i].pc == l->pc)
- break;
- if(lpcs[i].pc == 0){
- lpcs[i].pc = l->pc;
- break;
- }
- }
- lpcs[i].count--;
-}
-
static void
dumplockmem(char *tag, Lock *l)
{
@@ 69,8 31,6 @@ lockloop(Lock *l, ulong pc)
Proc *p;
p = l->p;
-print("lock loop %p\n", l);
-delay(1000);
print("lock 0x%lux loop key 0x%lux pc 0x%lux held by pc 0x%lux proc %lud\n",
l, l->key, pc, l->pc, p ? p->pid : 0);
dumpaproc(up);
@@ 81,66 41,49 @@ delay(1000);
sched();
}
-void
+int
lock(Lock *l)
{
- int i, cansched;
- ulong pc, oldpri;
+ int i;
+ ulong pc;
pc = getcallerpc(&l);
- lockstats.locks++; /* prevent being scheded */
- if (up) up->nlocks++;
+ lockstats.locks++;
+ if(up)
+ up->nlocks++; /* prevent being scheded */
if(tas(&l->key) == 0){
if (up) up->lastlock = l;
l->pc = pc;
-// incpcref(l);
l->p = up;
l->isilock = 0;
- return;
+ return 0;
}
- if (up) up->nlocks--; /* didn't get the lock, allow scheding */
+ if(up)
+ up->nlocks--; /* didn't get the lock, allow scheding */
lockstats.glare++;
- cansched = up != nil && up->state == Running;
- if(cansched){
- oldpri = up->priority;
- up->priority = PriLock;
- up->lockwait = l;
- } else
- oldpri = 0;
-
for(;;){
lockstats.inglare++;
i = 0;
while(l->key){
- if(conf.nmach < 2 && cansched){
- if (i++ > 1000){
- i = 0;
- lockloop(l, pc);
- }
- sched();
- } else {
- if(i++ > 100000000){
- i = 0;
- lockloop(l, pc);
- }
+ if(i++ > 100000000){
+ i = 0;
+ lockloop(l, pc);
}
}
- if (up) up->nlocks++;
+ if(up)
+ up->nlocks++;
if(tas(&l->key) == 0){
- if (up) up->lastlock = l;
+ if(up)
+ up->lastlock = l;
l->pc = pc;
-// incpcref(l);
l->p = up;
l->isilock = 0;
- if(cansched){
- up->lockwait = nil;
- up->priority = oldpri;
- }
- return;
+ return 1;
}
- if (up) up->nlocks--;
+ if(up)
+ up->nlocks--;
}
}
@@ 148,15 91,15 @@ void
ilock(Lock *l)
{
ulong x;
- ulong pc, oldpri;
- int cansched;
+ ulong pc;
pc = getcallerpc(&l);
lockstats.locks++;
x = splhi();
if(tas(&l->key) == 0){
- if (up) up->lastlock = l;
+ if(up)
+ up->lastlock = l;
l->sr = x;
l->pc = pc;
l->p = up;
@@ 165,13 108,6 @@ ilock(Lock *l)
}
lockstats.glare++;
- cansched = up != nil && up->state == Running;
- if(cansched){
- oldpri = up->priority;
- up->lockwait = l;
- up->priority = PriLock;
- } else
- oldpri = 0;
if(conf.nmach < 2){
dumplockmem("ilock:", l);
panic("ilock: no way out: pc %luX\n", pc);
@@ 189,10 125,6 @@ ilock(Lock *l)
l->pc = pc;
l->p = up;
l->isilock = 1;
- if(cansched){
- up->lockwait = nil;
- up->priority = oldpri;
- }
return;
}
}
@@ 201,15 133,17 @@ ilock(Lock *l)
int
canlock(Lock *l)
{
- if (up) up->nlocks++;
+ if(up)
+ up->nlocks++;
if(tas(&l->key)){
- if (up) up->nlocks--;
+ if(up)
+ up->nlocks--;
return 0;
}
- if (up) up->lastlock = l;
+ if(up)
+ up->lastlock = l;
l->pc = getcallerpc(&l);
-// incpcref(l);
l->p = up;
l->isilock = 0;
return 1;
@@ 224,8 158,7 @@ unlock(Lock *l)
print("unlock of ilock: pc %lux, held by %lux\n", getcallerpc(&l), l->pc);
if(l->p != up)
print("unlock: up changed: pc %lux, acquired at pc %lux, lock p 0x%p, unlock up 0x%p\n", getcallerpc(&l), l->pc, l->p, up);
-// decpcref(l);
- l->pc = 0;
+ l->pc = ~0;
l->key = 0;
if (up && --up->nlocks == 0 && up->delaysched){
up->delaysched = 0;
@@ 245,7 178,7 @@ iunlock(Lock *l)
print("iunlock of lock: pc %lux, held by %lux\n", getcallerpc(&l), l->pc);
sr = l->sr;
- l->pc = 0;
+ l->pc = ~1;
l->key = 0;
coherence();