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 sched_yield();
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 = "";
290 mypid = getpid();
291 lock(&_threadprocslock);
292 threadexitsmsg = msg;
293 npid = 0;
294 for(p=_threadprocs; p; p=p->next)
295 if(p->osprocid != mypid && p->osprocid >= 1)
296 pid[npid++] = p->osprocid;
297 for(i=0; i<npid; i++)
298 kill(pid[i], SIGUSR2);
299 unlock(&_threadprocslock);
300 exits(msg);
303 /*
304 * per-process data, indexed by pid
305 */
306 typedef struct Perproc Perproc;
307 struct Perproc
309 int pid;
310 Proc *proc;
311 };
313 static Lock perlock;
314 static Perproc perproc[1024];
315 #define P ((Proc*)-1)
317 static Perproc*
318 myperproc(void)
320 int i, pid, h;
321 Perproc *p;
323 pid = getpid();
324 h = pid%nelem(perproc);
325 for(i=0; i<nelem(perproc); i++){
326 p = &perproc[(i+h)%nelem(perproc)];
327 if(p->pid == pid)
328 return p;
329 if(p->pid == 0){
330 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
331 break;
334 fprint(2, "myperproc %d: cannot find self\n", pid);
335 abort();
336 return nil;
339 static Perproc*
340 newperproc(void)
342 int i, pid, h;
343 Perproc *p;
345 lock(&perlock);
346 pid = getpid();
347 h = pid%nelem(perproc);
348 for(i=0; i<nelem(perproc); i++){
349 p = &perproc[(i+h)%nelem(perproc)];
350 if(p->pid == pid || p->pid == -1 || p->pid == 0){
351 p->pid = pid;
352 unlock(&perlock);
353 return p;
356 fprint(2, "newperproc %d: out of procs\n", pid);
357 abort();
358 return nil;
361 Proc*
362 _threadproc(void)
364 return myperproc()->proc;
367 void
368 _threadsetproc(Proc *p)
370 Perproc *pp;
372 if(p)
373 p->osprocid = getpid();
374 pp = newperproc();
375 pp->proc = p;
376 if(p == nil)
377 pp->pid = -1;
380 void
381 _pthreadinit(void)
383 __isthreaded = 1;
384 signal(SIGUSR2, sigusr2handler);
387 void
388 _threadpexit(void)
390 _exit(0);