Blob


1 #include "threadimpl.h"
3 static int
4 timefmt(Fmt *fmt)
5 {
6 static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
7 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
8 vlong ns;
9 Tm tm;
10 ns = nsec();
11 tm = *localtime(time(0));
12 return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
13 mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
14 (int)(ns%1000000000)/1000000);
15 }
17 /*
18 * spin locks
19 */
20 extern int _tas(int*);
22 void
23 _threadunlock(Lock *l, ulong pc)
24 {
25 USED(pc);
27 l->held = 0;
28 }
30 int
31 _threadlock(Lock *l, int block, ulong pc)
32 {
33 int i;
34 static int first=1;
35 if(first) {first=0; fmtinstall('\001', timefmt);}
37 USED(pc);
39 /* once fast */
40 if(!_tas(&l->held))
41 return 1;
42 if(!block)
43 return 0;
45 /* a thousand times pretty fast */
46 for(i=0; i<1000; i++){
47 if(!_tas(&l->held))
48 return 1;
49 sched_yield();
50 }
51 /* now increasingly slow */
52 for(i=0; i<10; i++){
53 if(!_tas(&l->held))
54 return 1;
55 usleep(1);
56 }
57 fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
58 for(i=0; i<10; i++){
59 if(!_tas(&l->held))
60 return 1;
61 usleep(10);
62 }
63 fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
64 for(i=0; i<10; i++){
65 if(!_tas(&l->held))
66 return 1;
67 usleep(100);
68 }
69 fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
70 for(i=0; i<10; i++){
71 if(!_tas(&l->held))
72 return 1;
73 usleep(1000);
74 }
75 fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
76 for(i=0; i<10; i++){
77 if(!_tas(&l->held))
78 return 1;
79 usleep(10*1000);
80 }
81 fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
82 for(i=0; i<1000; i++){
83 if(!_tas(&l->held))
84 return 1;
85 usleep(100*1000);
86 }
87 fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
88 /* take your time */
89 while(_tas(&l->held))
90 usleep(1000*1000);
91 return 1;
92 }
94 /*
95 * sleep and wakeup
96 */
97 static void
98 ign(int x)
99 {
100 USED(x);
103 static void /*__attribute__((constructor))*/
104 ignusr1(int restart)
106 struct sigaction sa;
108 memset(&sa, 0, sizeof sa);
109 sa.sa_handler = ign;
110 sigemptyset(&sa.sa_mask);
111 sigaddset(&sa.sa_mask, SIGUSR1);
112 if(restart)
113 sa.sa_flags = SA_RESTART;
114 sigaction(SIGUSR1, &sa, nil);
117 void
118 _procsleep(_Procrendez *r)
120 sigset_t mask;
122 /*
123 * Go to sleep.
125 * Block USR1, set the handler to interrupt system calls,
126 * unlock the vouslock so our waker can wake us,
127 * and then suspend.
128 */
129 again:
130 r->asleep = 1;
131 r->pid = getpid();
133 sigprocmask(SIG_SETMASK, nil, &mask);
134 sigaddset(&mask, SIGUSR1);
135 sigprocmask(SIG_SETMASK, &mask, nil);
136 ignusr1(0);
137 unlock(r->l);
138 sigdelset(&mask, SIGUSR1);
139 sigsuspend(&mask);
141 /*
142 * We're awake. Make USR1 not interrupt system calls.
143 */
144 lock(r->l);
145 ignusr1(1);
146 if(r->asleep && r->pid == getpid()){
147 /* Didn't really wake up - signal from something else */
148 goto again;
152 void
153 _procwakeupandunlock(_Procrendez *r)
155 int pid;
157 pid = 0;
158 if(r->asleep){
159 r->asleep = 0;
160 assert(r->pid >= 1);
161 pid = r->pid;
163 assert(r->l);
164 unlock(r->l);
165 if(pid)
166 kill(pid, SIGUSR1);
169 /*
170 * process creation and exit
171 */
172 typedef struct Stackfree Stackfree;
173 struct Stackfree
175 Stackfree *next;
176 int pid;
177 int pid1;
178 };
179 static Lock stacklock;
180 static Stackfree *stackfree;
182 static void
183 delayfreestack(uchar *stk, int pid, int pid1)
185 Stackfree *sf;
187 sf = (Stackfree*)stk;
188 sf->pid = pid;
189 sf->pid1 = pid1;
190 lock(&stacklock);
191 sf->next = stackfree;
192 stackfree = sf;
193 unlock(&stacklock);
196 static void
197 dofreestacks(void)
199 Stackfree *sf, *last, *next;
201 if(stackfree==nil || !canlock(&stacklock))
202 return;
204 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
205 next = sf->next;
206 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
207 if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
208 free(sf);
209 if(last)
210 last->next = next;
211 else
212 stackfree = next;
213 sf = last;
216 unlock(&stacklock);
219 static int
220 startprocfn(void *v)
222 void **a;
223 uchar *stk;
224 void (*fn)(void*);
225 Proc *p;
226 int pid0, pid1;
228 a = (void**)v;
229 fn = a[0];
230 p = a[1];
231 stk = a[2];
232 pid0 = (int)a[4];
233 pid1 = getpid();
234 free(a);
235 p->osprocid = pid1;
237 (*fn)(p);
239 delayfreestack(stk, pid0, pid1);
240 _exit(0);
241 return 0;
244 /*
245 * indirect through here so that parent need not wait for child zombie
247 * slight race - if child exits and then another process starts before we
248 * manage to exit, we'll be running on a freed stack.
249 */
250 static int
251 trampnowait(void *v)
253 void **a;
254 int *kidpid;
256 a = (void*)v;
257 kidpid = a[3];
258 a[4] = (void*)getpid();
259 *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
260 _exit(0);
261 return 0;
264 void
265 _procstart(Proc *p, void (*fn)(Proc*))
267 void **a;
268 uchar *stk;
269 int pid, kidpid, status;
271 dofreestacks();
272 a = malloc(5*sizeof a[0]);
273 if(a == nil)
274 sysfatal("_procstart malloc: %r");
275 stk = malloc(65536);
276 if(stk == nil)
277 sysfatal("_procstart malloc stack: %r");
279 a[0] = fn;
280 a[1] = p;
281 a[2] = stk;
282 a[3] = &kidpid;
283 kidpid = -1;
285 pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
286 if(pid > 0)
287 if(wait4(pid, &status, __WALL, 0) < 0)
288 fprint(2, "ffork wait4: %r\n");
289 if(pid < 0 || kidpid < 0){
290 fprint(2, "_procstart clone: %r\n");
291 abort();
295 static char *threadexitsmsg;
296 void
297 sigusr2handler(int s)
299 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
300 if(threadexitsmsg)
301 _exits(threadexitsmsg);
304 void
305 threadexitsall(char *msg)
307 static int pid[1024];
308 int i, npid, mypid;
309 Proc *p;
311 if(msg == nil)
312 msg = "";
313 mypid = getpid();
314 lock(&_threadprocslock);
315 threadexitsmsg = msg;
316 npid = 0;
317 for(p=_threadprocs; p; p=p->next)
318 if(p->osprocid != mypid && p->osprocid >= 1)
319 pid[npid++] = p->osprocid;
320 for(i=0; i<npid; i++)
321 kill(pid[i], SIGUSR2);
322 unlock(&_threadprocslock);
323 exits(msg);
326 /*
327 * per-process data, indexed by pid
329 * could use modify_ldt and a segment register
330 * to avoid the many calls to getpid(), but i don't
331 * care -- this is compatibility code. linux 2.6 with
332 * nptl is a good enough pthreads to avoid this whole file.
333 */
334 typedef struct Perproc Perproc;
335 struct Perproc
337 int pid;
338 Proc *proc;
339 };
341 static Lock perlock;
342 static Perproc perproc[1024];
343 #define P ((Proc*)-1)
345 static Perproc*
346 myperproc(void)
348 int i, pid, h;
349 Perproc *p;
351 pid = getpid();
352 h = pid%nelem(perproc);
353 for(i=0; i<nelem(perproc); i++){
354 p = &perproc[(i+h)%nelem(perproc)];
355 if(p->pid == pid)
356 return p;
357 if(p->pid == 0){
358 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
359 break;
362 fprint(2, "myperproc %d: cannot find self\n", pid);
363 abort();
364 return nil;
367 static Perproc*
368 newperproc(void)
370 int i, pid, h;
371 Perproc *p;
373 lock(&perlock);
374 pid = getpid();
375 h = pid%nelem(perproc);
376 for(i=0; i<nelem(perproc); i++){
377 p = &perproc[(i+h)%nelem(perproc)];
378 if(p->pid == pid || p->pid == -1 || p->pid == 0){
379 p->pid = pid;
380 unlock(&perlock);
381 return p;
384 fprint(2, "newperproc %d: out of procs\n", pid);
385 abort();
386 return nil;
389 Proc*
390 _threadproc(void)
392 return myperproc()->proc;
395 void
396 _threadsetproc(Proc *p)
398 Perproc *pp;
400 if(p)
401 p->osprocid = getpid();
402 pp = newperproc();
403 pp->proc = p;
404 if(p == nil)
405 pp->pid = -1;
408 void
409 _pthreadinit(void)
411 signal(SIGUSR2, sigusr2handler);
414 void
415 _threadpexit(void)
417 _exit(0);