xref: /plan9/sys/src/liboventi/plan9-thread.c (revision 6ca6a3e703ee2ec4aed99c2177f71d7f127da6d9)
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