예제 #1
0
int
chanalt(Alt *a)
{
	int i, j, ncan, n, canblock;
	Channel *c;
	Task *t;

	needstack(512);
	for(i=0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++)
		;
	n = i;
	canblock = a[i].op == CHANEND;

	t = taskrunning;
    //所有alt指向正在运行的task
	for(i=0; i<n; i++){
		a[i].task = t;
		a[i].xalt = a;
	}
	ncan = 0;
	for(i=0; i<n; i++){
		if(altcanexec(&a[i])){
			ncan++;
		}
	}
	if(ncan){
		j = rand()%ncan;
		for(i=0; i<n; i++){
			if(altcanexec(&a[i])){
				if(j-- == 0){
                    altexec(&a[i]);
	                return i;
	            }
			}
		}
	}

	if(!canblock)
		return -1;

	for(i=0; i<n; i++){
		if(a[i].op != CHANNOP)
			altqueue(&a[i]);
	}

	taskswitch();

	/*
	 * the guy who ran the op took care of dequeueing us
	 * and then set a[0].alt to the one that was executed.
	 */
	return a[0].xalt - a;
}
예제 #2
0
int
chanalt(Alt *a)
{
	int i, j, ncan, n, canblock;
	Channel *c;
	Task *t;

	needstack(512);
	for(i=0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++)
		;
	n = i;
	canblock = a[i].op == CHANEND;

	t = taskrunning;
	for(i=0; i<n; i++){
		a[i].task = t;
		a[i].xalt = a;
	}
if(dbgalt) print("alt ");
	ncan = 0;
	for(i=0; i<n; i++){
		c = a[i].c;
if(dbgalt) print(" %c:", "esrnb"[a[i].op]);
if(dbgalt) { if(c->name) print("%s", c->name); else print("%p", c); }
		if(altcanexec(&a[i])){
if(dbgalt) print("*");
			ncan++;
		}
	}
	if(ncan){
		j = rand()%ncan;
		for(i=0; i<n; i++){
			if(altcanexec(&a[i])){
				if(j-- == 0){
if(dbgalt){
c = a[i].c;
print(" => %c:", "esrnb"[a[i].op]);
if(c->name) print("%s", c->name); else print("%p", c);
print("\n");
}
					altexec(&a[i]);
					return i;
				}
			}
		}
	}
if(dbgalt)print("\n");

	if(!canblock)
		return -1;

	for(i=0; i<n; i++){
		if(a[i].op != CHANNOP)
			altqueue(&a[i]);
	}

	taskswitch();

	/*
	 * the guy who ran the op took care of dequeueing us
	 * and then set a[0].alt to the one that was executed.
	 */
	return a[0].xalt - a;
}
예제 #3
0
파일: channel.c 프로젝트: 99years/plan9
int
alt(Alt *alts)
{
	Alt *a, *xa, *ca;
	Channel volatile *c;
	int n, s, waiting, allreadycl;
	void* r;
	Thread *t;

	/*
	 * The point of going splhi here is that note handlers
	 * might reasonably want to use channel operations,
	 * but that will hang if the note comes while we hold the
	 * chanlock.  Instead, we delay the note until we've dropped
	 * the lock.
	 */
	t = _threadgetproc()->thread;
	if(t->moribund || _threadexitsallstatus)
		yield();	/* won't return */
	s = _procsplhi();
	lock(&chanlock);
	t->alt = alts;
	t->chan = Chanalt;

	/* test whether any channels can proceed */
	n = 0;
	a = nil;

	for(xa=alts; xa->op!=CHANEND && xa->op!=CHANNOBLK; xa++){
		xa->entryno = -1;
		if(xa->op == CHANNOP)
			continue;

		c = xa->c;
		if(c==nil){
			unlock(&chanlock);
			_procsplx(s);
			t->chan = Channone;
			return -1;
		}

		if(isopenfor(c, xa->op) && canexec(xa))
			if(nrand(++n) == 0)
				a = xa;
	}


	if(a==nil){
		/* nothing can proceed */
		if(xa->op == CHANNOBLK){
			unlock(&chanlock);
			_procsplx(s);
			t->chan = Channone;
			if(xa->op == CHANNOBLK)
				return xa - alts;
		}

		/* enqueue on all channels open for us. */
		c = nil;
		ca = nil;
		waiting = 0;
		allreadycl = 0;
		for(xa=alts; xa->op!=CHANEND; xa++)
			if(xa->op==CHANNOP)
				continue;
			else if(isopenfor(xa->c, xa->op)){
				waiting = 1;
				enqueue(xa, &c);
			} else if(xa->err != errcl)
				ca = xa;
			else
				allreadycl = 1;

		if(waiting == 0)
			if(ca != nil){
				/* everything was closed, select last channel */
				ca->err = errcl;
				unlock(&chanlock);
				_procsplx(s);
				t->chan = Channone;
				return ca - alts;
			} else if(allreadycl){
				/* everything was already closed */
				unlock(&chanlock);
				_procsplx(s);
				t->chan = Channone;
				return -1;
			}
		/*
		 * wait for successful rendezvous.
		 * we can't just give up if the rendezvous
		 * is interrupted -- someone else might come
		 * along and try to rendezvous with us, so
		 * we need to be here.
		 * if the channel was closed, the op is done
		 * and we flag an error for the entry.
		 */
	    Again:
		unlock(&chanlock);
		_procsplx(s);
		r = _threadrendezvous(&c, 0);
		s = _procsplhi();
		lock(&chanlock);

		if(r==Intred){		/* interrupted */
			if(c!=nil)	/* someone will meet us; go back */
				goto Again;
			c = (Channel*)~0;	/* so no one tries to meet us */
		}

		/* dequeue from channels, find selected one */
		a = nil;
		for(xa=alts; xa->op!=CHANEND; xa++){
			if(xa->op==CHANNOP)
				continue;
			if(xa->c == c){
				a = xa;
				a->err = nil;
				if(r == Closed)
					a->err = errcl;
			}
			dequeue(xa);
		}
		unlock(&chanlock);
		_procsplx(s);
		if(a == nil){	/* we were interrupted */
			assert(c==(Channel*)~0);
			return -1;
		}
	}else
		altexec(a, s);	/* unlocks chanlock, does splx */
	_sched();
	t->chan = Channone;
	return a - alts;
}