Beispiel #1
0
/*
 *  a write to a closed pipe causes a note to be sent to
 *  the process.
 */
static long
pipewrite(Chan *c, void *va, long n, vlong)
{
	Pipe *p;

	if(!islo())
		print("pipewrite hi %#p\n", getcallerpc(&c));
	if(waserror()) {
		/* avoid notes when pipe is a mounted queue */
		if((c->flag & CMSG) == 0)
			postnote(up, 1, "sys: write on closed pipe", NUser);
		nexterror();
	}

	p = c->aux;

	switch(NETTYPE(c->qid.path)){
	case Qdata0:
		n = qwrite(p->q[1], va, n);
		break;

	case Qdata1:
		n = qwrite(p->q[0], va, n);
		break;

	default:
		panic("pipewrite");
	}

	poperror();
	return n;
}
Beispiel #2
0
/*
 *  write to a queue.  only Maxatomic bytes at a time is atomic.
 */
int
qwrite(Queue *q, void *vp, int len)
{
	int n, sofar;
	Block *b;
	uchar *p = vp;

	QDEBUG if(!islo())
		print("qwrite hi %#p\n", getcallerpc(&q));

	sofar = 0;
	do {
		n = len-sofar;
		if(n > Maxatomic)
			n = Maxatomic;

		b = allocb(n);
		setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
		if(waserror()){
			freeb(b);
			nexterror();
		}
		memmove(b->wp, p+sofar, n);
		poperror();
		b->wp += n;

		qbwrite(q, b);

		sofar += n;
	} while(sofar < len && (q->state & Qmsg) == 0);

	return len;
}
Beispiel #3
0
static void
myscreenputs(char *s, int n)
{
	int i;
	Rune r;
	char buf[4];

	if(!islo()) {
		/* don't deadlock trying to print in interrupt */
		if(!canlock(&screenlock))
			return;	
	}
	else
		lock(&screenlock);

	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		screenputc(buf);
	}
	unlock(&screenlock);
}
Beispiel #4
0
/*
 *  a write to a closed pipe causes a note to be sent to
 *  the process.
 */
static int32_t
pipewrite(Chan *c, void *va, int32_t n, int64_t mm)
{
	Proc *up = externup();
	Pipe *p;

	if(0)if(!islo())
		print("pipewrite hi %#p\n", getcallerpc()); // devmnt?

	if(waserror()) {
		/* avoid notes when pipe is a mounted queue */
		if((c->flag & CMSG) == 0)
			postnote(up, 1, "sys: write on closed pipe", NUser);
		nexterror();
	}

	p = c->aux;

	switch(PIPETYPE(c->qid.path)){
	case Qdata0:
		n = qwrite(p->q[1], va, n);
		break;

	case Qdata1:
		n = qwrite(p->q[0], va, n);
		break;

	default:
		panic("pipewrite");
	}

	poperror();
	return n;
}
Beispiel #5
0
void
idlehands(void)
{
	char *msgb = "idlehands called with splhi\n";
	char *msga = "doze returns with splhi\n";

	if(!islo()){
		uartputs(msga, strlen(msga));
		spllo();
	}
	doze();
	if(!islo()){
		uartputs(msgb, strlen(msgb));
		spllo();
	}
}
Beispiel #6
0
void
iunlock(Lock *l)
{
	ulong sr;

#ifdef LOCKCYCLES
	l->lockcycles += lcycles();
	cumilockcycles += l->lockcycles;
	if(l->lockcycles > maxilockcycles){
		maxilockcycles = l->lockcycles;
		maxilockpc = l->pc;
	}
	if(l->lockcycles > 2400)
		ilockpcs[n++ & 0xff]  = l->pc;
#endif
	if(l->key == 0)
		print("iunlock: not locked: pc %#p\n", getcallerpc(&l));
	if(!l->isilock)
		print("iunlock of lock: pc %#p, held by %#lux\n", getcallerpc(&l), l->pc);
	if(islo())
		print("iunlock while lo: pc %#p, held by %#lux\n", getcallerpc(&l), l->pc);

	sr = l->sr;
	l->m = nil;
	coherence();
	l->key = 0;
	coherence();
	m->ilockdepth--;
	if(up)
		up->lastilock = nil;
	splx(sr);
}
Beispiel #7
0
void
unlock(Lock *l)
{
	Proc *up = externup();
	uint64_t x;

	if(LOCKCYCLES){
		cycles(&x);
		l->lockcycles = x - l->lockcycles;
		if(l->lockcycles > maxlockcycles){
			maxlockcycles = l->lockcycles;
			maxlockpc = l->_pc;
		}
	}

	if(l->key == 0)
		print("unlock: not locked: pc %#p\n", getcallerpc());
	if(l->isilock)
		print("unlock of ilock: pc %#p, held by %#p\n", getcallerpc(), l->_pc);
	if(l->p != up)
		print("unlock: up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n", getcallerpc(), l->_pc, l->p, up);
	l->m = nil;
	l->key = 0;
	coherence();

	if(up && adec(&up->nlocks) == 0 && up->delaysched && islo()){
		/*
		 * Call sched if the need arose while locks were held
		 * But, don't do it from interrupt routines, hence the islo() test
		 */
		sched();
	}
}
Beispiel #8
0
void
unlock(Lock *l)
{
#ifdef LOCKCYCLES
	l->lockcycles += lcycles();
	cumlockcycles += l->lockcycles;
	if(l->lockcycles > maxlockcycles){
		maxlockcycles = l->lockcycles;
		maxlockpc = l->pc;
	}
#endif
	if(l->key == 0)
		print("unlock: not locked: pc %#p\n", getcallerpc(&l));
	if(l->isilock)
		print("unlock of ilock: pc %lux, held by %lux\n", getcallerpc(&l), l->pc);
	if(l->p != up)
		print("unlock: up changed: pc %#p, acquired at pc %lux, lock p %#p, unlock up %#p\n", getcallerpc(&l), l->pc, l->p, up);
	l->m = nil;
	coherence();
	l->key = 0;
	coherence();

	if(up && deccnt(&up->nlocks) == 0 && up->delaysched && islo()){
		/*
		 * Call sched if the need arose while locks were held
		 * But, don't do it from interrupt routines, hence the islo() test
		 */
		sched();
	}
}
Beispiel #9
0
/*
 *   Print a string on the console.  Convert \n to \r\n for serial
 *   line consoles.  Locking of the queues is left up to the screen
 *   or uart code.  Multi-line messages to serial consoles may get
 *   interspersed with other messages.
 */
static void
putstrn0(char *str, int n, int usewrite)
{

	if(!islo())
		usewrite = 0;

	/*
	 *  how many different output devices do we need?
	 */
	kmesgputs(str, n);

	/*
	 *  if someone is reading /dev/kprint,
	 *  put the message there.
	 *  if not and there's an attached bit mapped display,
	 *  put the message there.
	 *
	 *  if there's a serial line being used as a console,
	 *  put the message there.
	 */
	if(kprintoq != nil && !qisclosed(kprintoq)){
		if(usewrite)
			qwrite(kprintoq, str, n);
		else
			qiwrite(kprintoq, str, n);
	}else if(screenputs != nil)
		screenputs(str, n);

	uartputs(str, n);
#if 0 // Plan 9 VX
	if(serialoq == nil){
		uartputs(str, n);
		return;
	}

	while(n > 0) {
		t = memchr(str, '\n', n);
		if(t && !kbd.raw) {
			m = t-str;
			if(usewrite){
				qwrite(serialoq, str, m);
				qwrite(serialoq, "\r\n", 2);
			} else {
				qiwrite(serialoq, str, m);
				qiwrite(serialoq, "\r\n", 2);
			}
			n -= m+1;
			str = t+1;
		} else {
			if(usewrite)
				qwrite(serialoq, str, n);
			else
				qiwrite(serialoq, str, n);
			break;
		}
	}
#endif
}
Beispiel #10
0
void
qlock(QLock *q)
{
	Proc *up = externup();
	Proc *p;
	uint64_t t0;

	cycles(&t0);

	if(!islo() && machp()->ilockdepth != 0){
		print("qlock with ilockdepth %d,", machp()->ilockdepth);
		stacksnippet();
	}

	if(up != nil && up->nlocks)
		print("qlock: %#p: nlocks %d", getcallerpc(&q), up->nlocks);

	if(!canlock(&q->use)){
		lock(&q->use);
		slockstat(getcallerpc(&q), t0);
	}
	qlockstats.qlock++;
	if(!q->locked) {
		q->locked = 1;
		q->pc = getcallerpc(&q);
		unlock(&q->use);
		return;
	}
	if(up == nil)
		panic("qlock");
	qlockstats.qlockq++;
	p = q->tail;
	if(p == 0)
		q->head = up;
	else
		p->qnext = up;
	q->tail = up;
	up->qnext = 0;
	up->state = Queueing;
	up->qpc = getcallerpc(&q);
	if(up->trace)
		proctrace(up, SLock, 0);
	unlock(&q->use);
	sched();
	lockstat(getcallerpc(&q), t0);
}
Beispiel #11
0
/*
 *  write to a queue.  only Maxatomic bytes at a time is atomic.
 */
int qwrite(struct queue *q, void *vp, int len)
{
	int n, sofar;
	struct block *b;
	uint8_t *p = vp;
	void *ext_buf;

	QDEBUG if (!islo())
		 printd("qwrite hi %p\n", getcallerpc(&q));

	sofar = 0;
	do {
		n = len - sofar;
		/* This is 64K, the max amount per single block.  Still a good value? */
		if (n > Maxatomic)
			n = Maxatomic;

		/* If n is small, we don't need to bother with the extra_data.  But
		 * until the whole stack can handle extd blocks, we'll use them
		 * unconditionally. */
#ifdef CONFIG_BLOCK_EXTRAS
		/* allocb builds in 128 bytes of header space to all blocks, but this is
		 * only available via padblock (to the left).  we also need some space
		 * for pullupblock for some basic headers (like icmp) that get written
		 * in directly */
		b = allocb(64);
		ext_buf = kmalloc(n, 0);
		memcpy(ext_buf, p + sofar, n);
		block_add_extd(b, 1, KMALLOC_WAIT); /* returns 0 on success */
		b->extra_data[0].base = (uintptr_t)ext_buf;
		b->extra_data[0].off = 0;
		b->extra_data[0].len = n;
		b->extra_len += n;
#else
		b = allocb(n);
		memmove(b->wp, p + sofar, n);
		b->wp += n;
#endif
			
		qbwrite(q, b);

		sofar += n;
	} while (sofar < len && (q->state & Qmsg) == 0);

	return len;
}
Beispiel #12
0
/*
 *  write to a queue.  only Maxatomic bytes at a time is atomic.
 */
int
qwrite(Queue *q, void *vp, int len)
{
	int n, sofar;
	Block *b;
	uchar *p = vp;

	QDEBUG if(!islo())
		print("qwrite hi %#p\n", getcallerpc(&q));

	/* stop queue bloat before allocating blocks */
	if(q->len/2 >= q->limit && q->noblock == 0 && q->bypass == nil){
		while(waserror()){
			if(up->procctl == Proc_exitme || up->procctl == Proc_exitbig)
				error(Egreg);
		}
		qflow(q);
		poperror();
	}

	sofar = 0;
	do {
		n = len-sofar;
		if(n > Maxatomic)
			n = Maxatomic;

		b = allocb(n);
		setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
		if(waserror()){
			freeb(b);
			nexterror();
		}
		memmove(b->wp, p+sofar, n);
		poperror();
		b->wp += n;

		qbwrite(q, b);

		sofar += n;
	} while(sofar < len && (q->state & Qmsg) == 0);

	return len;
}
Beispiel #13
0
Datei: vga.c Projekt: 8l/inferno
static void
vgascreenputs(char* s, int n)
{
	int i;
	Rune r;
	char buf[4];
	VGAscr *scr;
	Rectangle flushr;

	scr = &vgascreen[0];

	if(!islo()){
		/*
		 * Don't deadlock trying to
		 * print in an interrupt.
		 */
		if(!canlock(&vgascreenlock))
			return;
	}
	else
		lock(&vgascreenlock);

	flushr = Rect(10000, 10000, -10000, -10000);

	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		vgascreenputc(scr, buf, &flushr);
	}
	flushmemscreen(flushr);

	unlock(&vgascreenlock);
}
Beispiel #14
0
static char*
flushq(Ctlr *ctlr, uint qid)
{
	TXQ *q;
	int i;

	q = &ctlr->tx[qid];
	qlock(q);
	for(i = 0; i < 200 && !ctlr->broken; i++){
		if(txqempty(q)){
			qunlock(q);
			return nil;
		}
		if(islo() && !waserror()){
			tsleep(q, txqempty, q, 10);
			poperror();
		}
	}
	qunlock(q);
	if(ctlr->broken)
		return "flushq: broken";
	return "flushq: timeout";
}
Beispiel #15
0
void
iunlock(Lock *l)
{
	Proc *up = externup();
	Mpl pl;
	uint64_t x;

	if(LOCKCYCLES){
		cycles(&x);
		l->lockcycles = x - l->lockcycles;
		if(l->lockcycles > maxilockcycles){
			maxilockcycles = l->lockcycles;
			maxilockpc = l->_pc;
		}
	}

	if(l->key == 0)
		print("iunlock: not locked: pc %#p\n", getcallerpc());
	if(!l->isilock)
		print("iunlock of lock: pc %#p, held by %#p\n", getcallerpc(), l->_pc);
	if(islo())
		print("iunlock while lo: pc %#p, held by %#p\n", getcallerpc(), l->_pc);
	if(l->m != machp()){
		print("iunlock by cpu%d, locked by cpu%d: pc %#p, held by %#p\n",
			machp()->machno, l->m->machno, getcallerpc(), l->_pc);
	}

	pl = l->pl;
	l->m = nil;
	l->key = 0;
	coherence();
	machp()->ilockdepth--;
	if(up)
		up->lastilock = nil;
	splx(pl);
}
Beispiel #16
0
/*
 *  All traps come here.  It is slower to have all traps call trap()
 *  rather than directly vectoring the handler.  However, this avoids a
 *  lot of code duplication and possible bugs.  The only exception is
 *  VectorSYSCALL.
 *  Trap is called with interrupts disabled via interrupt-gates.
 */
void
trap(Ureg* ureg)
{
    int clockintr, vno, user;
    // cache the previous vno to see what might be causing
    // trouble
    vno = ureg->type;
    uint64_t gsbase = rdmsr(GSbase);
    //if (sce > scx) iprint("====================");
    lastvno = vno;
    if (gsbase < 1ULL<<63)
        die("bogus gsbase");
    Proc *up = externup();
    char buf[ERRMAX];
    Vctl *ctl, *v;

    machp()->perf.intrts = perfticks();
    user = userureg(ureg);
    if(user && (machp()->NIX.nixtype == NIXTC)) {
        up->dbgreg = ureg;
        cycles(&up->kentry);
    }

    clockintr = 0;

    //_pmcupdate(machp());

    if(ctl = vctl[vno]) {
        if(ctl->isintr) {
            machp()->intr++;
            if(vno >= VectorPIC && vno != VectorSYSCALL)
                machp()->lastintr = ctl->Vkey.irq;
        } else if(up)
            up->nqtrap++;

        if(ctl->isr) {
            ctl->isr(vno);
            if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr);
        }
        for(v = ctl; v != nil; v = v->next) {
            if(v->f) {
                v->f(ureg, v->a);
                if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f);
            }
        }
        if(ctl->eoi) {
            ctl->eoi(vno);
            if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi);
        }

        intrtime(vno);
        if(ctl->isintr) {
            if(ctl->Vkey.irq == IrqCLOCK || ctl->Vkey.irq == IrqTIMER)
                clockintr = 1;

            if (ctl->Vkey.irq == IrqTIMER)
                oprof_alarm_handler(ureg);

            if(up && !clockintr)
                preempted();
        }
    }
    else if(vno < nelem(excname) && user) {
        spllo();
        snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
        postnote(up, 1, buf, NDebug);
    }
    else if(vno >= VectorPIC && vno != VectorSYSCALL) {
        /*
         * An unknown interrupt.
         * Check for a default IRQ7. This can happen when
         * the IRQ input goes away before the acknowledge.
         * In this case, a 'default IRQ7' is generated, but
         * the corresponding bit in the ISR isn't set.
         * In fact, just ignore all such interrupts.
         */

        /* clear the interrupt */
        i8259isr(vno);

        iprint("cpu%d: spurious interrupt %d, last %d\n",
               machp()->machno, vno, machp()->lastintr);
        intrtime(vno);
        if(user)
            kexit(ureg);
        return;
    }
    else {
        if(vno == VectorNMI) {
            nmienable();
            if(machp()->machno != 0) {
                iprint("cpu%d: PC %#llx\n",
                       machp()->machno, ureg->ip);
                for(;;);
            }
        }
        dumpregs(ureg);
        if(!user) {
            ureg->sp = PTR2UINT(&ureg->sp);
            dumpstackwithureg(ureg);
        }
        if(vno < nelem(excname))
            panic("%s", excname[vno]);
        panic("unknown trap/intr: %d\n", vno);
    }
    splhi();

    /* delaysched set because we held a lock or because our quantum ended */
    if(up && up->delaysched && clockintr) {
        if(0)
            if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0) {
                if(!waserror()) {
                    up->ac = getac(up, -1);
                    poperror();
                    runacore();
                    return;
                }
            }
        sched();
        splhi();
    }


    if(user) {
        if(up && up->procctl || up->nnote)
            notify(ureg);
        kexit(ureg);
    }
}
Beispiel #17
0
/*
 *  If changing this routine, look also at sleep().  It
 *  contains a copy of the guts of sched().
 */
void
sched(void)
{
	Proc *up = externup();
	Proc *p;

	if(!islo() && machp()->ilockdepth)
		panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p",
			machp()->machno,
			machp()->ilockdepth,
			up? up->lastilock: nil,
			(up && up->lastilock)? up->lastilock->_pc: 0,
			getcallerpc());

	kstackok();
	if(up){
		/*
		 * Delay the sched until the process gives up the locks
		 * it is holding.  This avoids dumb lock loops.
		 * Don't delay if the process is Moribund.
		 * It called sched to die.
		 * But do sched eventually.  This avoids a missing unlock
		 * from hanging the entire kernel.
		 * But don't reschedule procs holding palloc or procalloc.
		 * Those are far too important to be holding while asleep.
		 *
		 * This test is not exact.  There can still be a few
		 * instructions in the middle of taslock when a process
		 * holds a lock but Lock.p has not yet been initialized.
		 */
		if(up->nlocks)
		if(up->state != Moribund)
		if(up->delaysched < 20
		|| pga.l.p == up
		|| procalloc.l.p == up){
			up->delaysched++;
 			run.delayedscheds++;
			return;
		}
		up->delaysched = 0;

		splhi();
		/* statistics */
		if(up->nqtrap == 0 && up->nqsyscall == 0)
			up->nfullq++;
		machp()->cs++;

		procsave(up);
		mmuflushtlb(machp()->MMU.pml4->pa);
		if(setlabel(&up->sched)){
			procrestore(up);
			spllo();
			return;
		}
		/*debug*/gotolabel(&machp()->sched);
	}

	machp()->inidle = 1;
	p = runproc();	/* core 0 never returns */
	machp()->inidle = 0;

	if(!p->edf){
		updatecpu(p);
		p->priority = reprioritize(p);
	}
	if(nosmp){
		if(p != machp()->readied)
			machp()->schedticks = machp()->ticks + HZ/10;
		machp()->readied = 0;
	}
	machp()->externup = p;
	up = p;
	machp()->qstart = machp()->ticks;
	up->nqtrap = 0;
	up->nqsyscall = 0;
	up->state = Running;
	//up->mach = m;
	up->mach = sys->machptr[machp()->machno];
	machp()->proc = up;
//	iprint("up->sched.sp %p * %p\n", up->sched.sp,
//		*(void **) up->sched.sp);
	mmuswitch(up);

	assert(!up->wired || up->wired == machp());
	if (0) hi("gotolabel\n");
	/*debug*/gotolabel(&up->sched);
}