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 /*
94 * sleep and wakeup
95 */
96 static void
97 ign(int x)
98 {
99 USED(x);
102 static void /*__attribute__((constructor))*/
103 ignusr1(int restart)
105 struct sigaction sa;
107 memset(&sa, 0, sizeof sa);
108 sa.sa_handler = ign;
109 sigemptyset(&sa.sa_mask);
110 sigaddset(&sa.sa_mask, SIGUSR1);
111 if(restart)
112 sa.sa_flags = SA_RESTART;
113 sigaction(SIGUSR1, &sa, nil);
116 void
117 _procsleep(_Procrendez *r)
119 sigset_t mask;
121 /*
122 * Go to sleep.
124 * Block USR1, set the handler to interrupt system calls,
125 * unlock the vouslock so our waker can wake us,
126 * and then suspend.
127 */
128 again:
129 r->asleep = 1;
130 r->pid = getpid();
132 sigprocmask(SIG_SETMASK, nil, &mask);
133 sigaddset(&mask, SIGUSR1);
134 sigprocmask(SIG_SETMASK, &mask, nil);
135 ignusr1(0);
136 unlock(r->l);
137 sigdelset(&mask, SIGUSR1);
138 sigsuspend(&mask);
140 /*
141 * We're awake. Make USR1 not interrupt system calls.
142 */
143 lock(r->l);
144 ignusr1(1);
145 if(r->asleep && r->pid == getpid()){
146 /* Didn't really wake up - signal from something else */
147 goto again;
151 void
152 _procwakeup(_Procrendez *r)
154 if(r->asleep){
155 r->asleep = 0;
156 assert(r->pid >= 1);
157 kill(r->pid, SIGUSR1);
161 void
162 _procwakeupandunlock(_Procrendez *r)
164 _procwakeup(r);
165 unlock(r->l);
169 /*
170 * process creation and exit
171 */
172 typedef struct Stackfree Stackfree;
173 struct Stackfree
175 Stackfree *next;
176 int pid;
177 };
178 static Lock stacklock;
179 static Stackfree *stackfree;
181 static void
182 delayfreestack(uchar *stk)
184 Stackfree *sf;
186 sf = (Stackfree*)stk;
187 sf->pid = getpid();
188 lock(&stacklock);
189 sf->next = stackfree;
190 stackfree = sf;
191 unlock(&stacklock);
194 static void
195 dofreestacks(void)
197 Stackfree *sf, *last, *next;
199 if(stackfree==nil || !canlock(&stacklock))
200 return;
202 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
203 next = sf->next;
204 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
205 free(sf);
206 if(last)
207 last->next = next;
208 else
209 stackfree = next;
210 sf = last;
213 unlock(&stacklock);
216 static int
217 startprocfn(void *v)
219 void **a;
220 uchar *stk;
221 void (*fn)(void*);
222 Proc *p;
224 a = (void**)v;
225 fn = a[0];
226 p = a[1];
227 stk = a[2];
228 free(a);
229 p->osprocid = getpid();
231 (*fn)(p);
233 delayfreestack(stk);
234 _exit(0);
235 return 0;
238 void
239 _procstart(Proc *p, void (*fn)(Proc*))
241 void **a;
242 uchar *stk;
243 int pid;
245 dofreestacks();
246 a = malloc(3*sizeof a[0]);
247 if(a == nil)
248 sysfatal("_procstart malloc: %r");
249 stk = malloc(65536);
250 if(stk == nil)
251 sysfatal("_procstart malloc stack: %r");
253 a[0] = fn;
254 a[1] = p;
255 a[2] = stk;
257 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
258 if(pid < 0){
259 fprint(2, "_procstart rfork_thread: %r\n");
260 abort();
264 static char *threadexitsmsg;
265 void
266 sigusr2handler(int s)
268 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
269 if(threadexitsmsg)
270 _exits(threadexitsmsg);
273 void
274 threadexitsall(char *msg)
276 static int pid[1024];
277 int i, npid, mypid;
278 Proc *p;
280 if(msg == nil)
281 msg = "";
282 mypid = getpid();
283 lock(&_threadprocslock);
284 threadexitsmsg = msg;
285 npid = 0;
286 for(p=_threadprocs; p; p=p->next)
287 if(p->osprocid != mypid && p->osprocid >= 1)
288 pid[npid++] = p->osprocid;
289 for(i=0; i<npid; i++)
290 kill(pid[i], SIGUSR2);
291 unlock(&_threadprocslock);
292 exits(msg);
295 /*
296 * per-process data, indexed by pid
297 */
298 typedef struct Perproc Perproc;
299 struct Perproc
301 int pid;
302 Proc *proc;
303 };
305 static Lock perlock;
306 static Perproc perproc[1024];
307 #define P ((Proc*)-1)
309 static Perproc*
310 myperproc(void)
312 int i, pid, h;
313 Perproc *p;
315 pid = getpid();
316 h = pid%nelem(perproc);
317 for(i=0; i<nelem(perproc); i++){
318 p = &perproc[(i+h)%nelem(perproc)];
319 if(p->pid == pid)
320 return p;
321 if(p->pid == 0){
322 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
323 break;
326 fprint(2, "myperproc %d: cannot find self\n", pid);
327 abort();
328 return nil;
331 static Perproc*
332 newperproc(void)
334 int i, pid, h;
335 Perproc *p;
337 lock(&perlock);
338 pid = getpid();
339 h = pid%nelem(perproc);
340 for(i=0; i<nelem(perproc); i++){
341 p = &perproc[(i+h)%nelem(perproc)];
342 if(p->pid == pid || p->pid == -1 || p->pid == 0){
343 p->pid = pid;
344 unlock(&perlock);
345 return p;
348 fprint(2, "newperproc %d: out of procs\n", pid);
349 abort();
350 return nil;
353 Proc*
354 _threadproc(void)
356 return myperproc()->proc;
359 void
360 _threadsetproc(Proc *p)
362 Perproc *pp;
364 if(p)
365 p->osprocid = getpid();
366 pp = newperproc();
367 pp->proc = p;
368 if(p == nil)
369 pp->pid = -1;
372 void
373 _pthreadinit(void)
375 __isthreaded = 1;
376 signal(SIGUSR2, sigusr2handler);
379 void
380 _threadpexit(void)
382 _exit(0);