plan 9 kernel history: overview | file list | diff list

2002/0217/pc/main.c (diff list | history)

2002/0217/sys/src/9/pc/main.c:1,7402002/0323/sys/src/9/pc/main.c:1,743 (short | long | prev | next)
1991/0702    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0706    
#include	"mem.h" 
1991/0702    
#include	"dat.h" 
#include	"fns.h" 
1991/0706    
#include	"io.h" 
1991/0716    
#include	"ureg.h" 
#include	"init.h" 
1997/1101    
#include	"pool.h" 
2002/0109    
#include	"reboot.h" 
1991/0629    
 
1997/0327    
Mach *m; 
1992/0904    
 
1997/0327    
/* 
 * Where configuration info is left for the loaded programme. 
 * This will turn into a structure as more is done by the boot loader 
 * (e.g. why parse the .ini file twice?). 
2002/0109    
 * There are 3584 bytes available at CONFADDR. 
1997/0327    
 */ 
1997/0329    
#define BOOTLINE	((char*)CONFADDR) 
1997/0327    
#define BOOTLINELEN	64 
#define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN)) 
2000/0721    
#define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN) 
2002/0109    
#define	MAXCONF		64 
1993/0330    
 
2001/0527    
char bootdisk[KNAMELEN]; 
2002/0109    
Conf	conf; 
1993/0330    
char *confname[MAXCONF]; 
char *confval[MAXCONF]; 
int nconf; 
2002/0109    
uchar	*sp;	/* user stack of init proc */ 
1993/0330    
 
1997/0327    
static void 
1997/0403    
options(void) 
1997/0327    
{ 
1997/0403    
	long i, n; 
	char *cp, *line[MAXCONF], *p, *q; 
1997/0327    
 
1997/0403    
	/* 
	 *  parse configuration args from dos file plan9.ini 
	 */ 
	cp = BOOTARGS;	/* where b.com leaves its config */ 
	cp[BOOTARGSLEN-1] = 0; 
 
	/* 
	 * Strip out '\r', change '\t' -> ' '. 
	 */ 
	p = cp; 
	for(q = cp; *q; q++){ 
		if(*q == '\r') 
			continue; 
		if(*q == '\t') 
			*q = ' '; 
		*p++ = *q; 
	} 
	*p = 0; 
 
2001/0527    
	n = getfields(cp, line, MAXCONF, 1, "\n"); 
1997/0403    
	for(i = 0; i < n; i++){ 
		if(*line[i] == '#') 
			continue; 
		cp = strchr(line[i], '='); 
2001/0527    
		if(cp == nil) 
1997/0403    
			continue; 
2001/0527    
		*cp++ = '\0'; 
1997/0403    
		confname[nconf] = line[i]; 
		confval[nconf] = cp; 
		nconf++; 
	} 
1997/0327    
} 
 
1991/0716    
void 
1991/0702    
main(void) 
1991/0625    
{ 
2002/0109    
	mach0init(); 
1997/0403    
	options(); 
2001/0527    
	ioinit(); 
	i8250console(); 
2002/0217    
	quotefmtinstall(); 
2002/0109    
 
2001/0527    
	print("\nPlan 9\n"); 
2002/0109    
 
1997/0327    
	cpuidentify(); 
2001/0527    
	screeninit(); 
2002/0109    
	meminit(); 
1991/0711    
	confinit(); 
1997/0329    
	archinit(); 
1992/0625    
	xinit(); 
1997/0327    
	trapinit(); 
1991/0716    
	printinit(); 
1997/0522    
	cpuidprint(); 
1997/0327    
	mmuinit(); 
	if(arch->intrinit) 
		arch->intrinit(); 
1991/0906    
	mathinit(); 
1992/0409    
	kbdinit(); 
1997/0327    
	if(arch->clockenable) 
		arch->clockenable(); 
1991/0716    
	procinit0(); 
	initseg(); 
1995/0329    
	links(); 
1997/1101    
conf.monitor = 1; 
1991/0716    
	chandevreset(); 
1999/0422    
	pageinit(); 
1991/0716    
	swapinit(); 
	userinit(); 
	schedinit(); 
1991/0712    
} 
1991/0706    
 
1991/0716    
void 
2002/0109    
mach0init(void) 
{ 
	conf.nmach = 1; 
	MACHP(0) = (Mach*)CPU0MACH; 
	m->pdb = (ulong*)CPU0PDB; 
 
	machinit(); 
 
	active.machs = 1; 
	active.exiting = 0; 
} 
 
void 
1991/0716    
machinit(void) 
1991/0712    
{ 
1997/0327    
	int machno; 
1997/1101    
	ulong *pdb; 
1991/0712    
 
1997/0327    
	machno = m->machno; 
	pdb = m->pdb; 
1991/0716    
	memset(m, 0, sizeof(Mach)); 
1997/0327    
	m->machno = machno; 
	m->pdb = pdb; 
2001/0527    
 
	/* 
	 * For polled uart output at boot, need 
	 * a default delay constant. 100000 should 
	 * be enough for a while. Cpuidentify will 
	 * calculate the real value later. 
	 */ 
	m->loopconst = 100000; 
1991/0625    
} 
 
1991/0716    
void 
init0(void) 
1991/0712    
{ 
1993/0330    
	int i; 
2002/0109    
	char buf[2*KNAMELEN]; 
1992/0918    
 
1993/0915    
	up->nerrlab = 0; 
1991/0712    
 
1991/0720    
	spllo(); 
 
1991/0716    
	/* 
	 * These are o.k. because rootinit is null. 
	 * Then early kproc's will have a root and dot. 
	 */ 
1993/0915    
	up->slash = namec("#/", Atodir, 0, 0); 
1999/0629    
	cnameclose(up->slash->name); 
	up->slash->name = newcname("/"); 
2001/0527    
	up->dot = cclone(up->slash); 
1991/0712    
 
1991/0716    
	chandevinit(); 
 
1991/0926    
	if(!waserror()){ 
2002/0109    
		snprint(buf, sizeof(buf), "%s %s", arch->id, conffile); 
		ksetenv("terminal", buf, 0); 
		ksetenv("cputype", "386", 0); 
1997/0329    
		if(cpuserver) 
2002/0109    
			ksetenv("service", "cpu", 0); 
1997/0329    
		else 
2002/0109    
			ksetenv("service", "terminal", 0); 
1993/0915    
		for(i = 0; i < nconf; i++) 
2002/0323    
		for(i = 0; i < nconf; i++){ 
			if(confname[i][0] != '*') 
				ksetenv(confname[i], confval[i], 0); 
2002/0109    
			ksetenv(confname[i], confval[i], 1); 
2002/0323    
		} 
1991/0926    
		poperror(); 
	} 
1993/0915    
	kproc("alarm", alarmkproc, 0); 
1992/0323    
	touser(sp); 
1991/0712    
} 
 
1991/0629    
void 
1991/0716    
userinit(void) 
1991/0711    
{ 
1991/0716    
	Proc *p; 
	Segment *s; 
	KMap *k; 
1992/0323    
	Page *pg; 
1991/0905    
 
1991/0716    
	p = newproc(); 
	p->pgrp = newpgrp(); 
1992/0625    
	p->egrp = smalloc(sizeof(Egrp)); 
	p->egrp->ref = 1; 
1997/0606    
	p->fgrp = dupfgrp(nil); 
1994/0812    
	p->rgrp = newrgrp(); 
1991/1112    
	p->procmode = 0640; 
1991/0716    
 
2001/0527    
	kstrdup(&eve, ""); 
	kstrdup(&p->text, "*init*"); 
	kstrdup(&p->user, eve); 
 
1991/0716    
	p->fpstate = FPinit; 
1991/0906    
	fpoff(); 
1991/0716    
 
	/* 
	 * Kernel Stack 
1991/0717    
	 * 
2000/1012    
	 * N.B. make sure there's enough space for syscall to check 
	 *	for valid args and  
1991/0719    
	 *	4 bytes for gotolabel's return PC 
1991/0716    
	 */ 
	p->sched.pc = (ulong)init0; 
2000/1012    
	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); 
1991/0716    
 
	/* 
	 * User Stack 
	 */ 
1993/0915    
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); 
1991/0716    
	p->seg[SSEG] = s; 
1992/0323    
	pg = newpage(1, 0, USTKTOP-BY2PG); 
	segpage(s, pg); 
	k = kmap(pg); 
	bootargs(VA(k)); 
	kunmap(k); 
1991/0716    
 
	/* 
	 * Text 
	 */ 
	s = newseg(SG_TEXT, UTZERO, 1); 
1993/0915    
	s->flushme++; 
1991/0716    
	p->seg[TSEG] = s; 
1993/0915    
	pg = newpage(1, 0, UTZERO); 
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 
	segpage(s, pg); 
1991/0716    
	k = kmap(s->map[0]->pages[0]); 
	memmove((ulong*)VA(k), initcode, sizeof initcode); 
	kunmap(k); 
 
	ready(p); 
1992/0323    
} 
 
uchar * 
pusharg(char *p) 
{ 
	int n; 
 
	n = strlen(p)+1; 
	sp -= n; 
	memmove(sp, p, n); 
	return sp; 
} 
 
void 
bootargs(ulong base) 
{ 
 	int i, ac; 
	uchar *av[32]; 
	uchar **lsp; 
1992/0903    
	char *cp = BOOTLINE; 
	char buf[64]; 
1992/0323    
 
	sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD; 
 
	ac = 0; 
1994/0219    
	av[ac++] = pusharg("/386/9dos"); 
2002/0109    
 
	/* when boot is changed to only use rc, this code can go away */ 
1997/0327    
	cp[BOOTLINELEN-1] = 0; 
1993/0915    
	buf[0] = 0; 
2000/0518    
	if(strncmp(cp, "fd", 2) == 0){ 
		sprint(buf, "local!#f/fd%lddisk", strtol(cp+2, 0, 0)); 
1992/0903    
		av[ac++] = pusharg(buf); 
2000/0518    
	} else if(strncmp(cp, "sd", 2) == 0){ 
		sprint(buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3)); 
1993/0915    
		av[ac++] = pusharg(buf); 
2000/0531    
	} else if(strncmp(cp, "ether", 5) == 0) 
1994/1111    
		av[ac++] = pusharg("-n"); 
1992/0323    
 
	/* 4 byte word align stack */ 
	sp = (uchar*)((ulong)sp & ~3); 
 
	/* build argc, argv on stack */ 
	sp -= (ac+1)*sizeof(sp); 
	lsp = (uchar**)sp; 
	for(i = 0; i < ac; i++) 
		*lsp++ = av[i] + ((USTKTOP - BY2PG) - base); 
	*lsp = 0; 
	sp += (USTKTOP - BY2PG) - base - sizeof(ulong); 
1991/0711    
} 
 
1993/0915    
char* 
getconf(char *name) 
{ 
	int i; 
 
	for(i = 0; i < nconf; i++) 
1997/0403    
		if(cistrcmp(confname[i], name) == 0) 
1993/0915    
			return confval[i]; 
	return 0; 
} 
 
2002/0109    
static void 
writeconf(void) 
{ 
	char *p, *q; 
	int n; 
 
	p = getconfenv(); 
 
	if(waserror()) { 
		free(p); 
		nexterror(); 
	} 
 
	/* convert to name=value\n format */ 
	for(q=p; *q; q++) { 
		q += strlen(q); 
		*q = '='; 
		q += strlen(q); 
		*q = '\n'; 
	} 
	n = q - p + 1; 
	if(n >= BOOTARGSLEN) 
		error("kernel configuration too large"); 
	memset(BOOTLINE, 0, BOOTLINELEN); 
	memmove(BOOTARGS, p, n); 
	poperror(); 
	free(p); 
} 
 
1994/1210    
void 
1991/0711    
confinit(void) 
{ 
1997/0403    
	char *p; 
1999/1109    
	int userpcnt; 
2002/0109    
	ulong kpages; 
1991/0711    
 
1997/0403    
	if(p = getconf("*kernelpercent")) 
1998/1120    
		userpcnt = 100 - strtol(p, 0, 0); 
1997/0403    
	else 
1998/1120    
		userpcnt = 0; 
1994/0814    
 
1991/0711    
	conf.npage = conf.npage0 + conf.npage1; 
1998/1124    
 
	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; 
	if(cpuserver) 
		conf.nproc *= 3; 
	if(conf.nproc > 2000) 
		conf.nproc = 2000; 
	conf.nimage = 200; 
	conf.nswap = conf.nproc*80; 
	conf.nswppo = 4096; 
 
1997/1101    
	if(cpuserver) { 
1998/1120    
		if(userpcnt < 10) 
			userpcnt = 70; 
		kpages = conf.npage - (conf.npage*userpcnt)/100; 
 
		/* 
		 * Hack for the big boys. Only good while physmem < 4GB. 
2000/0609    
		 * Give the kernel fixed max + enough to allocate the 
1998/1120    
		 * page pool. 
		 * This is an overestimate as conf.upages < conf.npages. 
1998/1124    
		 * The patch of nimage is a band-aid, scanning the whole 
		 * page list in imagereclaim just takes too long. 
1998/1120    
		 */ 
2001/1011    
		if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){ 
			kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG; 
1998/1124    
			conf.nimage = 2000; 
1999/0709    
			kpages += (conf.nproc*KSTACK)/BY2PG; 
1998/1124    
		} 
1997/1101    
	} else { 
1998/1120    
		if(userpcnt < 10) { 
1997/1101    
			if(conf.npage*BY2PG < 16*MB) 
1998/1120    
				userpcnt = 40; 
1997/1101    
			else 
1998/1120    
				userpcnt = 60; 
1997/1101    
		} 
1998/1120    
		kpages = conf.npage - (conf.npage*userpcnt)/100; 
 
1998/0420    
		/* 
		 * Make sure terminals with low memory get at least 
		 * 4MB on the first Image chunk allocation. 
		 */ 
1997/1101    
		if(conf.npage*BY2PG < 16*MB) 
1999/0714    
			imagmem->minarena = 4*1024*1024; 
1997/1101    
	} 
1998/1120    
	conf.upages = conf.npage - kpages; 
1998/1124    
	conf.ialloc = (kpages/2)*BY2PG; 
1998/1120    
 
	/* 
	 * Guess how much is taken by the large permanent 
	 * datastructures. Mntcache and Mntrpc are not accounted for 
	 * (probably ~300KB). 
	 */ 
	kpages *= BY2PG; 
	kpages -= conf.upages*sizeof(Page) 
		+ conf.nproc*sizeof(Proc) 
		+ conf.nimage*sizeof(Image) 
		+ conf.nswap 
		+ conf.nswppo*sizeof(Page); 
1999/0714    
	mainmem->maxsize = kpages; 
1998/1120    
	if(!cpuserver){ 
		/* 
		 * give terminals lots of image memory, too; the dynamic 
		 * allocation will balance the load properly, hopefully. 
		 * be careful with 32-bit overflow. 
		 */ 
1999/0714    
		imagmem->maxsize = kpages; 
1998/1120    
	} 
1991/0711    
} 
 
1998/0910    
static char* mathmsg[] = 
1991/0906    
{ 
1991/0913    
	"invalid", 
	"denormalized", 
	"div-by-zero", 
	"overflow", 
	"underflow", 
	"precision", 
	"stack", 
	"error", 
}; 
1991/0906    
 
1998/0916    
static void 
mathnote(void) 
{ 
	int i; 
	ulong status; 
2001/0527    
	char *msg, note[ERRMAX]; 
1998/0916    
 
	status = up->fpsave.status; 
 
	/* 
	 * Some attention should probably be paid here to the 
	 * exception masks and error summary. 
	 */ 
	msg = "unknown"; 
	for(i = 0; i < 8; i++){ 
		if(!((1<<i) & status)) 
			continue; 
		msg = mathmsg[i]; 
		break; 
	} 
	sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->fpsave.pc); 
	postnote(up, 1, note, NDebug); 
} 
 
1991/0906    
/* 
1991/0912    
 *  math coprocessor error 
 */ 
1998/0910    
static void 
1997/0327    
matherror(Ureg *ur, void*) 
1991/0912    
{ 
1991/0913    
	/* 
	 *  a write cycle to port 0xF0 clears the interrupt latch attached 
	 *  to the error# line from the 387 
	 */ 
1998/0916    
	if(!(m->cpuiddx & 0x01)) 
		outb(0xF0, 0xFF); 
1991/0913    
 
1992/0806    
	/* 
	 *  save floating point state to check out error 
	 */ 
1993/0915    
	fpenv(&up->fpsave); 
1998/0916    
	mathnote(); 
1992/0806    
 
	if(ur->pc & KZERO) 
2002/0114    
		panic("fp: status %ux fppc=0x%lux pc=0x%lux", 
1998/0916    
			up->fpsave.status, up->fpsave.pc, ur->pc); 
1991/0912    
} 
 
/* 
1991/0906    
 *  math coprocessor emulation fault 
 */ 
1998/0910    
static void 
1997/0327    
mathemu(Ureg*, void*) 
1991/0906    
{ 
1993/0915    
	switch(up->fpstate){ 
1991/0906    
	case FPinit: 
		fpinit(); 
1993/0915    
		up->fpstate = FPactive; 
1991/0906    
		break; 
	case FPinactive: 
1998/0916    
		/* 
		 * Before restoring the state, check for any pending 
		 * exceptions, there's no way to restore the state without 
		 * generating an unmasked exception. 
		 * More attention should probably be paid here to the 
		 * exception masks and error summary. 
		 */ 
		if((up->fpsave.status & ~up->fpsave.control) & 0x07F){ 
			mathnote(); 
			break; 
		} 
1993/0915    
		fprestore(&up->fpsave); 
		up->fpstate = FPactive; 
1991/0906    
		break; 
	case FPactive: 
2002/0114    
		panic("math emu"); 
1991/0906    
		break; 
	} 
} 
 
/* 
 *  math coprocessor segment overrun 
 */ 
1998/0910    
static void 
1997/0327    
mathover(Ureg*, void*) 
1991/0906    
{ 
1992/0805    
	pexit("math overrun", 0); 
1991/0906    
} 
 
void 
mathinit(void) 
{ 
1999/0819    
	trapenable(VectorCERR, matherror, 0, "matherror"); 
1997/0327    
	if(X86FAMILY(m->cpuidax) == 3) 
1999/0819    
		intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror"); 
	trapenable(VectorCNA, mathemu, 0, "mathemu"); 
	trapenable(VectorCSO, mathover, 0, "mathover"); 
1991/0906    
} 
 
/* 
1991/0716    
 *  set up floating point for a new process 
 */ 
1991/0703    
void 
1991/0716    
procsetup(Proc *p) 
1991/0703    
{ 
1991/0716    
	p->fpstate = FPinit; 
1991/0906    
	fpoff(); 
1991/0705    
} 
 
1991/0712    
/* 
1991/0906    
 *  Save the mach dependent part of the process state. 
1991/0712    
 */ 
1991/0705    
void 
1992/0122    
procsave(Proc *p) 
1991/0705    
{ 
1992/0805    
	if(p->fpstate == FPactive){ 
		if(p->state == Moribund) 
			fpoff(); 
1998/0916    
		else{ 
			/* 
			 * Fpsave() stores without handling pending 
			 * unmasked exeptions. Postnote() can't be called 
			 * here as sleep() already has up->rlock, so 
			 * the handling of pending exceptions is delayed 
			 * until the process runs again and generates an 
			 * emulation fault to activate the FPU. 
			 */ 
1993/0915    
			fpsave(&up->fpsave); 
1998/0916    
		} 
1992/0805    
		p->fpstate = FPinactive; 
1991/0906    
	} 
1998/0605    
 
	/* 
	 * Switch to the prototype page tables for this processor. 
	 * While this processor is in the scheduler, the process could run 
	 * on another processor and exit, returning the page tables to 
	 * the free list where they could be reallocated and overwritten. 
	 * When this processor eventually has to get an entry from the 
	 * trashed page tables it will crash. 
	 */ 
	mmuflushtlb(PADDR(m->pdb)); 
1991/0712    
} 
 
2002/0109    
static void 
shutdown(int ispanic) 
1991/0712    
{ 
1997/0327    
	int ms, once; 
1991/0712    
 
1997/0327    
	lock(&active); 
	if(ispanic) 
		active.ispanic = ispanic; 
	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) 
		active.ispanic = 0; 
	once = active.machs & (1<<m->machno); 
	active.machs &= ~(1<<m->machno); 
	active.exiting = 1; 
	unlock(&active); 
1991/0803    
 
1997/0327    
	if(once) 
		print("cpu%d: exiting\n", m->machno); 
1996/01171    
	spllo(); 
1997/0327    
	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ 
		delay(TK2MS(2)); 
		if(active.machs == 0 && consactive() == 0) 
			break; 
	} 
 
	if(active.ispanic && m->machno == 0){ 
1993/1113    
		if(cpuserver) 
1993/0915    
			delay(10000); 
		else 
			for(;;); 
1997/0327    
	} 
	else 
1996/01171    
		delay(1000); 
2002/0109    
} 
1992/0903    
 
2002/0109    
void 
reboot(void *entry, void *code, ulong size) 
{ 
	void (*f)(ulong, ulong, ulong); 
	ulong *pdb; 
 
	writeconf(); 
 
	shutdown(0); 
 
	/* 
	 * should be the only processor running now 
	 */ 
 
	print("shutting down...\n"); 
	delay(200); 
 
	splhi(); 
 
	/* turn off buffered serial console */ 
	serialoq = nil; 
 
	/* shutdown devices */ 
	chandevshutdown(); 
 
	/* 
	 * Modify the machine page table to directly map the low 4MB of memory 
	 * This allows the reboot code to turn off the page mapping 
	 */ 
	pdb = m->pdb; 
	pdb[PDX(0)] = pdb[PDX(KZERO)]; 
	mmuflushtlb(PADDR(pdb)); 
 
	/* setup reboot trampoline function */ 
	f = (void*)REBOOTADDR; 
	memmove(f, rebootcode, sizeof(rebootcode)); 
 
	print("rebooting...\n"); 
 
	/* off we go - never to return */ 
	(*f)(PADDR(entry), PADDR(code), size); 
} 
 
 
void 
exit(int ispanic) 
{ 
	shutdown(ispanic); 
1997/0327    
	arch->reset(); 
1991/0803    
} 
 
1991/1210    
int 
1993/0915    
isaconfig(char *class, int ctlrno, ISAConf *isa) 
{ 
2001/0527    
	char cc[32], *p; 
2002/0109    
	int i; 
1993/0915    
 
2001/0527    
	snprint(cc, sizeof cc, "%s%d", class, ctlrno); 
2002/0109    
	p = getconf(cc); 
	if(p == nil) 
		return 0; 
 
	isa->nopt = tokenize(p, isa->opt, NISAOPT); 
	for(i = 0; i < isa->nopt; i++){ 
		p = isa->opt[i]; 
		if(cistrncmp(p, "type=", 5) == 0) 
			isa->type = p + 5; 
		else if(cistrncmp(p, "port=", 5) == 0) 
			isa->port = strtoul(p+5, &p, 0); 
		else if(cistrncmp(p, "irq=", 4) == 0) 
			isa->irq = strtoul(p+4, &p, 0); 
		else if(cistrncmp(p, "dma=", 4) == 0) 
			isa->dma = strtoul(p+4, &p, 0); 
		else if(cistrncmp(p, "mem=", 4) == 0) 
			isa->mem = strtoul(p+4, &p, 0); 
		else if(cistrncmp(p, "size=", 5) == 0) 
			isa->size = strtoul(p+5, &p, 0); 
		else if(cistrncmp(p, "freq=", 5) == 0) 
			isa->freq = strtoul(p+5, &p, 0); 
1993/0915    
	} 
2002/0109    
	return 1; 
1991/0803    
} 
1995/0222    
 
int 
cistrcmp(char *a, char *b) 
{ 
	int ac, bc; 
 
	for(;;){ 
		ac = *a++; 
		bc = *b++; 
	 
		if(ac >= 'A' && ac <= 'Z') 
			ac = 'a' + (ac - 'A'); 
		if(bc >= 'A' && bc <= 'Z') 
			bc = 'a' + (bc - 'A'); 
		ac -= bc; 
		if(ac) 
			return ac; 
		if(bc == 0) 
			break; 
	} 
1997/0327    
	return 0; 
} 
 
int 
cistrncmp(char *a, char *b, int n) 
{ 
	unsigned ac, bc; 
 
	while(n > 0){ 
		ac = *a++; 
		bc = *b++; 
		n--; 
 
		if(ac >= 'A' && ac <= 'Z') 
			ac = 'a' + (ac - 'A'); 
		if(bc >= 'A' && bc <= 'Z') 
			bc = 'a' + (bc - 'A'); 
 
		ac -= bc; 
		if(ac) 
			return ac; 
		if(bc == 0) 
			break; 
	} 
 
1995/0222    
	return 0; 
} 
2001/0123    
 
/* 
 *  put the processor in the halt state if we've no processes to run. 
 *  an interrupt will get us going again. 
 */ 
void 
idlehands(void) 
{ 
	if(conf.nmach == 1) 
		halt(); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)