Blob
1 #undef exits2 #undef _exits4 extern int __isthreaded;6 /*7 * spin locks8 */9 extern int _tas(int*);11 void12 _threadunlock(Lock *l, ulong pc)13 {14 USED(pc);16 l->held = 0;17 }19 int20 _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 sleep(0);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 void88 _spinlock(spinlock_t *lk)89 {90 lock((Lock*)&lk->access_lock);91 }93 void94 _spinunlock(spinlock_t *lk)95 {96 unlock((Lock*)&lk->access_lock);97 }101 /*102 * sleep and wakeup103 */104 static void105 ign(int x)106 {107 USED(x);108 }110 static void /*__attribute__((constructor))*/111 ignusr1(int restart)112 {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);122 }124 void125 _procsleep(_Procrendez *r)126 {127 sigset_t mask;129 /*130 * Go to sleep.131 *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;156 }157 }159 void160 _procwakeup(_Procrendez *r)161 {162 if(r->asleep){163 r->asleep = 0;164 assert(r->pid >= 1);165 kill(r->pid, SIGUSR1);166 }167 }169 void170 _procwakeupandunlock(_Procrendez *r)171 {172 _procwakeup(r);173 unlock(r->l);174 }177 /*178 * process creation and exit179 */180 typedef struct Stackfree Stackfree;181 struct Stackfree182 {183 Stackfree *next;184 int pid;185 };186 static Lock stacklock;187 static Stackfree *stackfree;189 static void190 delayfreestack(uchar *stk)191 {192 Stackfree *sf;194 sf = (Stackfree*)stk;195 sf->pid = getpid();196 lock(&stacklock);197 sf->next = stackfree;198 stackfree = sf;199 unlock(&stacklock);200 }202 static void203 dofreestacks(void)204 {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 else217 stackfree = next;218 sf = last;219 }220 }221 unlock(&stacklock);222 }224 static int225 startprocfn(void *v)226 {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;244 }246 void247 _procstart(Proc *p, void (*fn)(Proc*))248 {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();269 }270 }272 static char *threadexitsmsg;273 void274 sigusr2handler(int s)275 {276 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */277 if(threadexitsmsg)278 _exits(threadexitsmsg);279 }281 void282 threadexitsall(char *msg)283 {284 static int pid[1024];285 int i, npid, mypid;286 Proc *p;288 if(msg == nil)289 msg = "";291 /*292 * Only one guy, ever, gets to run this.293 * If two guys do it, inevitably they end up294 * tripping over each other in the underlying295 * C library exit() implementation, which is296 * trying to run the atexit handlers and apparently297 * not thread safe. This has been observed on298 * both Linux and OpenBSD. Sigh.299 */300 {301 static Lock onelock;302 if(!canlock(&onelock))303 _exits(threadexitsmsg);304 threadexitsmsg = msg;305 }307 if(msg == nil)308 msg = "";309 mypid = getpid();310 lock(&_threadprocslock);311 threadexitsmsg = msg;312 npid = 0;313 for(p=_threadprocs; p; p=p->next)314 if(p->osprocid != mypid && p->osprocid >= 1)315 pid[npid++] = p->osprocid;316 for(i=0; i<npid; i++)317 kill(pid[i], SIGUSR2);318 unlock(&_threadprocslock);319 exits(msg);320 }322 /*323 * per-process data, indexed by pid324 */325 typedef struct Perproc Perproc;326 struct Perproc327 {328 int pid;329 Proc *proc;330 };332 static Lock perlock;333 static Perproc perproc[1024];334 #define P ((Proc*)-1)336 static Perproc*337 myperproc(void)338 {339 int i, pid, h;340 Perproc *p;342 pid = getpid();343 h = pid%nelem(perproc);344 for(i=0; i<nelem(perproc); i++){345 p = &perproc[(i+h)%nelem(perproc)];346 if(p->pid == pid)347 return p;348 if(p->pid == 0){349 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);350 break;351 }352 }353 fprint(2, "myperproc %d: cannot find self\n", pid);354 abort();355 return nil;356 }358 static Perproc*359 newperproc(void)360 {361 int i, pid, h;362 Perproc *p;364 lock(&perlock);365 pid = getpid();366 h = pid%nelem(perproc);367 for(i=0; i<nelem(perproc); i++){368 p = &perproc[(i+h)%nelem(perproc)];369 if(p->pid == pid || p->pid == -1 || p->pid == 0){370 p->pid = pid;371 unlock(&perlock);372 return p;373 }374 }375 fprint(2, "newperproc %d: out of procs\n", pid);376 abort();377 return nil;378 }380 Proc*381 _threadproc(void)382 {383 return myperproc()->proc;384 }386 void387 _threadsetproc(Proc *p)388 {389 Perproc *pp;391 if(p)392 p->osprocid = getpid();393 pp = newperproc();394 pp->proc = p;395 if(p == nil)396 pp->pid = -1;397 }399 void400 _threadpexit(void)401 {402 _exit(0);403 }