Blob


1 #include "u.h"
2 #include <errno.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <sched.h>
6 #include <signal.h>
7 #include "libc.h"
8 #include "thread.h"
9 #include "threadimpl.h"
11 int ngetpid;
14 /*
15 * spin locks
16 */
17 extern int _tas(int*);
19 void
20 _threadunlock(Lock *l, ulong pc)
21 {
22 USED(pc);
24 l->held = 0;
25 }
27 int
28 _threadlock(Lock *l, int block, ulong pc)
29 {
30 int i;
32 USED(pc);
34 /* once fast */
35 if(!_tas(&l->held))
36 return 1;
37 if(!block)
38 return 0;
40 /* a thousand times pretty fast */
41 for(i=0; i<1000; i++){
42 if(!_tas(&l->held))
43 return 1;
44 sched_yield();
45 }
46 /* now nice and slow */
47 for(i=0; i<1000; i++){
48 if(!_tas(&l->held))
49 return 1;
50 usleep(100*1000);
51 }
52 /* take your time */
53 while(_tas(&l->held))
54 usleep(1000*1000);
55 return 1;
56 }
58 /*
59 * sleep and wakeup
60 */
61 static void
62 ign(int x)
63 {
64 USED(x);
65 }
67 static void /*__attribute__((constructor))*/
68 ignusr1(int restart)
69 {
70 struct sigaction sa;
72 memset(&sa, 0, sizeof sa);
73 sa.sa_handler = ign;
74 sigemptyset(&sa.sa_mask);
75 sigaddset(&sa.sa_mask, SIGUSR1);
76 if(restart)
77 sa.sa_flags = SA_RESTART;
78 sigaction(SIGUSR1, &sa, nil);
79 }
81 void
82 _procsleep(_Procrendez *r)
83 {
84 sigset_t mask;
86 /*
87 * Go to sleep.
88 *
89 * Block USR1, set the handler to interrupt system calls,
90 * unlock the vouslock so our waker can wake us,
91 * and then suspend.
92 */
93 again:
94 r->asleep = 1;
95 r->pid = getpid();
97 sigprocmask(SIG_SETMASK, nil, &mask);
98 sigaddset(&mask, SIGUSR1);
99 sigprocmask(SIG_SETMASK, &mask, nil);
100 ignusr1(0);
101 unlock(r->l);
102 sigdelset(&mask, SIGUSR1);
103 sigsuspend(&mask);
105 /*
106 * We're awake. Make USR1 not interrupt system calls.
107 */
108 lock(r->l);
109 ignusr1(1);
110 if(r->asleep && r->pid == getpid()){
111 /* Didn't really wake up - signal from something else */
112 goto again;
116 void
117 _procwakeup(_Procrendez *r)
119 if(r->asleep){
120 r->asleep = 0;
121 assert(r->pid >= 1);
122 kill(r->pid, SIGUSR1);
126 /*
127 * process creation and exit
128 */
129 typedef struct Stackfree Stackfree;
130 struct Stackfree
132 Stackfree *next;
133 int pid;
134 };
135 static Lock stacklock;
136 static Stackfree *stackfree;
138 static void
139 delayfreestack(uchar *stk)
141 Stackfree *sf;
143 sf = (Stackfree*)stk;
144 sf->pid = getpid();
145 lock(&stacklock);
146 sf->next = stackfree;
147 stackfree = sf;
148 unlock(&stacklock);
151 static void
152 dofreestacks(void)
154 Stackfree *sf, *last, *next;
156 if(stackfree==nil || !canlock(&stacklock))
157 return;
159 for(last=nil,sf=stackfree; sf; last=sf,sf=next){
160 next = sf->next;
161 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
162 free(sf);
163 if(last)
164 last->next = next;
165 else
166 stackfree = next;
167 sf = last;
170 unlock(&stacklock);
173 static int
174 startprocfn(void *v)
176 void **a;
177 uchar *stk;
178 void (*fn)(void*);
179 Proc *p;
181 a = (void**)v;
182 fn = a[0];
183 p = a[1];
184 stk = a[2];
185 free(a);
186 p->osprocid = getpid();
188 (*fn)(p);
190 delayfreestack(stk);
191 _exit(0);
192 return 0;
195 /*
196 * indirect through here so that parent need not wait for child zombie
198 * slight race - if child exits and then another process starts before we
199 * manage to exit, we'll be running on a freed stack.
200 */
201 static int
202 trampnowait(void *v)
204 void **a;
206 a = (void*)v;
207 *(int*)a[3] = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
208 _exit(0);
209 return 0;
212 void
213 _procstart(Proc *p, void (*fn)(Proc*))
215 void **a;
216 uchar *stk;
217 int pid, kidpid, status;
219 dofreestacks();
220 a = malloc(4*sizeof a[0]);
221 if(a == nil)
222 sysfatal("_procstart malloc: %r");
223 stk = malloc(65536);
224 if(stk == nil)
225 sysfatal("_procstart malloc stack: %r");
227 a[0] = fn;
228 a[1] = p;
229 a[2] = stk;
230 a[3] = &kidpid;
231 kidpid = -1;
233 pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
234 if(pid > 0)
235 if(wait4(pid, &status, __WALL, 0) < 0)
236 fprint(2, "ffork wait4: %r\n");
237 if(pid < 0 || kidpid < 0){
238 fprint(2, "_procstart clone: %r\n");
239 abort();
243 static char *threadexitsmsg;
244 void
245 sigusr2handler(int s)
247 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
248 if(threadexitsmsg)
249 _exits(threadexitsmsg);
252 void
253 threadexitsall(char *msg)
255 static int pid[1024];
256 int i, npid, mypid;
257 Proc *p;
259 if(msg == nil)
260 msg = "";
261 mypid = getpid();
262 lock(&_threadprocslock);
263 threadexitsmsg = msg;
264 npid = 0;
265 for(p=_threadprocs; p; p=p->next)
266 if(p->osprocid != mypid && p->osprocid >= 1)
267 pid[npid++] = p->osprocid;
268 for(i=0; i<npid; i++)
269 kill(pid[i], SIGUSR2);
270 unlock(&_threadprocslock);
271 exits(msg);
274 /*
275 * per-process data, indexed by pid
277 * could use modify_ldt and a segment register
278 * to avoid the many calls to getpid(), but i don't
279 * care -- this is compatibility code. linux 2.6 with
280 * nptl is a good enough pthreads to avoid this whole file.
281 */
282 typedef struct Perproc Perproc;
283 struct Perproc
285 int pid;
286 Proc *proc;
287 };
289 static Lock perlock;
290 static Perproc perproc[1024];
291 #define P ((Proc*)-1)
293 static Perproc*
294 myperproc(void)
296 int i, pid, h;
297 Perproc *p;
299 pid = getpid();
300 h = pid%nelem(perproc);
301 for(i=0; i<nelem(perproc); i++){
302 p = &perproc[(i+h)%nelem(perproc)];
303 if(p->pid == pid)
304 return p;
305 if(p->pid == 0){
306 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
307 break;
310 fprint(2, "myperproc %d: cannot find self\n", pid);
311 abort();
312 return nil;
315 static Perproc*
316 newperproc(void)
318 int i, pid, h;
319 Perproc *p;
321 lock(&perlock);
322 pid = getpid();
323 h = pid%nelem(perproc);
324 for(i=0; i<nelem(perproc); i++){
325 p = &perproc[(i+h)%nelem(perproc)];
326 if(p->pid == pid || p->pid == -1 || p->pid == 0){
327 p->pid = pid;
328 unlock(&perlock);
329 return p;
332 fprint(2, "newperproc %d: out of procs\n", pid);
333 abort();
334 return nil;
337 Proc*
338 _threadproc(void)
340 return myperproc()->proc;
343 void
344 _threadsetproc(Proc *p)
346 Perproc *pp;
348 if(p)
349 p->osprocid = getpid();
350 pp = newperproc();
351 pp->proc = p;
352 if(p == nil)
353 pp->pid = -1;
356 void
357 _pthreadinit(void)
359 signal(SIGUSR2, sigusr2handler);