blob: b9e8888e4c193ec6bb9a73d1c102415398414742 [file] [log] [blame]
rsccea10002005-05-01 18:38:12 +00001#undef exits
2#undef _exits
3
4extern int __isthreaded;
5
6/*
7 * spin locks
8 */
9extern int _tas(int*);
10
11void
12_threadunlock(Lock *l, ulong pc)
13{
14 USED(pc);
15
16 l->held = 0;
17}
18
19int
20_threadlock(Lock *l, int block, ulong pc)
21{
22 int i;
23
24 USED(pc);
25
26 /* once fast */
27 if(!_tas(&l->held))
28 return 1;
29 if(!block)
30 return 0;
31
32 /* a thousand times pretty fast */
33 for(i=0; i<1000; i++){
34 if(!_tas(&l->held))
35 return 1;
rscc54b8b62006-01-27 05:51:54 +000036 sleep(0);
rsccea10002005-05-01 18:38:12 +000037 }
38 /* increasingly slow */
39 for(i=0; i<10; i++){
40 if(!_tas(&l->held))
41 return 1;
42 usleep(1);
43 }
44 for(i=0; i<10; i++){
45 if(!_tas(&l->held))
46 return 1;
47 usleep(10);
48 }
49 for(i=0; i<10; i++){
50 if(!_tas(&l->held))
51 return 1;
52 usleep(100);
53 }
54 for(i=0; i<10; i++){
55 if(!_tas(&l->held))
56 return 1;
57 usleep(1000);
58 }
59 for(i=0; i<10; i++){
60 if(!_tas(&l->held))
61 return 1;
62 usleep(10*1000);
63 }
64 /* now nice and slow */
65 for(i=0; i<1000; i++){
66 if(!_tas(&l->held))
67 return 1;
68 usleep(100*1000);
69 }
70 /* take your time */
71 while(_tas(&l->held))
72 usleep(1000*1000);
73 return 1;
74}
75
76/*
77 * For libc.
78 */
79
80typedef struct {
81 volatile long access_lock;
82 volatile long lock_owner;
83 volatile char *fname;
84 volatile int lineno;
85} spinlock_t;
86
87void
88_spinlock(spinlock_t *lk)
89{
90 lock((Lock*)&lk->access_lock);
91}
92
rscfe8c9252005-07-21 18:29:04 +000093void
94_spinunlock(spinlock_t *lk)
95{
96 unlock((Lock*)&lk->access_lock);
97}
98
99
100
rsccea10002005-05-01 18:38:12 +0000101/*
102 * sleep and wakeup
103 */
104static void
105ign(int x)
106{
107 USED(x);
108}
109
110static void /*__attribute__((constructor))*/
111ignusr1(int restart)
112{
113 struct sigaction sa;
114
115 memset(&sa, 0, sizeof sa);
116 sa.sa_handler = ign;
117 sigemptyset(&sa.sa_mask);
118 sigaddset(&sa.sa_mask, SIGUSR1);
119 if(restart)
120 sa.sa_flags = SA_RESTART;
121 sigaction(SIGUSR1, &sa, nil);
122}
123
124void
125_procsleep(_Procrendez *r)
126{
127 sigset_t mask;
128
129 /*
130 * Go to sleep.
131 *
132 * Block USR1, set the handler to interrupt system calls,
133 * unlock the vouslock so our waker can wake us,
134 * and then suspend.
135 */
136again:
137 r->asleep = 1;
138 r->pid = getpid();
139
140 sigprocmask(SIG_SETMASK, nil, &mask);
141 sigaddset(&mask, SIGUSR1);
142 sigprocmask(SIG_SETMASK, &mask, nil);
143 ignusr1(0);
144 unlock(r->l);
145 sigdelset(&mask, SIGUSR1);
146 sigsuspend(&mask);
147
148 /*
149 * We're awake. Make USR1 not interrupt system calls.
150 */
151 lock(r->l);
152 ignusr1(1);
153 if(r->asleep && r->pid == getpid()){
154 /* Didn't really wake up - signal from something else */
155 goto again;
156 }
157}
158
159void
160_procwakeup(_Procrendez *r)
161{
162 if(r->asleep){
163 r->asleep = 0;
164 assert(r->pid >= 1);
165 kill(r->pid, SIGUSR1);
166 }
167}
168
169void
170_procwakeupandunlock(_Procrendez *r)
171{
172 _procwakeup(r);
173 unlock(r->l);
174}
175
176
177/*
178 * process creation and exit
179 */
180typedef struct Stackfree Stackfree;
181struct Stackfree
182{
183 Stackfree *next;
184 int pid;
185};
186static Lock stacklock;
187static Stackfree *stackfree;
188
189static void
190delayfreestack(uchar *stk)
191{
192 Stackfree *sf;
193
194 sf = (Stackfree*)stk;
195 sf->pid = getpid();
196 lock(&stacklock);
197 sf->next = stackfree;
198 stackfree = sf;
199 unlock(&stacklock);
200}
201
202static void
203dofreestacks(void)
204{
205 Stackfree *sf, *last, *next;
206
207 if(stackfree==nil || !canlock(&stacklock))
208 return;
209
210 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
211 next = sf->next;
212 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
213 free(sf);
214 if(last)
215 last->next = next;
216 else
217 stackfree = next;
218 sf = last;
219 }
220 }
221 unlock(&stacklock);
222}
223
224static int
225startprocfn(void *v)
226{
227 void **a;
228 uchar *stk;
229 void (*fn)(void*);
230 Proc *p;
231
232 a = (void**)v;
233 fn = a[0];
234 p = a[1];
235 stk = a[2];
236 free(a);
237 p->osprocid = getpid();
238
239 (*fn)(p);
240
241 delayfreestack(stk);
242 _exit(0);
243 return 0;
244}
245
246void
247_procstart(Proc *p, void (*fn)(Proc*))
248{
249 void **a;
250 uchar *stk;
251 int pid;
252
253 dofreestacks();
254 a = malloc(3*sizeof a[0]);
255 if(a == nil)
256 sysfatal("_procstart malloc: %r");
257 stk = malloc(65536);
258 if(stk == nil)
259 sysfatal("_procstart malloc stack: %r");
260
261 a[0] = fn;
262 a[1] = p;
263 a[2] = stk;
264
265 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
266 if(pid < 0){
267 fprint(2, "_procstart rfork_thread: %r\n");
268 abort();
269 }
270}
271
272static char *threadexitsmsg;
273void
274sigusr2handler(int s)
275{
276/* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
277 if(threadexitsmsg)
278 _exits(threadexitsmsg);
279}
280
281void
282threadexitsall(char *msg)
283{
284 static int pid[1024];
285 int i, npid, mypid;
286 Proc *p;
287
rscf19d5682005-07-28 12:43:41 +0000288 if(msg == nil)
289 msg = "";
290
rsc9689b582005-07-27 20:25:34 +0000291 /*
292 * Only one guy, ever, gets to run this.
293 * If two guys do it, inevitably they end up
294 * tripping over each other in the underlying
295 * C library exit() implementation, which is
296 * trying to run the atexit handlers and apparently
297 * not thread safe. This has been observed on
298 * both Linux and OpenBSD. Sigh.
299 */
300 {
301 static Lock onelock;
rscf19d5682005-07-28 12:43:41 +0000302 if(!canlock(&onelock))
303 _exits(threadexitsmsg);
304 threadexitsmsg = msg;
rsc9689b582005-07-27 20:25:34 +0000305 }
306
rsccea10002005-05-01 18:38:12 +0000307 if(msg == nil)
308 msg = "";
309 mypid = getpid();
310 lock(&_threadprocslock);
311 threadexitsmsg = msg;
312 npid = 0;
313 for(p=_threadprocs; p; p=p->next)
314 if(p->osprocid != mypid && p->osprocid >= 1)
315 pid[npid++] = p->osprocid;
316 for(i=0; i<npid; i++)
317 kill(pid[i], SIGUSR2);
318 unlock(&_threadprocslock);
319 exits(msg);
320}
321
322/*
323 * per-process data, indexed by pid
324 */
325typedef struct Perproc Perproc;
326struct Perproc
327{
328 int pid;
329 Proc *proc;
330};
331
332static Lock perlock;
333static Perproc perproc[1024];
334#define P ((Proc*)-1)
335
336static Perproc*
337myperproc(void)
338{
339 int i, pid, h;
340 Perproc *p;
341
342 pid = getpid();
343 h = pid%nelem(perproc);
344 for(i=0; i<nelem(perproc); i++){
345 p = &perproc[(i+h)%nelem(perproc)];
346 if(p->pid == pid)
347 return p;
348 if(p->pid == 0){
349 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
350 break;
351 }
352 }
353 fprint(2, "myperproc %d: cannot find self\n", pid);
354 abort();
355 return nil;
356}
357
358static Perproc*
359newperproc(void)
360{
361 int i, pid, h;
362 Perproc *p;
363
364 lock(&perlock);
365 pid = getpid();
366 h = pid%nelem(perproc);
367 for(i=0; i<nelem(perproc); i++){
368 p = &perproc[(i+h)%nelem(perproc)];
369 if(p->pid == pid || p->pid == -1 || p->pid == 0){
370 p->pid = pid;
371 unlock(&perlock);
372 return p;
373 }
374 }
375 fprint(2, "newperproc %d: out of procs\n", pid);
376 abort();
377 return nil;
378}
379
380Proc*
381_threadproc(void)
382{
383 return myperproc()->proc;
384}
385
386void
387_threadsetproc(Proc *p)
388{
389 Perproc *pp;
390
391 if(p)
392 p->osprocid = getpid();
393 pp = newperproc();
394 pp->proc = p;
395 if(p == nil)
396 pp->pid = -1;
397}
398
399void
rsccea10002005-05-01 18:38:12 +0000400_threadpexit(void)
401{
402 _exit(0);
403}
404