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 /*
135 * process creation and exit
136 */
137 typedef struct Stackfree Stackfree;
138 struct Stackfree
140 Stackfree *next;
141 int pid;
142 };
143 static Lock stacklock;
144 static Stackfree *stackfree;
146 static void
147 delayfreestack(uchar *stk)
149 Stackfree *sf;
151 sf = (Stackfree*)stk;
152 sf->pid = getpid();
153 lock(&stacklock);
154 sf->next = stackfree;
155 stackfree = sf;
156 unlock(&stacklock);
159 static void
160 dofreestacks(void)
162 Stackfree *sf, *last, *next;
164 if(stackfree==nil || !canlock(&stacklock))
165 return;
167 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
168 next = sf->next;
169 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
170 free(sf);
171 if(last)
172 last->next = next;
173 else
174 stackfree = next;
175 sf = last;
178 unlock(&stacklock);
181 static int
182 startprocfn(void *v)
184 void **a;
185 uchar *stk;
186 void (*fn)(void*);
187 Proc *p;
189 a = (void**)v;
190 fn = a[0];
191 p = a[1];
192 stk = a[2];
193 free(a);
194 p->osprocid = getpid();
196 (*fn)(p);
198 delayfreestack(stk);
199 _exit(0);
200 return 0;
203 void
204 _procstart(Proc *p, void (*fn)(Proc*))
206 void **a;
207 uchar *stk;
208 int pid;
210 dofreestacks();
211 a = malloc(3*sizeof a[0]);
212 if(a == nil)
213 sysfatal("_procstart malloc: %r");
214 stk = malloc(65536);
215 if(stk == nil)
216 sysfatal("_procstart malloc stack: %r");
218 a[0] = fn;
219 a[1] = p;
220 a[2] = stk;
222 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
223 if(pid < 0){
224 fprint(2, "_procstart rfork_thread: %r\n");
225 abort();
229 static char *threadexitsmsg;
230 void
231 sigusr2handler(int s)
233 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
234 if(threadexitsmsg)
235 _exits(threadexitsmsg);
238 void
239 threadexitsall(char *msg)
241 static int pid[1024];
242 int i, npid, mypid;
243 Proc *p;
245 if(msg == nil)
246 msg = "";
247 mypid = getpid();
248 lock(&_threadprocslock);
249 threadexitsmsg = msg;
250 npid = 0;
251 for(p=_threadprocs; p; p=p->next)
252 if(p->osprocid != mypid && p->osprocid >= 1)
253 pid[npid++] = p->osprocid;
254 for(i=0; i<npid; i++)
255 kill(pid[i], SIGUSR2);
256 unlock(&_threadprocslock);
257 exits(msg);
260 /*
261 * per-process data, indexed by pid
263 * could use modify_ldt and a segment register
264 * to avoid the many calls to getpid(), but i don't
265 * care -- this is compatibility code. linux 2.6 with
266 * nptl is a good enough pthreads to avoid this whole file.
267 */
268 typedef struct Perproc Perproc;
269 struct Perproc
271 int pid;
272 Proc *proc;
273 };
275 static Lock perlock;
276 static Perproc perproc[1024];
277 #define P ((Proc*)-1)
279 static Perproc*
280 myperproc(void)
282 int i, pid, h;
283 Perproc *p;
285 pid = getpid();
286 h = pid%nelem(perproc);
287 for(i=0; i<nelem(perproc); i++){
288 p = &perproc[(i+h)%nelem(perproc)];
289 if(p->pid == pid)
290 return p;
291 if(p->pid == 0){
292 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
293 break;
296 fprint(2, "myperproc %d: cannot find self\n", pid);
297 abort();
298 return nil;
301 static Perproc*
302 newperproc(void)
304 int i, pid, h;
305 Perproc *p;
307 lock(&perlock);
308 pid = getpid();
309 h = pid%nelem(perproc);
310 for(i=0; i<nelem(perproc); i++){
311 p = &perproc[(i+h)%nelem(perproc)];
312 if(p->pid == pid || p->pid == -1 || p->pid == 0){
313 p->pid = pid;
314 unlock(&perlock);
315 return p;
318 fprint(2, "newperproc %d: out of procs\n", pid);
319 abort();
320 return nil;
323 Proc*
324 _threadproc(void)
326 return myperproc()->proc;
329 void
330 _threadsetproc(Proc *p)
332 Perproc *pp;
334 if(p)
335 p->osprocid = getpid();
336 pp = newperproc();
337 pp->proc = p;
338 if(p == nil)
339 pp->pid = -1;
342 void
343 _pthreadinit(void)
345 __isthreaded = 1;
346 signal(SIGUSR2, sigusr2handler);
349 void
350 _threadpexit(void)
352 _exit(0);
356 /*
357 * FreeBSD 4 and earlier needs the context functions.
358 */
359 void
360 makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
362 int *sp;
364 sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
365 sp -= argc;
366 memmove(sp, &argc+1, argc*sizeof(int));
367 *--sp = 0; /* return address */
368 ucp->uc_mcontext.mc_eip = (long)func;
369 ucp->uc_mcontext.mc_esp = (int)sp;
372 extern int getmcontext(mcontext_t*);
373 extern int setmcontext(mcontext_t*);
375 int
376 getcontext(ucontext_t *uc)
378 return getmcontext(&uc->uc_mcontext);
381 void
382 setcontext(ucontext_t *uc)
384 setmcontext(&uc->uc_mcontext);
387 int
388 swapcontext(ucontext_t *oucp, ucontext_t *ucp)
390 if(getcontext(oucp) == 0)
391 setcontext(ucp);
392 return 0;