xref: /plan9/sys/src/libthread/rendez.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <thread.h>
4*9a747e4fSDavid du Colombier #include "threadimpl.h"
5*9a747e4fSDavid du Colombier 
6*9a747e4fSDavid du Colombier Rgrp _threadrgrp;
7*9a747e4fSDavid du Colombier static int isdirty;
8*9a747e4fSDavid du Colombier 
9*9a747e4fSDavid du Colombier static ulong
10*9a747e4fSDavid du Colombier finish(Thread *t, ulong val)
11*9a747e4fSDavid du Colombier {
12*9a747e4fSDavid du Colombier 	ulong ret;
13*9a747e4fSDavid du Colombier 
14*9a747e4fSDavid du Colombier 	ret = t->rendval;
15*9a747e4fSDavid du Colombier 	t->rendval = val;
16*9a747e4fSDavid du Colombier 	while(t->state == Running)
17*9a747e4fSDavid du Colombier 		sleep(0);
18*9a747e4fSDavid du Colombier 	lock(&t->proc->lock);
19*9a747e4fSDavid du Colombier 	if(t->state == Rendezvous){	/* not always true: might be Dead */
20*9a747e4fSDavid du Colombier 		t->state = Ready;
21*9a747e4fSDavid du Colombier 		_threadready(t);
22*9a747e4fSDavid du Colombier 	}
23*9a747e4fSDavid du Colombier 	unlock(&t->proc->lock);
24*9a747e4fSDavid du Colombier 	return ret;
25*9a747e4fSDavid du Colombier }
26*9a747e4fSDavid du Colombier 
27*9a747e4fSDavid du Colombier ulong
28*9a747e4fSDavid du Colombier _threadrendezvous(ulong tag, ulong val)
29*9a747e4fSDavid du Colombier {
30*9a747e4fSDavid du Colombier 	ulong ret;
31*9a747e4fSDavid du Colombier 	Thread *t, **l;
32*9a747e4fSDavid du Colombier 
33*9a747e4fSDavid du Colombier 	lock(&_threadrgrp.lock);
34*9a747e4fSDavid du Colombier 	l = &_threadrgrp.hash[tag%nelem(_threadrgrp.hash)];
35*9a747e4fSDavid du Colombier 	for(t=*l; t; l=&t->rendhash, t=*l){
36*9a747e4fSDavid du Colombier 		if(t->rendtag==tag){
37*9a747e4fSDavid du Colombier 			_threaddebug(DBGREND, "Rendezvous with thread %d.%d", t->proc->pid, t->id);
38*9a747e4fSDavid du Colombier 			*l = t->rendhash;
39*9a747e4fSDavid du Colombier 			ret = finish(t, val);
40*9a747e4fSDavid du Colombier 			unlock(&_threadrgrp.lock);
41*9a747e4fSDavid du Colombier 			return ret;
42*9a747e4fSDavid du Colombier 		}
43*9a747e4fSDavid du Colombier 	}
44*9a747e4fSDavid du Colombier 
45*9a747e4fSDavid du Colombier 	/* Going to sleep here. */
46*9a747e4fSDavid du Colombier 	t = _threadgetproc()->thread;
47*9a747e4fSDavid du Colombier 	t->rendbreak = 0;
48*9a747e4fSDavid du Colombier 	t->inrendez = 1;
49*9a747e4fSDavid du Colombier 	t->rendtag = tag;
50*9a747e4fSDavid du Colombier 	t->rendval = val;
51*9a747e4fSDavid du Colombier 	t->rendhash = *l;
52*9a747e4fSDavid du Colombier 	*l = t;
53*9a747e4fSDavid du Colombier 	t->nextstate = Rendezvous;
54*9a747e4fSDavid du Colombier 	_threaddebug(DBGREND, "Rendezvous for tag %lud", t->rendtag);
55*9a747e4fSDavid du Colombier 	unlock(&_threadrgrp.lock);
56*9a747e4fSDavid du Colombier 	_sched();
57*9a747e4fSDavid du Colombier 	t->inrendez = 0;
58*9a747e4fSDavid du Colombier 	_threaddebug(DBGREND, "Woke after rendezvous; val is %lud", t->rendval);
59*9a747e4fSDavid du Colombier 	return t->rendval;
60*9a747e4fSDavid du Colombier }
61*9a747e4fSDavid du Colombier 
62*9a747e4fSDavid du Colombier /*
63*9a747e4fSDavid du Colombier  * This is called while holding _threadpq.lock and p->lock,
64*9a747e4fSDavid du Colombier  * so we can't lock _threadrgrp.lock.  Instead our caller has
65*9a747e4fSDavid du Colombier  * to call _threadbreakrendez after dropping those locks.
66*9a747e4fSDavid du Colombier  */
67*9a747e4fSDavid du Colombier void
68*9a747e4fSDavid du Colombier _threadflagrendez(Thread *t)
69*9a747e4fSDavid du Colombier {
70*9a747e4fSDavid du Colombier 	t->rendbreak = 1;
71*9a747e4fSDavid du Colombier 	isdirty = 1;
72*9a747e4fSDavid du Colombier }
73*9a747e4fSDavid du Colombier 
74*9a747e4fSDavid du Colombier void
75*9a747e4fSDavid du Colombier _threadbreakrendez(void)
76*9a747e4fSDavid du Colombier {
77*9a747e4fSDavid du Colombier 	int i;
78*9a747e4fSDavid du Colombier 	Thread *t, **l;
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier 	if(isdirty == 0)
81*9a747e4fSDavid du Colombier 		return;
82*9a747e4fSDavid du Colombier 	lock(&_threadrgrp.lock);
83*9a747e4fSDavid du Colombier 	if(isdirty == 0){
84*9a747e4fSDavid du Colombier 		unlock(&_threadrgrp.lock);
85*9a747e4fSDavid du Colombier 		return;
86*9a747e4fSDavid du Colombier 	}
87*9a747e4fSDavid du Colombier 	isdirty = 0;
88*9a747e4fSDavid du Colombier 	for(i=0; i<nelem(_threadrgrp.hash); i++){
89*9a747e4fSDavid du Colombier 		l = &_threadrgrp.hash[i];
90*9a747e4fSDavid du Colombier 		for(t=*l; t; t=*l){
91*9a747e4fSDavid du Colombier 			if(t->rendbreak){
92*9a747e4fSDavid du Colombier 				*l = t->rendhash;
93*9a747e4fSDavid du Colombier 				finish(t, ~0);
94*9a747e4fSDavid du Colombier 			}else
95*9a747e4fSDavid du Colombier 				 l=&t->rendhash;
96*9a747e4fSDavid du Colombier 		}
97*9a747e4fSDavid du Colombier 	}
98*9a747e4fSDavid du Colombier 	unlock(&_threadrgrp.lock);
99*9a747e4fSDavid du Colombier }
100