Blob


1 #include "threadimpl.h"
3 extern int __isthreaded;
5 /*
6 * spin locks
7 */
8 extern int _tas(int*);
10 void
11 _threadunlock(Lock *l, ulong pc)
12 {
13 USED(pc);
15 l->held = 0;
16 }
18 int
19 _threadlock(Lock *l, int block, ulong pc)
20 {
21 int i;
23 USED(pc);
25 /* once fast */
26 if(!_tas(&l->held))
27 return 1;
28 if(!block)
29 return 0;
31 /* a thousand times pretty fast */
32 for(i=0; i<1000; i++){
33 if(!_tas(&l->held))
34 return 1;
35 sched_yield();
36 }
37 /* now nice and slow */
38 for(i=0; i<1000; i++){
39 if(!_tas(&l->held))
40 return 1;
41 usleep(100*1000);
42 }
43 /* take your time */
44 while(_tas(&l->held))
45 usleep(1000*1000);
46 return 1;
47 }
49 /*
50 * For FreeBSD libc.
51 */
53 typedef struct {
54 volatile long access_lock;
55 volatile long lock_owner;
56 volatile char *fname;
57 volatile int lineno;
58 } spinlock_t;
60 void
61 _spinlock(spinlock_t *lk)
62 {
63 lock((Lock*)&lk->access_lock);
64 }
66 /*
67 * sleep and wakeup
68 */
69 static void
70 ign(int x)
71 {
72 USED(x);
73 }
75 static void /*__attribute__((constructor))*/
76 ignusr1(int restart)
77 {
78 struct sigaction sa;
80 memset(&sa, 0, sizeof sa);
81 sa.sa_handler = ign;
82 sigemptyset(&sa.sa_mask);
83 sigaddset(&sa.sa_mask, SIGUSR1);
84 if(restart)
85 sa.sa_flags = SA_RESTART;
86 sigaction(SIGUSR1, &sa, nil);
87 }
89 void
90 _procsleep(_Procrendez *r)
91 {
92 sigset_t mask;
94 /*
95 * Go to sleep.
96 *
97 * Block USR1, set the handler to interrupt system calls,
98 * unlock the vouslock so our waker can wake us,
99 * and then suspend.
100 */
101 again:
102 r->asleep = 1;
103 r->pid = getpid();
105 sigprocmask(SIG_SETMASK, nil, &mask);
106 sigaddset(&mask, SIGUSR1);
107 sigprocmask(SIG_SETMASK, &mask, nil);
108 ignusr1(0);
109 unlock(r->l);
110 sigdelset(&mask, SIGUSR1);
111 sigsuspend(&mask);
113 /*
114 * We're awake. Make USR1 not interrupt system calls.
115 */
116 lock(r->l);
117 ignusr1(1);
118 if(r->asleep && r->pid == getpid()){
119 /* Didn't really wake up - signal from something else */
120 goto again;
124 void
125 _procwakeup(_Procrendez *r)
127 if(r->asleep){
128 r->asleep = 0;
129 assert(r->pid >= 1);
130 kill(r->pid, SIGUSR1);
134 void
135 _procwakeupandunlock(_Procrendez *r)
137 _procwakeup(r);
138 unlock(r->l);
142 /*
143 * process creation and exit
144 */
145 typedef struct Stackfree Stackfree;
146 struct Stackfree
148 Stackfree *next;
149 int pid;
150 };
151 static Lock stacklock;
152 static Stackfree *stackfree;
154 static void
155 delayfreestack(uchar *stk)
157 Stackfree *sf;
159 sf = (Stackfree*)stk;
160 sf->pid = getpid();
161 lock(&stacklock);
162 sf->next = stackfree;
163 stackfree = sf;
164 unlock(&stacklock);
167 static void
168 dofreestacks(void)
170 Stackfree *sf, *last, *next;
172 if(stackfree==nil || !canlock(&stacklock))
173 return;
175 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
176 next = sf->next;
177 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
178 free(sf);
179 if(last)
180 last->next = next;
181 else
182 stackfree = next;
183 sf = last;
186 unlock(&stacklock);
189 static int
190 startprocfn(void *v)
192 void **a;
193 uchar *stk;
194 void (*fn)(void*);
195 Proc *p;
197 a = (void**)v;
198 fn = a[0];
199 p = a[1];
200 stk = a[2];
201 free(a);
202 p->osprocid = getpid();
204 (*fn)(p);
206 delayfreestack(stk);
207 _exit(0);
208 return 0;
211 void
212 _procstart(Proc *p, void (*fn)(Proc*))
214 void **a;
215 uchar *stk;
216 int pid;
218 dofreestacks();
219 a = malloc(3*sizeof a[0]);
220 if(a == nil)
221 sysfatal("_procstart malloc: %r");
222 stk = malloc(65536);
223 if(stk == nil)
224 sysfatal("_procstart malloc stack: %r");
226 a[0] = fn;
227 a[1] = p;
228 a[2] = stk;
230 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
231 if(pid < 0){
232 fprint(2, "_procstart rfork_thread: %r\n");
233 abort();
237 static char *threadexitsmsg;
238 void
239 sigusr2handler(int s)
241 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
242 if(threadexitsmsg)
243 _exits(threadexitsmsg);
246 void
247 threadexitsall(char *msg)
249 static int pid[1024];
250 int i, npid, mypid;
251 Proc *p;
253 if(msg == nil)
254 msg = "";
255 mypid = getpid();
256 lock(&_threadprocslock);
257 threadexitsmsg = msg;
258 npid = 0;
259 for(p=_threadprocs; p; p=p->next)
260 if(p->osprocid != mypid && p->osprocid >= 1)
261 pid[npid++] = p->osprocid;
262 for(i=0; i<npid; i++)
263 kill(pid[i], SIGUSR2);
264 unlock(&_threadprocslock);
265 exits(msg);
268 /*
269 * per-process data, indexed by pid
271 * could use modify_ldt and a segment register
272 * to avoid the many calls to getpid(), but i don't
273 * care -- this is compatibility code. linux 2.6 with
274 * nptl is a good enough pthreads to avoid this whole file.
275 */
276 typedef struct Perproc Perproc;
277 struct Perproc
279 int pid;
280 Proc *proc;
281 };
283 static Lock perlock;
284 static Perproc perproc[1024];
285 #define P ((Proc*)-1)
287 static Perproc*
288 myperproc(void)
290 int i, pid, h;
291 Perproc *p;
293 pid = getpid();
294 h = pid%nelem(perproc);
295 for(i=0; i<nelem(perproc); i++){
296 p = &perproc[(i+h)%nelem(perproc)];
297 if(p->pid == pid)
298 return p;
299 if(p->pid == 0){
300 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
301 break;
304 fprint(2, "myperproc %d: cannot find self\n", pid);
305 abort();
306 return nil;
309 static Perproc*
310 newperproc(void)
312 int i, pid, h;
313 Perproc *p;
315 lock(&perlock);
316 pid = getpid();
317 h = pid%nelem(perproc);
318 for(i=0; i<nelem(perproc); i++){
319 p = &perproc[(i+h)%nelem(perproc)];
320 if(p->pid == pid || p->pid == -1 || p->pid == 0){
321 p->pid = pid;
322 unlock(&perlock);
323 return p;
326 fprint(2, "newperproc %d: out of procs\n", pid);
327 abort();
328 return nil;
331 Proc*
332 _threadproc(void)
334 return myperproc()->proc;
337 void
338 _threadsetproc(Proc *p)
340 Perproc *pp;
342 if(p)
343 p->osprocid = getpid();
344 pp = newperproc();
345 pp->proc = p;
346 if(p == nil)
347 pp->pid = -1;
350 void
351 _pthreadinit(void)
353 __isthreaded = 1;
354 signal(SIGUSR2, sigusr2handler);
357 void
358 _threadpexit(void)
360 _exit(0);
364 /*
365 * FreeBSD 4 and earlier needs the context functions.
366 */
367 void
368 makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
370 int *sp;
372 sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
373 sp -= argc;
374 memmove(sp, &argc+1, argc*sizeof(int));
375 *--sp = 0; /* return address */
376 ucp->uc_mcontext.mc_eip = (long)func;
377 ucp->uc_mcontext.mc_esp = (int)sp;
380 extern int getmcontext(mcontext_t*);
381 extern int setmcontext(mcontext_t*);
383 int
384 getcontext(ucontext_t *uc)
386 return getmcontext(&uc->uc_mcontext);
389 void
390 setcontext(ucontext_t *uc)
392 setmcontext(&uc->uc_mcontext);
395 int
396 swapcontext(ucontext_t *oucp, ucontext_t *ucp)
398 if(getcontext(oucp) == 0)
399 setcontext(ucp);
400 return 0;