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 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 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 = "";290 mypid = getpid();291 lock(&_threadprocslock);292 threadexitsmsg = msg;293 npid = 0;294 for(p=_threadprocs; p; p=p->next)295 if(p->osprocid != mypid && p->osprocid >= 1)296 pid[npid++] = p->osprocid;297 for(i=0; i<npid; i++)298 kill(pid[i], SIGUSR2);299 unlock(&_threadprocslock);300 exits(msg);301 }303 /*304 * per-process data, indexed by pid305 */306 typedef struct Perproc Perproc;307 struct Perproc308 {309 int pid;310 Proc *proc;311 };313 static Lock perlock;314 static Perproc perproc[1024];315 #define P ((Proc*)-1)317 static Perproc*318 myperproc(void)319 {320 int i, pid, h;321 Perproc *p;323 pid = getpid();324 h = pid%nelem(perproc);325 for(i=0; i<nelem(perproc); i++){326 p = &perproc[(i+h)%nelem(perproc)];327 if(p->pid == pid)328 return p;329 if(p->pid == 0){330 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);331 break;332 }333 }334 fprint(2, "myperproc %d: cannot find self\n", pid);335 abort();336 return nil;337 }339 static Perproc*340 newperproc(void)341 {342 int i, pid, h;343 Perproc *p;345 lock(&perlock);346 pid = getpid();347 h = pid%nelem(perproc);348 for(i=0; i<nelem(perproc); i++){349 p = &perproc[(i+h)%nelem(perproc)];350 if(p->pid == pid || p->pid == -1 || p->pid == 0){351 p->pid = pid;352 unlock(&perlock);353 return p;354 }355 }356 fprint(2, "newperproc %d: out of procs\n", pid);357 abort();358 return nil;359 }361 Proc*362 _threadproc(void)363 {364 return myperproc()->proc;365 }367 void368 _threadsetproc(Proc *p)369 {370 Perproc *pp;372 if(p)373 p->osprocid = getpid();374 pp = newperproc();375 pp->proc = p;376 if(p == nil)377 pp->pid = -1;378 }380 void381 _pthreadinit(void)382 {383 __isthreaded = 1;384 signal(SIGUSR2, sigusr2handler);385 }387 void388 _threadpexit(void)389 {390 _exit(0);391 }