Blob


1 #undef exits
2 #undef _exits
4 extern int __isthreaded;
6 /*
7 * spin locks
8 */
9 extern int _tas(int*);
11 void
12 _threadunlock(Lock *l, ulong pc)
13 {
14 USED(pc);
16 l->held = 0;
17 }
19 int
20 _threadlock(Lock *l, int block, ulong pc)
21 {
22 int i;
24 USED(pc);
26 /* once fast */
27 if(!_tas(&l->held))
28 return 1;
29 if(!block)
30 return 0;
32 /* a thousand times pretty fast */
33 for(i=0; i<1000; i++){
34 if(!_tas(&l->held))
35 return 1;
36 sleep(0);
37 }
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 }
76 /*
77 * For libc.
78 */
80 typedef struct {
81 volatile long access_lock;
82 volatile long lock_owner;
83 volatile char *fname;
84 volatile int lineno;
85 } spinlock_t;
87 void
88 _spinlock(spinlock_t *lk)
89 {
90 lock((Lock*)&lk->access_lock);
91 }
93 void
94 _spinunlock(spinlock_t *lk)
95 {
96 unlock((Lock*)&lk->access_lock);
97 }
101 /*
102 * sleep and wakeup
103 */
104 static void
105 ign(int x)
107 USED(x);
110 static void /*__attribute__((constructor))*/
111 ignusr1(int restart)
113 struct sigaction sa;
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);
124 void
125 _procsleep(_Procrendez *r)
127 sigset_t mask;
129 /*
130 * Go to sleep.
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 */
136 again:
137 r->asleep = 1;
138 r->pid = getpid();
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);
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;
159 void
160 _procwakeup(_Procrendez *r)
162 if(r->asleep){
163 r->asleep = 0;
164 assert(r->pid >= 1);
165 kill(r->pid, SIGUSR1);
169 void
170 _procwakeupandunlock(_Procrendez *r)
172 _procwakeup(r);
173 unlock(r->l);
177 /*
178 * process creation and exit
179 */
180 typedef struct Stackfree Stackfree;
181 struct Stackfree
183 Stackfree *next;
184 int pid;
185 };
186 static Lock stacklock;
187 static Stackfree *stackfree;
189 static void
190 delayfreestack(uchar *stk)
192 Stackfree *sf;
194 sf = (Stackfree*)stk;
195 sf->pid = getpid();
196 lock(&stacklock);
197 sf->next = stackfree;
198 stackfree = sf;
199 unlock(&stacklock);
202 static void
203 dofreestacks(void)
205 Stackfree *sf, *last, *next;
207 if(stackfree==nil || !canlock(&stacklock))
208 return;
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;
221 unlock(&stacklock);
224 static int
225 startprocfn(void *v)
227 void **a;
228 uchar *stk;
229 void (*fn)(void*);
230 Proc *p;
232 a = (void**)v;
233 fn = a[0];
234 p = a[1];
235 stk = a[2];
236 free(a);
237 p->osprocid = getpid();
239 (*fn)(p);
241 delayfreestack(stk);
242 _exit(0);
243 return 0;
246 void
247 _procstart(Proc *p, void (*fn)(Proc*))
249 void **a;
250 uchar *stk;
251 int pid;
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");
261 a[0] = fn;
262 a[1] = p;
263 a[2] = stk;
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();
272 static char *threadexitsmsg;
273 void
274 sigusr2handler(int s)
276 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
277 if(threadexitsmsg)
278 _exits(threadexitsmsg);
281 void
282 threadexitsall(char *msg)
284 static int pid[1024];
285 int i, npid, mypid;
286 Proc *p;
288 if(msg == nil)
289 msg = "";
291 /*
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 */
301 static Lock onelock;
302 if(!canlock(&onelock))
303 _exits(threadexitsmsg);
304 threadexitsmsg = msg;
307 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);
322 /*
323 * per-process data, indexed by pid
324 */
325 typedef struct Perproc Perproc;
326 struct Perproc
328 int pid;
329 Proc *proc;
330 };
332 static Lock perlock;
333 static Perproc perproc[1024];
334 #define P ((Proc*)-1)
336 static Perproc*
337 myperproc(void)
339 int i, pid, h;
340 Perproc *p;
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;
353 fprint(2, "myperproc %d: cannot find self\n", pid);
354 abort();
355 return nil;
358 static Perproc*
359 newperproc(void)
361 int i, pid, h;
362 Perproc *p;
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;
375 fprint(2, "newperproc %d: out of procs\n", pid);
376 abort();
377 return nil;
380 Proc*
381 _threadproc(void)
383 return myperproc()->proc;
386 void
387 _threadsetproc(Proc *p)
389 Perproc *pp;
391 if(p)
392 p->osprocid = getpid();
393 pp = newperproc();
394 pp->proc = p;
395 if(p == nil)
396 pp->pid = -1;
399 void
400 _threadpexit(void)
402 _exit(0);