#include <9pm/u.h> #include <9pm/libc.h> #include <9pm/ns.h> #include <9pm/thread.h> #include <9pm/threadimpl.h> char *_threadexitsallstatus; void threadexits(char *exitstr) { Thread *t, *new; Tproc *p; Channel *c; _threaddebug(DBGTHRD|DBGKILL, "Exitthread()"); p = _threadgetproc(); t = _threadgetthr(); if (p->nthreads > 1) { t->exiting = 1; p->nthreads--; lock(&_threndezlock); while ((new = _threadgetq(&p->runnable)) == nil) { _threaddebug(DBGTHRD, "Nothing left to run"); /* called with rendezlock held */ p->blocked = 1; unlock(&_threndezlock); if ((new = (Thread *)rendezvous((ulong)p, 0)) != (Thread *)~0) { threadassert(!p->blocked); threadassert(new->proc == p); p->curthread = new; new->state = Running; /* switch to new thread, pass it `t' for cleanup */ new->garbage = t; longjmp(new->env, (int)t); /* No return */ } _threaddebug(DBGNOTE|DBGTHRD, "interrupted"); lock(&_threndezlock); } unlock(&_threndezlock); _threaddebug(DBGTHRD, "Yield atexit to %d.%d", p->pid, new->id); p->curthread = new; new->state = Running; if (new->exiting) threadexits(nil); /* switch to new thread, pass it `t' for cleanup */ new->garbage = t; longjmp(new->env, (int)t); /* no return */ } /* * thewaitchan confounds exiting the entire program, so handle it * carefully; store exposed global in local variable c. */ if(!p->nowait && (c = _threadwaitchan) != nil) { Waitmsg *w; long t[4]; /* create a Waitmsg out of whole cloth; this proc was created RFNOWAIT */ w = _threadmalloc(sizeof(Waitmsg)+(exitstr==nil? 0 : strlen(exitstr)+1), 0); w->pid = p->pid; w->tm[2] = _threadtimes(t); /* real */ w->tm[0] = t[0]+t[2]; /* user + child user */ w->tm[1] = t[1]+t[3]; /* sys + child sys */ w->msg = ""; if(exitstr != nil){ w->msg = (char*)(&w[1]); strcpy(w->msg, exitstr); } _threaddebug(DBGCHLD, "In thread %s: sending exit status %s for %d", p->curthread->cmdname, exitstr, p->pid); sendp(c, w); } _threaddebug(DBGPROC, "Exiting p=%p", p); t->exiting = 1; if(exitstr == nil) p->exitstr[0] = '\0'; else utfecpy(p->exitstr, p->exitstr+sizeof p->exitstr, exitstr); p->nthreads--; /* clean up and exit */ longjmp(p->oldenv, DOEXIT); } void threadexitsall(char *status) { Channel *c; Waitmsg *w; if ((c = _threadwaitchan) != nil) { _threadwaitchan = nil; while ((w = nbrecvp(c)) != nil){ /* Unblock threads previously exited, * sending on thewaitchan, not yet waited for */ free(w); } } if(status == nil) status=""; _threadexitsallstatus = status; _threadsignalpasser(); _threadsignal(); _osexitsall(status); exits(status); }