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