1368c31abSDavid du Colombier #include <u.h>
2368c31abSDavid du Colombier #include <libc.h>
3368c31abSDavid du Colombier #include <oventi.h>
4368c31abSDavid du Colombier
5368c31abSDavid du Colombier enum
6368c31abSDavid du Colombier {
7368c31abSDavid du Colombier QueuingW, /* queuing for write lock */
8368c31abSDavid du Colombier QueuingR, /* queuing for read lock */
9368c31abSDavid du Colombier };
10368c31abSDavid du Colombier
11368c31abSDavid du Colombier
12368c31abSDavid du Colombier typedef struct Thread Thread;
13368c31abSDavid du Colombier
14368c31abSDavid du Colombier struct Thread {
15368c31abSDavid du Colombier int pid;
16368c31abSDavid du Colombier int ref;
17368c31abSDavid du Colombier char *error;
18368c31abSDavid du Colombier int state;
19368c31abSDavid du Colombier Thread *next;
20368c31abSDavid du Colombier };
21368c31abSDavid du Colombier
22368c31abSDavid du Colombier struct VtLock {
23368c31abSDavid du Colombier Lock lk;
24368c31abSDavid du Colombier Thread *writer; /* thread writering write lock */
25368c31abSDavid du Colombier int readers; /* number writering read lock */
26368c31abSDavid du Colombier Thread *qfirst;
27368c31abSDavid du Colombier Thread *qlast;
28*6ca6a3e7SDavid du Colombier uintptr pc;
29368c31abSDavid du Colombier };
30368c31abSDavid du Colombier
31368c31abSDavid du Colombier struct VtRendez {
32368c31abSDavid du Colombier VtLock *lk;
33368c31abSDavid du Colombier Thread *wfirst;
34368c31abSDavid du Colombier Thread *wlast;
35368c31abSDavid du Colombier };
36368c31abSDavid du Colombier
37368c31abSDavid du Colombier enum {
38368c31abSDavid du Colombier ERROR = 0,
39368c31abSDavid du Colombier };
40368c31abSDavid du Colombier
41368c31abSDavid du Colombier static Thread **vtRock;
42368c31abSDavid du Colombier
43368c31abSDavid du Colombier static void vtThreadInit(void);
44368c31abSDavid du Colombier static void threadSleep(Thread*);
45368c31abSDavid du Colombier static void threadWakeup(Thread*);
46368c31abSDavid du Colombier
47368c31abSDavid du Colombier int
vtThread(void (* f)(void *),void * rock)48368c31abSDavid du Colombier vtThread(void (*f)(void*), void *rock)
49368c31abSDavid du Colombier {
50368c31abSDavid du Colombier int tid;
51368c31abSDavid du Colombier
52368c31abSDavid du Colombier tid = rfork(RFNOWAIT|RFMEM|RFPROC);
53368c31abSDavid du Colombier switch(tid){
54368c31abSDavid du Colombier case -1:
55368c31abSDavid du Colombier vtOSError();
56368c31abSDavid du Colombier return -1;
57368c31abSDavid du Colombier case 0:
58368c31abSDavid du Colombier break;
59368c31abSDavid du Colombier default:
60368c31abSDavid du Colombier return tid;
61368c31abSDavid du Colombier }
62368c31abSDavid du Colombier vtAttach();
63368c31abSDavid du Colombier (*f)(rock);
64368c31abSDavid du Colombier vtDetach();
65368c31abSDavid du Colombier _exits(0);
66368c31abSDavid du Colombier return 0;
67368c31abSDavid du Colombier }
68368c31abSDavid du Colombier
69368c31abSDavid du Colombier static Thread *
threadLookup(void)70368c31abSDavid du Colombier threadLookup(void)
71368c31abSDavid du Colombier {
72368c31abSDavid du Colombier return *vtRock;
73368c31abSDavid du Colombier }
74368c31abSDavid du Colombier
75368c31abSDavid du Colombier void
vtAttach(void)76368c31abSDavid du Colombier vtAttach(void)
77368c31abSDavid du Colombier {
78368c31abSDavid du Colombier int pid;
79368c31abSDavid du Colombier Thread *p;
80368c31abSDavid du Colombier static int init;
81368c31abSDavid du Colombier static Lock lk;
82368c31abSDavid du Colombier
83368c31abSDavid du Colombier lock(&lk);
84368c31abSDavid du Colombier if(!init) {
85368c31abSDavid du Colombier rfork(RFREND);
86368c31abSDavid du Colombier vtThreadInit();
87368c31abSDavid du Colombier init = 1;
88368c31abSDavid du Colombier }
89368c31abSDavid du Colombier unlock(&lk);
90368c31abSDavid du Colombier
91368c31abSDavid du Colombier pid = getpid();
92368c31abSDavid du Colombier p = *vtRock;
93368c31abSDavid du Colombier if(p != nil && p->pid == pid) {
94368c31abSDavid du Colombier p->ref++;
95368c31abSDavid du Colombier return;
96368c31abSDavid du Colombier }
97368c31abSDavid du Colombier p = vtMemAllocZ(sizeof(Thread));
98368c31abSDavid du Colombier p->ref = 1;
99368c31abSDavid du Colombier p->pid = pid;
100368c31abSDavid du Colombier *vtRock = p;
101368c31abSDavid du Colombier }
102368c31abSDavid du Colombier
103368c31abSDavid du Colombier void
vtDetach(void)104368c31abSDavid du Colombier vtDetach(void)
105368c31abSDavid du Colombier {
106368c31abSDavid du Colombier Thread *p;
107368c31abSDavid du Colombier
108368c31abSDavid du Colombier p = *vtRock;
109368c31abSDavid du Colombier assert(p != nil);
110368c31abSDavid du Colombier p->ref--;
111368c31abSDavid du Colombier if(p->ref == 0) {
112368c31abSDavid du Colombier vtMemFree(p->error);
113368c31abSDavid du Colombier vtMemFree(p);
114368c31abSDavid du Colombier *vtRock = nil;
115368c31abSDavid du Colombier }
116368c31abSDavid du Colombier }
117368c31abSDavid du Colombier
118368c31abSDavid du Colombier char *
vtGetError(void)119368c31abSDavid du Colombier vtGetError(void)
120368c31abSDavid du Colombier {
121368c31abSDavid du Colombier char *s;
122368c31abSDavid du Colombier
123368c31abSDavid du Colombier if(ERROR)
124368c31abSDavid du Colombier fprint(2, "vtGetError: %s\n", threadLookup()->error);
125368c31abSDavid du Colombier s = threadLookup()->error;
126368c31abSDavid du Colombier if(s == nil)
127368c31abSDavid du Colombier return "unknown error";
128368c31abSDavid du Colombier return s;
129368c31abSDavid du Colombier }
130368c31abSDavid du Colombier
131368c31abSDavid du Colombier char*
vtSetError(char * fmt,...)132368c31abSDavid du Colombier vtSetError(char* fmt, ...)
133368c31abSDavid du Colombier {
134368c31abSDavid du Colombier Thread *p;
135368c31abSDavid du Colombier char *s;
136368c31abSDavid du Colombier va_list args;
137368c31abSDavid du Colombier
138368c31abSDavid du Colombier p = threadLookup();
139368c31abSDavid du Colombier
140368c31abSDavid du Colombier va_start(args, fmt);
141368c31abSDavid du Colombier s = vsmprint(fmt, args);
142368c31abSDavid du Colombier vtMemFree(p->error);
143368c31abSDavid du Colombier p->error = s;
144368c31abSDavid du Colombier va_end(args);
145368c31abSDavid du Colombier if(ERROR)
146368c31abSDavid du Colombier fprint(2, "vtSetError: %s\n", p->error);
147368c31abSDavid du Colombier werrstr("%s", p->error);
148368c31abSDavid du Colombier return p->error;
149368c31abSDavid du Colombier }
150368c31abSDavid du Colombier
151368c31abSDavid du Colombier static void
vtThreadInit(void)152368c31abSDavid du Colombier vtThreadInit(void)
153368c31abSDavid du Colombier {
154368c31abSDavid du Colombier static Lock lk;
155368c31abSDavid du Colombier
156368c31abSDavid du Colombier lock(&lk);
157368c31abSDavid du Colombier if(vtRock != nil) {
158368c31abSDavid du Colombier unlock(&lk);
159368c31abSDavid du Colombier return;
160368c31abSDavid du Colombier }
161368c31abSDavid du Colombier vtRock = privalloc();
162368c31abSDavid du Colombier if(vtRock == nil)
163368c31abSDavid du Colombier vtFatal("can't allocate thread-private storage");
164368c31abSDavid du Colombier unlock(&lk);
165368c31abSDavid du Colombier }
166368c31abSDavid du Colombier
167368c31abSDavid du Colombier VtLock*
vtLockAlloc(void)168368c31abSDavid du Colombier vtLockAlloc(void)
169368c31abSDavid du Colombier {
170368c31abSDavid du Colombier return vtMemAllocZ(sizeof(VtLock));
171368c31abSDavid du Colombier }
172368c31abSDavid du Colombier
173368c31abSDavid du Colombier /*
174368c31abSDavid du Colombier * RSC: I think the test is backward. Let's see who uses it.
175368c31abSDavid du Colombier *
176368c31abSDavid du Colombier void
177368c31abSDavid du Colombier vtLockInit(VtLock **p)
178368c31abSDavid du Colombier {
179368c31abSDavid du Colombier static Lock lk;
180368c31abSDavid du Colombier
181368c31abSDavid du Colombier lock(&lk);
182368c31abSDavid du Colombier if(*p != nil)
183368c31abSDavid du Colombier *p = vtLockAlloc();
184368c31abSDavid du Colombier unlock(&lk);
185368c31abSDavid du Colombier }
186368c31abSDavid du Colombier */
187368c31abSDavid du Colombier
188368c31abSDavid du Colombier void
vtLockFree(VtLock * p)189368c31abSDavid du Colombier vtLockFree(VtLock *p)
190368c31abSDavid du Colombier {
191368c31abSDavid du Colombier if(p == nil)
192368c31abSDavid du Colombier return;
193368c31abSDavid du Colombier assert(p->writer == nil);
194368c31abSDavid du Colombier assert(p->readers == 0);
195368c31abSDavid du Colombier assert(p->qfirst == nil);
196368c31abSDavid du Colombier vtMemFree(p);
197368c31abSDavid du Colombier }
198368c31abSDavid du Colombier
199368c31abSDavid du Colombier VtRendez*
vtRendezAlloc(VtLock * p)200368c31abSDavid du Colombier vtRendezAlloc(VtLock *p)
201368c31abSDavid du Colombier {
202368c31abSDavid du Colombier VtRendez *q;
203368c31abSDavid du Colombier
204368c31abSDavid du Colombier q = vtMemAllocZ(sizeof(VtRendez));
205368c31abSDavid du Colombier q->lk = p;
206225077b0SDavid du Colombier setmalloctag(q, getcallerpc(&p));
207368c31abSDavid du Colombier return q;
208368c31abSDavid du Colombier }
209368c31abSDavid du Colombier
210368c31abSDavid du Colombier void
vtRendezFree(VtRendez * q)211368c31abSDavid du Colombier vtRendezFree(VtRendez *q)
212368c31abSDavid du Colombier {
213368c31abSDavid du Colombier if(q == nil)
214368c31abSDavid du Colombier return;
215368c31abSDavid du Colombier assert(q->wfirst == nil);
216368c31abSDavid du Colombier vtMemFree(q);
217368c31abSDavid du Colombier }
218368c31abSDavid du Colombier
219368c31abSDavid du Colombier int
vtCanLock(VtLock * p)220368c31abSDavid du Colombier vtCanLock(VtLock *p)
221368c31abSDavid du Colombier {
222368c31abSDavid du Colombier Thread *t;
223368c31abSDavid du Colombier
224368c31abSDavid du Colombier lock(&p->lk);
225368c31abSDavid du Colombier t = *vtRock;
226368c31abSDavid du Colombier if(p->writer == nil && p->readers == 0) {
227368c31abSDavid du Colombier p->writer = t;
228368c31abSDavid du Colombier unlock(&p->lk);
229368c31abSDavid du Colombier return 1;
230368c31abSDavid du Colombier }
231368c31abSDavid du Colombier unlock(&p->lk);
232368c31abSDavid du Colombier return 0;
233368c31abSDavid du Colombier }
234368c31abSDavid du Colombier
235368c31abSDavid du Colombier
236368c31abSDavid du Colombier void
vtLock(VtLock * p)237368c31abSDavid du Colombier vtLock(VtLock *p)
238368c31abSDavid du Colombier {
239368c31abSDavid du Colombier Thread *t;
240368c31abSDavid du Colombier
241368c31abSDavid du Colombier lock(&p->lk);
242*6ca6a3e7SDavid du Colombier p->pc = getcallerpc(&p);
243368c31abSDavid du Colombier t = *vtRock;
244368c31abSDavid du Colombier if(p->writer == nil && p->readers == 0) {
245368c31abSDavid du Colombier p->writer = t;
246368c31abSDavid du Colombier unlock(&p->lk);
247368c31abSDavid du Colombier return;
248368c31abSDavid du Colombier }
249368c31abSDavid du Colombier
250368c31abSDavid du Colombier /*
251368c31abSDavid du Colombier * venti currently contains code that assume locks can be passed between threads :-(
252368c31abSDavid du Colombier * assert(p->writer != t);
253368c31abSDavid du Colombier */
254368c31abSDavid du Colombier
255368c31abSDavid du Colombier if(p->qfirst == nil)
256368c31abSDavid du Colombier p->qfirst = t;
257368c31abSDavid du Colombier else
258368c31abSDavid du Colombier p->qlast->next = t;
259368c31abSDavid du Colombier p->qlast = t;
260368c31abSDavid du Colombier t->next = nil;
261368c31abSDavid du Colombier t->state = QueuingW;
262368c31abSDavid du Colombier unlock(&p->lk);
263368c31abSDavid du Colombier
264368c31abSDavid du Colombier threadSleep(t);
265368c31abSDavid du Colombier assert(p->writer == t && p->readers == 0);
266368c31abSDavid du Colombier }
267368c31abSDavid du Colombier
268368c31abSDavid du Colombier int
vtCanRLock(VtLock * p)269368c31abSDavid du Colombier vtCanRLock(VtLock *p)
270368c31abSDavid du Colombier {
271368c31abSDavid du Colombier lock(&p->lk);
272368c31abSDavid du Colombier if(p->writer == nil && p->qfirst == nil) {
273368c31abSDavid du Colombier p->readers++;
274368c31abSDavid du Colombier unlock(&p->lk);
275368c31abSDavid du Colombier return 1;
276368c31abSDavid du Colombier }
277368c31abSDavid du Colombier unlock(&p->lk);
278368c31abSDavid du Colombier return 0;
279368c31abSDavid du Colombier }
280368c31abSDavid du Colombier
281368c31abSDavid du Colombier void
vtRLock(VtLock * p)282368c31abSDavid du Colombier vtRLock(VtLock *p)
283368c31abSDavid du Colombier {
284368c31abSDavid du Colombier Thread *t;
285368c31abSDavid du Colombier
286368c31abSDavid du Colombier lock(&p->lk);
287368c31abSDavid du Colombier t = *vtRock;
288368c31abSDavid du Colombier if(p->writer == nil && p->qfirst == nil) {
289368c31abSDavid du Colombier p->readers++;
290368c31abSDavid du Colombier unlock(&p->lk);
291368c31abSDavid du Colombier return;
292368c31abSDavid du Colombier }
293368c31abSDavid du Colombier
294368c31abSDavid du Colombier /*
295368c31abSDavid du Colombier * venti currently contains code that assumes locks can be passed between threads
296368c31abSDavid du Colombier * assert(p->writer != t);
297368c31abSDavid du Colombier */
298368c31abSDavid du Colombier if(p->qfirst == nil)
299368c31abSDavid du Colombier p->qfirst = t;
300368c31abSDavid du Colombier else
301368c31abSDavid du Colombier p->qlast->next = t;
302368c31abSDavid du Colombier p->qlast = t;
303368c31abSDavid du Colombier t->next = nil;
304368c31abSDavid du Colombier t->state = QueuingR;
305368c31abSDavid du Colombier unlock(&p->lk);
306368c31abSDavid du Colombier
307368c31abSDavid du Colombier threadSleep(t);
308368c31abSDavid du Colombier assert(p->writer == nil && p->readers > 0);
309368c31abSDavid du Colombier }
310368c31abSDavid du Colombier
311368c31abSDavid du Colombier void
vtUnlock(VtLock * p)312368c31abSDavid du Colombier vtUnlock(VtLock *p)
313368c31abSDavid du Colombier {
314368c31abSDavid du Colombier Thread *t, *tt;
315368c31abSDavid du Colombier
316368c31abSDavid du Colombier lock(&p->lk);
317368c31abSDavid du Colombier /*
318368c31abSDavid du Colombier * venti currently has code that assumes lock can be passed between threads :-)
319368c31abSDavid du Colombier * assert(p->writer == *vtRock);
320368c31abSDavid du Colombier */
321368c31abSDavid du Colombier assert(p->writer != nil);
322368c31abSDavid du Colombier assert(p->readers == 0);
323368c31abSDavid du Colombier t = p->qfirst;
324368c31abSDavid du Colombier if(t == nil) {
325368c31abSDavid du Colombier p->writer = nil;
326368c31abSDavid du Colombier unlock(&p->lk);
327368c31abSDavid du Colombier return;
328368c31abSDavid du Colombier }
329368c31abSDavid du Colombier if(t->state == QueuingW) {
330368c31abSDavid du Colombier p->qfirst = t->next;
331368c31abSDavid du Colombier p->writer = t;
332368c31abSDavid du Colombier unlock(&p->lk);
333*6ca6a3e7SDavid du Colombier
334368c31abSDavid du Colombier threadWakeup(t);
335368c31abSDavid du Colombier return;
336368c31abSDavid du Colombier }
337368c31abSDavid du Colombier
338368c31abSDavid du Colombier p->writer = nil;
339368c31abSDavid du Colombier while(t != nil && t->state == QueuingR) {
340368c31abSDavid du Colombier tt = t;
341368c31abSDavid du Colombier t = t->next;
342368c31abSDavid du Colombier p->readers++;
343*6ca6a3e7SDavid du Colombier
344368c31abSDavid du Colombier threadWakeup(tt);
345368c31abSDavid du Colombier }
346368c31abSDavid du Colombier p->qfirst = t;
347368c31abSDavid du Colombier unlock(&p->lk);
348368c31abSDavid du Colombier }
349368c31abSDavid du Colombier
350368c31abSDavid du Colombier void
vtRUnlock(VtLock * p)351368c31abSDavid du Colombier vtRUnlock(VtLock *p)
352368c31abSDavid du Colombier {
353368c31abSDavid du Colombier Thread *t;
354368c31abSDavid du Colombier
355368c31abSDavid du Colombier lock(&p->lk);
356368c31abSDavid du Colombier assert(p->writer == nil && p->readers > 0);
357368c31abSDavid du Colombier p->readers--;
358368c31abSDavid du Colombier t = p->qfirst;
359368c31abSDavid du Colombier if(p->readers > 0 || t == nil) {
360368c31abSDavid du Colombier unlock(&p->lk);
361368c31abSDavid du Colombier return;
362368c31abSDavid du Colombier }
363368c31abSDavid du Colombier assert(t->state == QueuingW);
364368c31abSDavid du Colombier
365368c31abSDavid du Colombier p->qfirst = t->next;
366368c31abSDavid du Colombier p->writer = t;
367368c31abSDavid du Colombier unlock(&p->lk);
368368c31abSDavid du Colombier
369368c31abSDavid du Colombier threadWakeup(t);
370368c31abSDavid du Colombier }
371368c31abSDavid du Colombier
372368c31abSDavid du Colombier int
vtSleep(VtRendez * q)373368c31abSDavid du Colombier vtSleep(VtRendez *q)
374368c31abSDavid du Colombier {
375368c31abSDavid du Colombier Thread *s, *t, *tt;
376368c31abSDavid du Colombier VtLock *p;
377368c31abSDavid du Colombier
378368c31abSDavid du Colombier p = q->lk;
379368c31abSDavid du Colombier lock(&p->lk);
380368c31abSDavid du Colombier s = *vtRock;
381368c31abSDavid du Colombier /*
382368c31abSDavid du Colombier * venti currently contains code that assume locks can be passed between threads :-(
383368c31abSDavid du Colombier * assert(p->writer != s);
384368c31abSDavid du Colombier */
385368c31abSDavid du Colombier assert(p->writer != nil);
386368c31abSDavid du Colombier assert(p->readers == 0);
387368c31abSDavid du Colombier t = p->qfirst;
388368c31abSDavid du Colombier if(t == nil) {
389368c31abSDavid du Colombier p->writer = nil;
390368c31abSDavid du Colombier } else if(t->state == QueuingW) {
391368c31abSDavid du Colombier p->qfirst = t->next;
392368c31abSDavid du Colombier p->writer = t;
393368c31abSDavid du Colombier threadWakeup(t);
394368c31abSDavid du Colombier } else {
395368c31abSDavid du Colombier p->writer = nil;
396368c31abSDavid du Colombier while(t != nil && t->state == QueuingR) {
397368c31abSDavid du Colombier tt = t;
398368c31abSDavid du Colombier t = t->next;
399368c31abSDavid du Colombier p->readers++;
400368c31abSDavid du Colombier threadWakeup(tt);
401368c31abSDavid du Colombier }
402368c31abSDavid du Colombier }
403368c31abSDavid du Colombier
404368c31abSDavid du Colombier if(q->wfirst == nil)
405368c31abSDavid du Colombier q->wfirst = s;
406368c31abSDavid du Colombier else
407368c31abSDavid du Colombier q->wlast->next = s;
408368c31abSDavid du Colombier q->wlast = s;
409368c31abSDavid du Colombier s->next = nil;
410368c31abSDavid du Colombier unlock(&p->lk);
411368c31abSDavid du Colombier
412368c31abSDavid du Colombier threadSleep(s);
413368c31abSDavid du Colombier assert(p->writer == s);
414368c31abSDavid du Colombier return 1;
415368c31abSDavid du Colombier }
416368c31abSDavid du Colombier
417368c31abSDavid du Colombier int
vtWakeup(VtRendez * q)418368c31abSDavid du Colombier vtWakeup(VtRendez *q)
419368c31abSDavid du Colombier {
420368c31abSDavid du Colombier Thread *t;
421368c31abSDavid du Colombier VtLock *p;
422368c31abSDavid du Colombier
423368c31abSDavid du Colombier /*
424368c31abSDavid du Colombier * take off wait and put on front of queue
425368c31abSDavid du Colombier * put on front so guys that have been waiting will not get starved
426368c31abSDavid du Colombier */
427368c31abSDavid du Colombier p = q->lk;
428368c31abSDavid du Colombier lock(&p->lk);
429368c31abSDavid du Colombier /*
430368c31abSDavid du Colombier * venti currently has code that assumes lock can be passed between threads :-)
431368c31abSDavid du Colombier * assert(p->writer == *vtRock);
432368c31abSDavid du Colombier */
433368c31abSDavid du Colombier assert(p->writer != nil);
434368c31abSDavid du Colombier t = q->wfirst;
435368c31abSDavid du Colombier if(t == nil) {
436368c31abSDavid du Colombier unlock(&p->lk);
437368c31abSDavid du Colombier return 0;
438368c31abSDavid du Colombier }
439368c31abSDavid du Colombier q->wfirst = t->next;
440368c31abSDavid du Colombier if(p->qfirst == nil)
441368c31abSDavid du Colombier p->qlast = t;
442368c31abSDavid du Colombier t->next = p->qfirst;
443368c31abSDavid du Colombier p->qfirst = t;
444368c31abSDavid du Colombier t->state = QueuingW;
445368c31abSDavid du Colombier unlock(&p->lk);
446368c31abSDavid du Colombier
447368c31abSDavid du Colombier return 1;
448368c31abSDavid du Colombier }
449368c31abSDavid du Colombier
450368c31abSDavid du Colombier int
vtWakeupAll(VtRendez * q)451368c31abSDavid du Colombier vtWakeupAll(VtRendez *q)
452368c31abSDavid du Colombier {
453368c31abSDavid du Colombier int i;
454368c31abSDavid du Colombier
455368c31abSDavid du Colombier for(i=0; vtWakeup(q); i++)
456368c31abSDavid du Colombier ;
457368c31abSDavid du Colombier return i;
458368c31abSDavid du Colombier }
459368c31abSDavid du Colombier
460368c31abSDavid du Colombier static void
threadSleep(Thread * t)461368c31abSDavid du Colombier threadSleep(Thread *t)
462368c31abSDavid du Colombier {
463368c31abSDavid du Colombier if(rendezvous(t, (void*)0x22bbdfd6) != (void*)0x44391f14)
464368c31abSDavid du Colombier sysfatal("threadSleep: rendezvous failed: %r");
465368c31abSDavid du Colombier }
466368c31abSDavid du Colombier
467368c31abSDavid du Colombier static void
threadWakeup(Thread * t)468368c31abSDavid du Colombier threadWakeup(Thread *t)
469368c31abSDavid du Colombier {
470368c31abSDavid du Colombier if(rendezvous(t, (void*)0x44391f14) != (void*)0x22bbdfd6)
471368c31abSDavid du Colombier sysfatal("threadWakeup: rendezvous failed: %r");
472368c31abSDavid du Colombier }
473