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