Blob


1 #include "threadimpl.h"
3 #undef exits
4 #undef _exits
6 extern int __isthreaded;
8 /*
9 * spin locks
10 */
11 extern int _tas(int*);
13 void
14 _threadunlock(Lock *l, ulong pc)
15 {
16 USED(pc);
18 l->held = 0;
19 }
21 int
22 _threadlock(Lock *l, int block, ulong pc)
23 {
24 int i;
26 USED(pc);
28 /* once fast */
29 if(!_tas(&l->held))
30 return 1;
31 if(!block)
32 return 0;
34 /* a thousand times pretty fast */
35 for(i=0; i<1000; i++){
36 if(!_tas(&l->held))
37 return 1;
38 sched_yield();
39 }
40 /* now nice and slow */
41 for(i=0; i<1000; i++){
42 if(!_tas(&l->held))
43 return 1;
44 usleep(100*1000);
45 }
46 /* take your time */
47 while(_tas(&l->held))
48 usleep(1000*1000);
49 return 1;
50 }
52 /*
53 * For FreeBSD libc.
54 */
56 typedef struct {
57 volatile long access_lock;
58 volatile long lock_owner;
59 volatile char *fname;
60 volatile int lineno;
61 } spinlock_t;
63 void
64 _spinlock(spinlock_t *lk)
65 {
66 lock((Lock*)&lk->access_lock);
67 }
69 /*
70 * sleep and wakeup
71 */
72 static void
73 ign(int x)
74 {
75 USED(x);
76 }
78 static void /*__attribute__((constructor))*/
79 ignusr1(int restart)
80 {
81 struct sigaction sa;
83 memset(&sa, 0, sizeof sa);
84 sa.sa_handler = ign;
85 sigemptyset(&sa.sa_mask);
86 sigaddset(&sa.sa_mask, SIGUSR1);
87 if(restart)
88 sa.sa_flags = SA_RESTART;
89 sigaction(SIGUSR1, &sa, nil);
90 }
92 void
93 _procsleep(_Procrendez *r)
94 {
95 sigset_t mask;
97 /*
98 * Go to sleep.
99 *
100 * Block USR1, set the handler to interrupt system calls,
101 * unlock the vouslock so our waker can wake us,
102 * and then suspend.
103 */
104 again:
105 r->asleep = 1;
106 r->pid = getpid();
108 sigprocmask(SIG_SETMASK, nil, &mask);
109 sigaddset(&mask, SIGUSR1);
110 sigprocmask(SIG_SETMASK, &mask, nil);
111 ignusr1(0);
112 unlock(r->l);
113 sigdelset(&mask, SIGUSR1);
114 sigsuspend(&mask);
116 /*
117 * We're awake. Make USR1 not interrupt system calls.
118 */
119 lock(r->l);
120 ignusr1(1);
121 if(r->asleep && r->pid == getpid()){
122 /* Didn't really wake up - signal from something else */
123 goto again;
127 void
128 _procwakeup(_Procrendez *r)
130 if(r->asleep){
131 r->asleep = 0;
132 assert(r->pid >= 1);
133 kill(r->pid, SIGUSR1);
137 void
138 _procwakeupandunlock(_Procrendez *r)
140 _procwakeup(r);
141 unlock(r->l);
145 /*
146 * process creation and exit
147 */
148 typedef struct Stackfree Stackfree;
149 struct Stackfree
151 Stackfree *next;
152 int pid;
153 };
154 static Lock stacklock;
155 static Stackfree *stackfree;
157 static void
158 delayfreestack(uchar *stk)
160 Stackfree *sf;
162 sf = (Stackfree*)stk;
163 sf->pid = getpid();
164 lock(&stacklock);
165 sf->next = stackfree;
166 stackfree = sf;
167 unlock(&stacklock);
170 static void
171 dofreestacks(void)
173 Stackfree *sf, *last, *next;
175 if(stackfree==nil || !canlock(&stacklock))
176 return;
178 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
179 next = sf->next;
180 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
181 free(sf);
182 if(last)
183 last->next = next;
184 else
185 stackfree = next;
186 sf = last;
189 unlock(&stacklock);
192 static int
193 startprocfn(void *v)
195 void **a;
196 uchar *stk;
197 void (*fn)(void*);
198 Proc *p;
200 a = (void**)v;
201 fn = a[0];
202 p = a[1];
203 stk = a[2];
204 free(a);
205 p->osprocid = getpid();
207 (*fn)(p);
209 delayfreestack(stk);
210 _exit(0);
211 return 0;
214 void
215 _procstart(Proc *p, void (*fn)(Proc*))
217 void **a;
218 uchar *stk;
219 int pid;
221 dofreestacks();
222 a = malloc(3*sizeof a[0]);
223 if(a == nil)
224 sysfatal("_procstart malloc: %r");
225 stk = malloc(65536);
226 if(stk == nil)
227 sysfatal("_procstart malloc stack: %r");
229 a[0] = fn;
230 a[1] = p;
231 a[2] = stk;
233 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
234 if(pid < 0){
235 fprint(2, "_procstart rfork_thread: %r\n");
236 abort();
240 static char *threadexitsmsg;
241 void
242 sigusr2handler(int s)
244 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
245 if(threadexitsmsg)
246 _exits(threadexitsmsg);
249 void
250 threadexitsall(char *msg)
252 static int pid[1024];
253 int i, npid, mypid;
254 Proc *p;
256 if(msg == nil)
257 msg = "";
258 mypid = getpid();
259 lock(&_threadprocslock);
260 threadexitsmsg = msg;
261 npid = 0;
262 for(p=_threadprocs; p; p=p->next)
263 if(p->osprocid != mypid && p->osprocid >= 1)
264 pid[npid++] = p->osprocid;
265 for(i=0; i<npid; i++)
266 kill(pid[i], SIGUSR2);
267 unlock(&_threadprocslock);
268 exits(msg);
271 /*
272 * per-process data, indexed by pid
274 * could use modify_ldt and a segment register
275 * to avoid the many calls to getpid(), but i don't
276 * care -- this is compatibility code. linux 2.6 with
277 * nptl is a good enough pthreads to avoid this whole file.
278 */
279 typedef struct Perproc Perproc;
280 struct Perproc
282 int pid;
283 Proc *proc;
284 };
286 static Lock perlock;
287 static Perproc perproc[1024];
288 #define P ((Proc*)-1)
290 static Perproc*
291 myperproc(void)
293 int i, pid, h;
294 Perproc *p;
296 pid = getpid();
297 h = pid%nelem(perproc);
298 for(i=0; i<nelem(perproc); i++){
299 p = &perproc[(i+h)%nelem(perproc)];
300 if(p->pid == pid)
301 return p;
302 if(p->pid == 0){
303 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
304 break;
307 fprint(2, "myperproc %d: cannot find self\n", pid);
308 abort();
309 return nil;
312 static Perproc*
313 newperproc(void)
315 int i, pid, h;
316 Perproc *p;
318 lock(&perlock);
319 pid = getpid();
320 h = pid%nelem(perproc);
321 for(i=0; i<nelem(perproc); i++){
322 p = &perproc[(i+h)%nelem(perproc)];
323 if(p->pid == pid || p->pid == -1 || p->pid == 0){
324 p->pid = pid;
325 unlock(&perlock);
326 return p;
329 fprint(2, "newperproc %d: out of procs\n", pid);
330 abort();
331 return nil;
334 Proc*
335 _threadproc(void)
337 return myperproc()->proc;
340 void
341 _threadsetproc(Proc *p)
343 Perproc *pp;
345 if(p)
346 p->osprocid = getpid();
347 pp = newperproc();
348 pp->proc = p;
349 if(p == nil)
350 pp->pid = -1;
353 void
354 _pthreadinit(void)
356 __isthreaded = 1;
357 signal(SIGUSR2, sigusr2handler);
360 void
361 _threadpexit(void)
363 _exit(0);
367 /*
368 * FreeBSD 4 and earlier needs the context functions.
369 */
370 void
371 makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
373 int *sp;
375 sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
376 sp -= argc;
377 memmove(sp, &argc+1, argc*sizeof(int));
378 *--sp = 0; /* return address */
379 ucp->uc_mcontext.mc_eip = (long)func;
380 ucp->uc_mcontext.mc_esp = (int)sp;
383 extern int getmcontext(mcontext_t*);
384 extern int setmcontext(mcontext_t*);
386 int
387 getcontext(ucontext_t *uc)
389 return getmcontext(&uc->uc_mcontext);
392 void
393 setcontext(ucontext_t *uc)
395 setmcontext(&uc->uc_mcontext);
398 int
399 swapcontext(ucontext_t *oucp, ucontext_t *ucp)
401 if(getcontext(oucp) == 0)
402 setcontext(ucp);
403 return 0;