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 /*94 * sleep and wakeup95 */96 static void97 ign(int x)98 {99 USED(x);100 }102 static void /*__attribute__((constructor))*/103 ignusr1(int restart)104 {105 struct sigaction sa;107 memset(&sa, 0, sizeof sa);108 sa.sa_handler = ign;109 sigemptyset(&sa.sa_mask);110 sigaddset(&sa.sa_mask, SIGUSR1);111 if(restart)112 sa.sa_flags = SA_RESTART;113 sigaction(SIGUSR1, &sa, nil);114 }116 void117 _procsleep(_Procrendez *r)118 {119 sigset_t mask;121 /*122 * Go to sleep.123 *124 * Block USR1, set the handler to interrupt system calls,125 * unlock the vouslock so our waker can wake us,126 * and then suspend.127 */128 again:129 r->asleep = 1;130 r->pid = getpid();132 sigprocmask(SIG_SETMASK, nil, &mask);133 sigaddset(&mask, SIGUSR1);134 sigprocmask(SIG_SETMASK, &mask, nil);135 ignusr1(0);136 unlock(r->l);137 sigdelset(&mask, SIGUSR1);138 sigsuspend(&mask);140 /*141 * We're awake. Make USR1 not interrupt system calls.142 */143 lock(r->l);144 ignusr1(1);145 if(r->asleep && r->pid == getpid()){146 /* Didn't really wake up - signal from something else */147 goto again;148 }149 }151 void152 _procwakeup(_Procrendez *r)153 {154 if(r->asleep){155 r->asleep = 0;156 assert(r->pid >= 1);157 kill(r->pid, SIGUSR1);158 }159 }161 void162 _procwakeupandunlock(_Procrendez *r)163 {164 _procwakeup(r);165 unlock(r->l);166 }169 /*170 * process creation and exit171 */172 typedef struct Stackfree Stackfree;173 struct Stackfree174 {175 Stackfree *next;176 int pid;177 };178 static Lock stacklock;179 static Stackfree *stackfree;181 static void182 delayfreestack(uchar *stk)183 {184 Stackfree *sf;186 sf = (Stackfree*)stk;187 sf->pid = getpid();188 lock(&stacklock);189 sf->next = stackfree;190 stackfree = sf;191 unlock(&stacklock);192 }194 static void195 dofreestacks(void)196 {197 Stackfree *sf, *last, *next;199 if(stackfree==nil || !canlock(&stacklock))200 return;202 for(last=nil,sf=stackfree; sf; last=sf,sf=next){203 next = sf->next;204 if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){205 free(sf);206 if(last)207 last->next = next;208 else209 stackfree = next;210 sf = last;211 }212 }213 unlock(&stacklock);214 }216 static int217 startprocfn(void *v)218 {219 void **a;220 uchar *stk;221 void (*fn)(void*);222 Proc *p;224 a = (void**)v;225 fn = a[0];226 p = a[1];227 stk = a[2];228 free(a);229 p->osprocid = getpid();231 (*fn)(p);233 delayfreestack(stk);234 _exit(0);235 return 0;236 }238 void239 _procstart(Proc *p, void (*fn)(Proc*))240 {241 void **a;242 uchar *stk;243 int pid;245 dofreestacks();246 a = malloc(3*sizeof a[0]);247 if(a == nil)248 sysfatal("_procstart malloc: %r");249 stk = malloc(65536);250 if(stk == nil)251 sysfatal("_procstart malloc stack: %r");253 a[0] = fn;254 a[1] = p;255 a[2] = stk;257 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);258 if(pid < 0){259 fprint(2, "_procstart rfork_thread: %r\n");260 abort();261 }262 }264 static char *threadexitsmsg;265 void266 sigusr2handler(int s)267 {268 /* fprint(2, "%d usr2 %d\n", time(0), getpid()); */269 if(threadexitsmsg)270 _exits(threadexitsmsg);271 }273 void274 threadexitsall(char *msg)275 {276 static int pid[1024];277 int i, npid, mypid;278 Proc *p;280 if(msg == nil)281 msg = "";282 mypid = getpid();283 lock(&_threadprocslock);284 threadexitsmsg = msg;285 npid = 0;286 for(p=_threadprocs; p; p=p->next)287 if(p->osprocid != mypid && p->osprocid >= 1)288 pid[npid++] = p->osprocid;289 for(i=0; i<npid; i++)290 kill(pid[i], SIGUSR2);291 unlock(&_threadprocslock);292 exits(msg);293 }295 /*296 * per-process data, indexed by pid297 */298 typedef struct Perproc Perproc;299 struct Perproc300 {301 int pid;302 Proc *proc;303 };305 static Lock perlock;306 static Perproc perproc[1024];307 #define P ((Proc*)-1)309 static Perproc*310 myperproc(void)311 {312 int i, pid, h;313 Perproc *p;315 pid = getpid();316 h = pid%nelem(perproc);317 for(i=0; i<nelem(perproc); i++){318 p = &perproc[(i+h)%nelem(perproc)];319 if(p->pid == pid)320 return p;321 if(p->pid == 0){322 print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);323 break;324 }325 }326 fprint(2, "myperproc %d: cannot find self\n", pid);327 abort();328 return nil;329 }331 static Perproc*332 newperproc(void)333 {334 int i, pid, h;335 Perproc *p;337 lock(&perlock);338 pid = getpid();339 h = pid%nelem(perproc);340 for(i=0; i<nelem(perproc); i++){341 p = &perproc[(i+h)%nelem(perproc)];342 if(p->pid == pid || p->pid == -1 || p->pid == 0){343 p->pid = pid;344 unlock(&perlock);345 return p;346 }347 }348 fprint(2, "newperproc %d: out of procs\n", pid);349 abort();350 return nil;351 }353 Proc*354 _threadproc(void)355 {356 return myperproc()->proc;357 }359 void360 _threadsetproc(Proc *p)361 {362 Perproc *pp;364 if(p)365 p->osprocid = getpid();366 pp = newperproc();367 pp->proc = p;368 if(p == nil)369 pp->pid = -1;370 }372 void373 _pthreadinit(void)374 {375 __isthreaded = 1;376 signal(SIGUSR2, sigusr2handler);377 }379 void380 _threadpexit(void)381 {382 _exit(0);383 }