Blob


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