1 #include "threadimpl.h"
2 
3 #undef exits
4 #undef _exits
5 
6 static int
timefmt(Fmt * fmt)7 timefmt(Fmt *fmt)
8 {
9 	static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
10 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
11 	vlong ns;
12 	Tm tm;
13 	ns = nsec();
14 	tm = *localtime(time(0));
15 	return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
16 		mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
17 		(int)(ns%1000000000)/1000000);
18 }
19 
20 /*
21  * spin locks
22  */
23 extern int _tas(int*);
24 
25 void
_threadunlock(Lock * l,ulong pc)26 _threadunlock(Lock *l, ulong pc)
27 {
28 	USED(pc);
29 
30 	l->held = 0;
31 }
32 
33 int
_threadlock(Lock * l,int block,ulong pc)34 _threadlock(Lock *l, int block, ulong pc)
35 {
36 	int i;
37 static int first=1;
38 if(first) {first=0; fmtinstall('\001', timefmt);}
39 
40 	USED(pc);
41 
42 	/* once fast */
43 	if(!_tas(&l->held))
44 		return 1;
45 	if(!block)
46 		return 0;
47 
48 	/* a thousand times pretty fast */
49 	for(i=0; i<1000; i++){
50 		if(!_tas(&l->held))
51 			return 1;
52 		sched_yield();
53 	}
54 	/* now increasingly slow */
55 	for(i=0; i<10; i++){
56 		if(!_tas(&l->held))
57 			return 1;
58 		usleep(1);
59 	}
60 fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
61 	for(i=0; i<10; i++){
62 		if(!_tas(&l->held))
63 			return 1;
64 		usleep(10);
65 	}
66 fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
67 	for(i=0; i<10; i++){
68 		if(!_tas(&l->held))
69 			return 1;
70 		usleep(100);
71 	}
72 fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
73 	for(i=0; i<10; i++){
74 		if(!_tas(&l->held))
75 			return 1;
76 		usleep(1000);
77 	}
78 fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
79 	for(i=0; i<10; i++){
80 		if(!_tas(&l->held))
81 			return 1;
82 		usleep(10*1000);
83 	}
84 fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
85 	for(i=0; i<1000; i++){
86 		if(!_tas(&l->held))
87 			return 1;
88 		usleep(100*1000);
89 	}
90 fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
91 	/* take your time */
92 	while(_tas(&l->held))
93 		usleep(1000*1000);
94 	return 1;
95 }
96 
97 /*
98  * sleep and wakeup
99  */
100 static void
ign(int x)101 ign(int x)
102 {
103 	USED(x);
104 }
105 
106 static void /*__attribute__((constructor))*/
ignusr1(int restart)107 ignusr1(int restart)
108 {
109 	struct sigaction sa;
110 
111 	memset(&sa, 0, sizeof sa);
112 	sa.sa_handler = ign;
113 	sigemptyset(&sa.sa_mask);
114 	sigaddset(&sa.sa_mask, SIGUSR1);
115 	if(restart)
116 		sa.sa_flags = SA_RESTART;
117 	sigaction(SIGUSR1, &sa, nil);
118 }
119 
120 void
_procsleep(_Procrendez * r)121 _procsleep(_Procrendez *r)
122 {
123 	sigset_t mask;
124 
125 	/*
126 	 * Go to sleep.
127 	 *
128 	 * Block USR1, set the handler to interrupt system calls,
129 	 * unlock the vouslock so our waker can wake us,
130 	 * and then suspend.
131 	 */
132 again:
133 	r->asleep = 1;
134 	r->pid = getpid();
135 
136 	sigprocmask(SIG_SETMASK, nil, &mask);
137 	sigaddset(&mask, SIGUSR1);
138 	sigprocmask(SIG_SETMASK, &mask, nil);
139 	ignusr1(0);
140 	unlock(r->l);
141 	sigdelset(&mask, SIGUSR1);
142 	sigsuspend(&mask);
143 
144 	/*
145 	 * We're awake.  Make USR1 not interrupt system calls.
146 	 */
147 	lock(r->l);
148 	ignusr1(1);
149 	if(r->asleep && r->pid == getpid()){
150 		/* Didn't really wake up - signal from something else */
151 		goto again;
152 	}
153 }
154 
155 void
_procwakeupandunlock(_Procrendez * r)156 _procwakeupandunlock(_Procrendez *r)
157 {
158 	int pid;
159 
160 	pid = 0;
161 	if(r->asleep){
162 		r->asleep = 0;
163 		assert(r->pid >= 1);
164 		pid = r->pid;
165 	}
166 	assert(r->l);
167 	unlock(r->l);
168 	if(pid)
169 		kill(pid, SIGUSR1);
170 }
171 
172 /*
173  * process creation and exit
174  */
175 typedef struct Stackfree Stackfree;
176 struct Stackfree
177 {
178 	Stackfree	*next;
179 	int	pid;
180 	int	pid1;
181 };
182 static Lock stacklock;
183 static Stackfree *stackfree;
184 
185 static void
delayfreestack(uchar * stk,int pid,int pid1)186 delayfreestack(uchar *stk, int pid, int pid1)
187 {
188 	Stackfree *sf;
189 
190 	sf = (Stackfree*)stk;
191 	sf->pid = pid;
192 	sf->pid1 = pid1;
193 	lock(&stacklock);
194 	sf->next = stackfree;
195 	stackfree = sf;
196 	unlock(&stacklock);
197 }
198 
199 static void
dofreestacks(void)200 dofreestacks(void)
201 {
202 	Stackfree *sf, *last, *next;
203 
204 	if(stackfree==nil || !canlock(&stacklock))
205 		return;
206 
207 	for(last=nil,sf=stackfree; sf; last=sf,sf=next){
208 		next = sf->next;
209 		if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
210 		if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
211 			free(sf);
212 			if(last)
213 				last->next = next;
214 			else
215 				stackfree = next;
216 			sf = last;
217 		}
218 	}
219 	unlock(&stacklock);
220 }
221 
222 static int
startprocfn(void * v)223 startprocfn(void *v)
224 {
225 	void **a;
226 	uchar *stk;
227 	void (*fn)(void*);
228 	Proc *p;
229 	int pid0, pid1;
230 
231 	a = (void**)v;
232 	fn = a[0];
233 	p = a[1];
234 	stk = a[2];
235 	pid0 = (int)a[4];
236 	pid1 = getpid();
237 	free(a);
238 	p->osprocid = pid1;
239 
240 	(*fn)(p);
241 
242 	delayfreestack(stk, pid0, pid1);
243 	_exit(0);
244 	return 0;
245 }
246 
247 /*
248  * indirect through here so that parent need not wait for child zombie
249  *
250  * slight race - if child exits and then another process starts before we
251  * manage to exit, we'll be running on a freed stack.
252  */
253 static int
trampnowait(void * v)254 trampnowait(void *v)
255 {
256 	void **a;
257 	int *kidpid;
258 
259 	a = (void*)v;
260 	kidpid = a[3];
261 	a[4] = (void*)getpid();
262 	*kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
263 	_exit(0);
264 	return 0;
265 }
266 
267 void
_procstart(Proc * p,void (* fn)(Proc *))268 _procstart(Proc *p, void (*fn)(Proc*))
269 {
270 	void **a;
271 	uchar *stk;
272 	int pid, kidpid, status;
273 
274 	dofreestacks();
275 	a = malloc(5*sizeof a[0]);
276 	if(a == nil)
277 		sysfatal("_procstart malloc: %r");
278 	stk = malloc(65536);
279 	if(stk == nil)
280 		sysfatal("_procstart malloc stack: %r");
281 
282 	a[0] = fn;
283 	a[1] = p;
284 	a[2] = stk;
285 	a[3] = &kidpid;
286 	kidpid = -1;
287 
288 	pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
289 	if(pid > 0)
290 		if(wait4(pid, &status, __WALL, 0) < 0)
291 			fprint(2, "ffork wait4: %r\n");
292 	if(pid < 0 || kidpid < 0){
293 		fprint(2, "_procstart clone: %r\n");
294 		abort();
295 	}
296 }
297 
298 static char *threadexitsmsg;
299 void
sigusr2handler(int s)300 sigusr2handler(int s)
301 {
302 /*	fprint(2, "%d usr2 %d\n", time(0), getpid()); */
303 	if(threadexitsmsg)
304 		_exits(threadexitsmsg);
305 }
306 
307 void
threadexitsall(char * msg)308 threadexitsall(char *msg)
309 {
310 	static int pid[1024];
311 	int i, npid, mypid;
312 	Proc *p;
313 
314 	if(msg == nil)
315 		msg = "";
316 
317 	/*
318 	 * Only one guy, ever, gets to run this.
319 	 * If two guys do it, inevitably they end up
320 	 * tripping over each other in the underlying
321 	 * C library exit() implementation, which is
322 	 * trying to run the atexit handlers and apparently
323 	 * not thread safe.  This has been observed on
324 	 * both Linux and OpenBSD.  Sigh.
325 	 */
326 	{
327 		static Lock onelock;
328 		if(!canlock(&onelock))
329 			_exits(threadexitsmsg);
330 		threadexitsmsg = msg;
331 	}
332 
333 	mypid = getpid();
334 	lock(&_threadprocslock);
335 	npid = 0;
336 	for(p=_threadprocs; p; p=p->next)
337 		if(p->osprocid != mypid && p->osprocid >= 1)
338 			pid[npid++] = p->osprocid;
339 	for(i=0; i<npid; i++)
340 		kill(pid[i], SIGUSR2);
341 	unlock(&_threadprocslock);
342 	exits(msg);
343 }
344 
345 /*
346  * per-process data, indexed by pid
347  *
348  * could use modify_ldt and a segment register
349  * to avoid the many calls to getpid(), but i don't
350  * care -- this is compatibility code.  linux 2.6 with
351  * nptl is a good enough pthreads to avoid this whole file.
352  */
353 typedef struct Perproc Perproc;
354 struct Perproc
355 {
356 	int		pid;
357 	Proc	*proc;
358 };
359 
360 static Lock perlock;
361 static Perproc perproc[1024];
362 #define P ((Proc*)-1)
363 
364 static Perproc*
myperproc(void)365 myperproc(void)
366 {
367 	int i, pid, h;
368 	Perproc *p;
369 
370 	pid = getpid();
371 	h = pid%nelem(perproc);
372 	for(i=0; i<nelem(perproc); i++){
373 		p = &perproc[(i+h)%nelem(perproc)];
374 		if(p->pid == pid)
375 			return p;
376 		if(p->pid == 0){
377 			print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
378 			break;
379 		}
380 	}
381 	fprint(2, "myperproc %d (%s): cannot find self\n", pid, argv0);
382 	abort();
383 	return nil;
384 }
385 
386 static Perproc*
newperproc(void)387 newperproc(void)
388 {
389 	int i, pid, h;
390 	Perproc *p;
391 
392 	lock(&perlock);
393 	pid = getpid();
394 	h = pid%nelem(perproc);
395 	for(i=0; i<nelem(perproc); i++){
396 		p = &perproc[(i+h)%nelem(perproc)];
397 		if(p->pid == pid || p->pid == -1 || p->pid == 0){
398 			p->pid = pid;
399 			unlock(&perlock);
400 			return p;
401 		}
402 	}
403 	fprint(2, "newperproc %d: out of procs\n", pid);
404 	abort();
405 	return nil;
406 }
407 
408 Proc*
_threadproc(void)409 _threadproc(void)
410 {
411 	return myperproc()->proc;
412 }
413 
414 void
_threadsetproc(Proc * p)415 _threadsetproc(Proc *p)
416 {
417 	Perproc *pp;
418 
419 	if(p)
420 		p->osprocid = getpid();
421 	pp = newperproc();
422 	pp->proc = p;
423 	if(p == nil)
424 		pp->pid = -1;
425 }
426 
427 void
_pthreadinit(void)428 _pthreadinit(void)
429 {
430 	signal(SIGUSR2, sigusr2handler);
431 }
432 
433 void
_threadpexit(void)434 _threadpexit(void)
435 {
436 	_exit(0);
437 }
438