#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);
}
syntax highlighted by Code2HTML, v. 0.9.1