~kris/9p

9hist

0289f300ccd00390a42785f28b2bfc0cfcab1732 — David du Colombier 24 years ago 72933d0
Plan 9 from Bell Labs 2002-04-03
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, &ether->opt[i][3]) == -1)
				if(parseether(ether->ea, &ether->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();