mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
more thread work
This commit is contained in:
parent
77dcf88474
commit
1956455367
12 changed files with 294 additions and 340 deletions
|
@ -4,7 +4,7 @@ static Lock chanlock; /* central channel access lock */
|
|||
|
||||
static void enqueue(Alt*, Thread*);
|
||||
static void dequeue(Alt*);
|
||||
static int altexec(Alt*, int);
|
||||
static int altexec(Alt*);
|
||||
|
||||
int _threadhighnentry;
|
||||
int _threadnalt;
|
||||
|
@ -101,7 +101,7 @@ _alt(Alt *alts)
|
|||
{
|
||||
Alt *a, *xa;
|
||||
Channel *c;
|
||||
int n, s;
|
||||
int n;
|
||||
Thread *t;
|
||||
|
||||
/*
|
||||
|
@ -119,7 +119,6 @@ _alt(Alt *alts)
|
|||
t = _threadgetproc()->thread;
|
||||
if((t && t->moribund) || _threadexitsallstatus)
|
||||
yield(); /* won't return */
|
||||
s = _procsplhi();
|
||||
lock(&chanlock);
|
||||
|
||||
/* test whether any channels can proceed */
|
||||
|
@ -134,7 +133,6 @@ _alt(Alt *alts)
|
|||
c = xa->c;
|
||||
if(c==nil){
|
||||
unlock(&chanlock);
|
||||
_procsplx(s);
|
||||
return -1;
|
||||
}
|
||||
if(canexec(xa))
|
||||
|
@ -146,8 +144,7 @@ _alt(Alt *alts)
|
|||
/* nothing can proceed */
|
||||
if(xa->op == CHANNOBLK){
|
||||
unlock(&chanlock);
|
||||
_procsplx(s);
|
||||
_threadnalt++;
|
||||
_threadnalt++;
|
||||
return xa - alts;
|
||||
}
|
||||
|
||||
|
@ -172,9 +169,7 @@ _threadnalt++;
|
|||
t->alt = alts;
|
||||
t->chan = Chanalt;
|
||||
t->altrend.l = &chanlock;
|
||||
_procsplx(s);
|
||||
_threadsleep(&t->altrend);
|
||||
s = _procsplhi();
|
||||
|
||||
/* dequeue from channels, find selected one */
|
||||
a = nil;
|
||||
|
@ -187,13 +182,12 @@ _threadnalt++;
|
|||
dequeue(xa);
|
||||
}
|
||||
unlock(&chanlock);
|
||||
_procsplx(s);
|
||||
if(a == nil){ /* we were interrupted */
|
||||
assert(c==(Channel*)~0);
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
altexec(a, s); /* unlocks chanlock, does splx */
|
||||
altexec(a); /* unlocks chanlock, does splx */
|
||||
}
|
||||
if(t)
|
||||
t->chan = Channone;
|
||||
|
@ -445,7 +439,7 @@ altcopy(void *dst, void *src, int sz)
|
|||
}
|
||||
|
||||
static int
|
||||
altexec(Alt *a, int spl)
|
||||
altexec(Alt *a)
|
||||
{
|
||||
volatile Alt *b;
|
||||
int i, n, otherop;
|
||||
|
@ -492,7 +486,6 @@ altexec(Alt *a, int spl)
|
|||
_threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&chanlock);
|
||||
_threaddebug(DBGCHAN, "unlocking the chanlock");
|
||||
unlock(&chanlock);
|
||||
_procsplx(spl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -503,6 +496,5 @@ altexec(Alt *a, int spl)
|
|||
altcopy(buf, me, c->e);
|
||||
|
||||
unlock(&chanlock);
|
||||
_procsplx(spl);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ proccreate(void (*f)(void*), void *arg, uint stacksize)
|
|||
p = _threadgetproc();
|
||||
np = _newproc();
|
||||
p->newproc = np;
|
||||
p->schedfn = _threadstartproc;
|
||||
p->schedfn = _kthreadstartproc;
|
||||
id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
|
||||
_sched(); /* call into scheduler to create proc XXX */
|
||||
return id;
|
||||
|
|
|
@ -10,20 +10,9 @@ _threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
|
|||
int pfd[2];
|
||||
int n, pid;
|
||||
char exitstr[ERRMAX];
|
||||
static int firstexec = 1;
|
||||
static Lock lk;
|
||||
|
||||
_threaddebug(DBGEXEC, "threadexec %s", prog);
|
||||
|
||||
if(firstexec){
|
||||
lock(&lk);
|
||||
if(firstexec){
|
||||
firstexec = 0;
|
||||
_threadfirstexec();
|
||||
}
|
||||
unlock(&lk);
|
||||
}
|
||||
|
||||
/*
|
||||
* We want threadexec to behave like exec; if exec succeeds,
|
||||
* never return, and if it fails, return with errstr set.
|
||||
|
@ -53,7 +42,6 @@ _threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
|
|||
_threaddebug(DBGSCHED, "exit after efork");
|
||||
_exit(0);
|
||||
default:
|
||||
_threadafterexec();
|
||||
if(freeargs)
|
||||
free(args);
|
||||
break;
|
||||
|
@ -88,14 +76,14 @@ Bad:
|
|||
void
|
||||
threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
|
||||
{
|
||||
if(_callthreadexec(pidc, fd, prog, args, 0) >= 0)
|
||||
if(_kthreadexec(pidc, fd, prog, args, 0) >= 0)
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
int
|
||||
threadspawn(int fd[3], char *prog, char *args[])
|
||||
{
|
||||
return _callthreadexec(nil, fd, prog, args, 0);
|
||||
return _kthreadexec(nil, fd, prog, args, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -128,7 +116,7 @@ threadexecl(Channel *pidc, int fd[3], char *f, ...)
|
|||
args[n] = 0;
|
||||
va_end(arg);
|
||||
|
||||
if(_callthreadexec(pidc, fd, f, args, 1) >= 0)
|
||||
if(_kthreadexec(pidc, fd, f, args, 1) >= 0)
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ threadexitsall(char *exitstr)
|
|||
_threadexitsallstatus = exitstr;
|
||||
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
|
||||
/* leave */
|
||||
_threadexitallproc(exitstr);
|
||||
_kthreadexitallproc(exitstr);
|
||||
}
|
||||
|
||||
Channel*
|
||||
|
|
|
@ -7,164 +7,25 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define debugpoll 0
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/time.h>
|
||||
enum { POLLIN=1, POLLOUT=2, POLLERR=4 };
|
||||
struct pollfd
|
||||
void
|
||||
fdwait()
|
||||
{
|
||||
int fd;
|
||||
int events;
|
||||
int revents;
|
||||
};
|
||||
|
||||
int
|
||||
poll(struct pollfd *p, int np, int ms)
|
||||
{
|
||||
int i, maxfd, n;
|
||||
struct timeval tv, *tvp;
|
||||
fd_set rfd, wfd, efd;
|
||||
|
||||
maxfd = -1;
|
||||
|
||||
FD_ZERO(&rfd);
|
||||
FD_ZERO(&wfd);
|
||||
FD_ZERO(&efd);
|
||||
for(i=0; i<np; i++){
|
||||
p[i].revents = 0;
|
||||
if(p[i].fd == -1)
|
||||
continue;
|
||||
if(p[i].fd > maxfd)
|
||||
maxfd = p[i].fd;
|
||||
if(p[i].events & POLLIN)
|
||||
FD_SET(p[i].fd, &rfd);
|
||||
if(p[i].events & POLLOUT)
|
||||
FD_SET(p[i].fd, &wfd);
|
||||
FD_SET(p[i].fd, &efd);
|
||||
}
|
||||
|
||||
if(ms != -1){
|
||||
tv.tv_usec = (ms%1000)*1000;
|
||||
tv.tv_sec = ms/1000;
|
||||
tvp = &tv;
|
||||
}else
|
||||
tvp = nil;
|
||||
|
||||
if(debugpoll){
|
||||
fprint(2, "select %d:", maxfd+1);
|
||||
for(i=0; i<=maxfd; i++){
|
||||
if(FD_ISSET(i, &rfd))
|
||||
fprint(2, " r%d", i);
|
||||
if(FD_ISSET(i, &wfd))
|
||||
fprint(2, " w%d", i);
|
||||
if(FD_ISSET(i, &efd))
|
||||
fprint(2, " e%d", i);
|
||||
}
|
||||
fprint(2, "; tp=%p, t=%d.%d\n", tvp, tv.tv_sec, tv.tv_usec);
|
||||
}
|
||||
|
||||
n = select(maxfd+1, &rfd, &wfd, &efd, tvp);
|
||||
|
||||
if(n <= 0)
|
||||
return n;
|
||||
|
||||
for(i=0; i<np; i++){
|
||||
if(p[i].fd == -1)
|
||||
continue;
|
||||
if(FD_ISSET(p[i].fd, &rfd))
|
||||
p[i].revents |= POLLIN;
|
||||
if(FD_ISSET(p[i].fd, &wfd))
|
||||
p[i].revents |= POLLOUT;
|
||||
if(FD_ISSET(p[i].fd, &efd))
|
||||
p[i].revents |= POLLERR;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Poll file descriptors in an idle loop.
|
||||
*/
|
||||
|
||||
typedef struct Poll Poll;
|
||||
|
||||
struct Poll
|
||||
{
|
||||
Channel *c; /* for sending back */
|
||||
};
|
||||
|
||||
static Channel *sleepchan[64];
|
||||
static int sleeptime[64];
|
||||
static int nsleep;
|
||||
|
||||
static struct pollfd pfd[64];
|
||||
static struct Poll polls[64];
|
||||
static int npoll;
|
||||
|
||||
static void
|
||||
pollidle(void *v)
|
||||
{
|
||||
int i, n, t;
|
||||
uint now;
|
||||
|
||||
for(;; yield()){
|
||||
if(debugpoll) fprint(2, "poll %d:", npoll);
|
||||
for(i=0; i<npoll; i++){
|
||||
if(debugpoll) fprint(2, " %d%c", pfd[i].fd, pfd[i].events==POLLIN ? 'r' : 'w');
|
||||
pfd[i].revents = 0;
|
||||
}
|
||||
t = -1;
|
||||
now = p9nsec()/1000000;
|
||||
for(i=0; i<nsleep; i++){
|
||||
n = sleeptime[i] - now;
|
||||
if(debugpoll) fprint(2, " s%d", n);
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
if(t == -1 || n < t)
|
||||
t = n;
|
||||
}
|
||||
if(debugpoll) fprint(2, "; t=%d\n", t);
|
||||
|
||||
n = poll(pfd, npoll, t);
|
||||
//fprint(2, "poll ret %d:", n);
|
||||
now = p9nsec()/1000000;
|
||||
for(i=0; i<nsleep; i++){
|
||||
if((int)(sleeptime[i] - now) < 0){
|
||||
nbsendul(sleepchan[i], 0);
|
||||
nsleep--;
|
||||
sleepchan[i] = sleepchan[nsleep];
|
||||
sleeptime[i] = sleeptime[nsleep];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if(n <= 0)
|
||||
continue;
|
||||
for(i=0; i<npoll; i++)
|
||||
if(pfd[i].fd != -1 && pfd[i].revents){
|
||||
//fprint(2, " %d", pfd[i].fd);
|
||||
pfd[i].fd = -1;
|
||||
pfd[i].events = 0;
|
||||
pfd[i].revents = 0;
|
||||
nbsendul(polls[i].c, 1);
|
||||
//fprint(2, " x%d", pfd[i].fd);
|
||||
}
|
||||
//fprint(2, "\n");
|
||||
}
|
||||
if(mode=='w')
|
||||
FD_SET(&wfd, fd);
|
||||
else
|
||||
FD_SET(&rfd, fd);
|
||||
FD_SET(&efd, fd);
|
||||
select(fd+1, &rfd, &wfd, &efd, nil);
|
||||
}
|
||||
|
||||
void
|
||||
threadfdwaitsetup(void)
|
||||
{
|
||||
static int setup = 0;
|
||||
|
||||
if(!setup){
|
||||
setup = 1;
|
||||
proccreate(pollidle, nil, 16384);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -199,6 +60,8 @@ _threadfdwait(int fd, int rw, ulong pc)
|
|||
polls[i].c = &s.c;
|
||||
if(0) fprint(2, "%s [%3d] fdwait %d %c list *0x%lux\n",
|
||||
argv0, threadid(), fd, rw, pc);
|
||||
if(pollpid)
|
||||
postnote(PNPROC, pollpid, "interrupt");
|
||||
recvul(&s.c);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,12 +11,10 @@ struct Mainarg
|
|||
char **argv;
|
||||
};
|
||||
|
||||
int _threadmainpid;
|
||||
int mainstacksize;
|
||||
int _callsthreaddaemonize;
|
||||
static int passtomainpid;
|
||||
|
||||
extern void (*_sysfatal)(char*, va_list);
|
||||
extern Jmp *(*_notejmpbuf)(void);
|
||||
|
||||
static void
|
||||
mainlauncher(void *arg)
|
||||
|
@ -24,58 +22,24 @@ mainlauncher(void *arg)
|
|||
Mainarg *a;
|
||||
|
||||
a = arg;
|
||||
_threadmaininit();
|
||||
_kmaininit();
|
||||
threadmain(a->argc, a->argv);
|
||||
threadexits("threadmain");
|
||||
}
|
||||
|
||||
static void
|
||||
passer(void *x, char *msg)
|
||||
{
|
||||
USED(x);
|
||||
Waitmsg *w;
|
||||
|
||||
if(strcmp(msg, "sys: usr2") == 0)
|
||||
_exit(0); /* daemonize */
|
||||
else if(strcmp(msg, "sys: child") == 0){
|
||||
w = wait();
|
||||
if(w == nil)
|
||||
_exit(1);
|
||||
_exit(atoi(w->msg));
|
||||
}else
|
||||
postnote(PNPROC, passtomainpid, msg);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int pid;
|
||||
Mainarg a;
|
||||
Proc *p;
|
||||
sigset_t mask;
|
||||
|
||||
/*
|
||||
* Do daemonize hack here.
|
||||
* In pthreads, threadmain is actually run in a subprocess,
|
||||
* so that the main process can exit (if threaddaemonize is called).
|
||||
* The main process relays notes to the subprocess.
|
||||
* _Threadbackgroundsetup will return only in the subprocess.
|
||||
*/
|
||||
if(_callsthreaddaemonize){
|
||||
passtomainpid = getpid();
|
||||
switch(pid = fork()){
|
||||
case -1:
|
||||
sysfatal("fork: %r");
|
||||
|
||||
case 0:
|
||||
/* continue executing */
|
||||
_threadmainpid = getppid();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* wait for signal USR2 */
|
||||
notify(passer);
|
||||
for(;;)
|
||||
pause();
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
_threadbackgroundinit();
|
||||
|
||||
/*
|
||||
* Instruct QLock et al. to use our scheduling functions
|
||||
|
@ -85,16 +49,17 @@ main(int argc, char **argv)
|
|||
|
||||
/*
|
||||
* Install our own _threadsysfatal which takes down
|
||||
* the whole conglomeration of procs.
|
||||
* the whole confederation of procs.
|
||||
*/
|
||||
_sysfatal = _threadsysfatal;
|
||||
|
||||
/*
|
||||
* XXX Install our own jump handler.
|
||||
* Install our own jump handler.
|
||||
*/
|
||||
_notejmpbuf = _threadgetjmp;
|
||||
|
||||
/*
|
||||
* Install our own signal handlers.
|
||||
* Install our own signal handler.
|
||||
*/
|
||||
notify(_threadnote);
|
||||
|
||||
|
@ -119,3 +84,15 @@ void
|
|||
_threadlinkmain(void)
|
||||
{
|
||||
}
|
||||
|
||||
Jmp*
|
||||
_threadgetjmp(void)
|
||||
{
|
||||
static Jmp j;
|
||||
Proc *p;
|
||||
|
||||
p = _threadgetproc();
|
||||
if(p == nil)
|
||||
return &j;
|
||||
return &p->sigjmp;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
LIB=libthread.a
|
||||
THREAD=`sh ./thread.sh`
|
||||
SYSOFILES=`sh ./sysofiles.sh`
|
||||
OFILES=\
|
||||
$OBJTYPE.$O\
|
||||
$THREAD.$O\
|
||||
asm-$SYSNAME-$OBJTYPE.$O\
|
||||
$SYSOFILES\
|
||||
channel.$O\
|
||||
chanprint.$O\
|
||||
create.$O\
|
||||
daemon.$O\
|
||||
debug.$O\
|
||||
exec-unix.$O\
|
||||
exit.$O\
|
||||
|
@ -29,10 +26,10 @@ OFILES=\
|
|||
main.$O\
|
||||
memset.$O\
|
||||
memsetd.$O\
|
||||
note.$O\
|
||||
read9pmsg.$O\
|
||||
ref.$O\
|
||||
sched.$O\
|
||||
setproc.$O\
|
||||
sleep.$O\
|
||||
|
||||
HFILES=\
|
||||
|
@ -57,6 +54,9 @@ tspawn: tspawn.$O $PLAN9/lib/$LIB
|
|||
trend: trend.$O $PLAN9/lib/$LIB
|
||||
$LD -o trend trend.$O $LDFLAGS -lthread -l9
|
||||
|
||||
tsignal: tsignal.$O $PLAN9/lib/$LIB
|
||||
$LD -o tsignal tsignal.$O $LDFLAGS -lthread -l9
|
||||
|
||||
CLEANFILES=$CLEANFILES tprimes texec
|
||||
|
||||
asm-Linux-ppc.$O: asm-Linux-386.s
|
||||
|
|
|
@ -2,53 +2,36 @@
|
|||
#include <errno.h>
|
||||
#include "threadimpl.h"
|
||||
|
||||
static int multi;
|
||||
static Proc *theproc;
|
||||
/*
|
||||
* Basic kernel thread management.
|
||||
*/
|
||||
static pthread_key_t key;
|
||||
|
||||
/*
|
||||
* Called before we go multiprocess.
|
||||
*/
|
||||
void
|
||||
_threadmultiproc(void)
|
||||
_kthreadinit(void)
|
||||
{
|
||||
if(multi == 0){
|
||||
multi = 1;
|
||||
pthread_key_create(&key, 0);
|
||||
_threadsetproc(theproc);
|
||||
}
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the proc for the current pthread.
|
||||
*/
|
||||
void
|
||||
_threadsetproc(Proc *p)
|
||||
_kthreadsetproc(Proc *p)
|
||||
{
|
||||
if(!multi){
|
||||
theproc = p;
|
||||
return;
|
||||
}
|
||||
sigset_t all;
|
||||
|
||||
p->pthreadid = pthread_self();
|
||||
sigfillset(&all);
|
||||
pthread_sigmask(SIG_SETMASK, &all, nil);
|
||||
pthread_setspecific(key, p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the proc for the current pthread.
|
||||
*/
|
||||
Proc*
|
||||
_threadgetproc(void)
|
||||
_kthreadgetproc(void)
|
||||
{
|
||||
if(!multi)
|
||||
return theproc;
|
||||
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to start a new proc.
|
||||
*/
|
||||
void
|
||||
_threadstartproc(Proc *p)
|
||||
_kthreadstartproc(Proc *p)
|
||||
{
|
||||
Proc *np;
|
||||
pthread_t tid;
|
||||
|
@ -63,69 +46,43 @@ _threadstartproc(Proc *p)
|
|||
np->pthreadid = tid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to associate p with the current pthread.
|
||||
*/
|
||||
void
|
||||
_threadinitproc(Proc *p)
|
||||
{
|
||||
p->pthreadid = pthread_self();
|
||||
_threadsetproc(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to exit the current pthread.
|
||||
*/
|
||||
void
|
||||
_threadexitproc(char *exitstr)
|
||||
_kthreadexitproc(char *exitstr)
|
||||
{
|
||||
_threaddebug(DBGSCHED, "_pthreadexit");
|
||||
pthread_exit(nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to exit all pthreads.
|
||||
*/
|
||||
void
|
||||
_threadexitallproc(char *exitstr)
|
||||
_kthreadexitallproc(char *exitstr)
|
||||
{
|
||||
_threaddebug(DBGSCHED, "_threadexitallproc");
|
||||
exits(exitstr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to poll for any kids of this pthread.
|
||||
* Wait messages aren't restricted to a particular
|
||||
* pthread, so we have a separate proc responsible
|
||||
* for them. So this is a no-op.
|
||||
* Exec. Pthreads does the hard work of making it possible
|
||||
* for any thread to do the waiting, so this is pretty easy.
|
||||
* We create a separate proc whose job is to wait for children
|
||||
* and deliver wait messages.
|
||||
*/
|
||||
void
|
||||
_threadwaitkids(Proc *p)
|
||||
{
|
||||
}
|
||||
static Channel *_threadexecwaitchan;
|
||||
|
||||
/*
|
||||
* Separate process to wait for child messages.
|
||||
* Also runs signal handlers.
|
||||
*/
|
||||
static Channel *_threadexecchan;
|
||||
static void
|
||||
_threadwaitproc(void *v)
|
||||
{
|
||||
Channel *c;
|
||||
Waitmsg *w;
|
||||
sigset_t none;
|
||||
|
||||
sigemptyset(&none);
|
||||
pthread_sigmask(SIG_SETMASK, &none, 0);
|
||||
_threadinternalproc();
|
||||
|
||||
USED(v);
|
||||
|
||||
for(;;){
|
||||
w = wait();
|
||||
if(w == nil){
|
||||
if(errno == ECHILD)
|
||||
recvul(_threadexecchan);
|
||||
if(errno == ECHILD) /* wait for more */
|
||||
recvul(_threadexecwaitchan);
|
||||
continue;
|
||||
}
|
||||
if((c = _threadwaitchan) != nil)
|
||||
|
@ -133,43 +90,182 @@ _threadwaitproc(void *v)
|
|||
else
|
||||
free(w);
|
||||
}
|
||||
fprint(2, "_threadwaitproc exits\n");
|
||||
fprint(2, "_threadwaitproc exits\n"); /* not reached */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called before the first exec.
|
||||
* Call _threadexec in the right conditions.
|
||||
*/
|
||||
void
|
||||
_threadfirstexec(void)
|
||||
int
|
||||
_kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
|
||||
{
|
||||
static Lock lk;
|
||||
int rv;
|
||||
|
||||
if(!_threadexecwaitchan){
|
||||
lock(&lk);
|
||||
if(!_threadexecwaitchan){
|
||||
_threadexecwaitchan = chancreate(sizeof(ulong), 1);
|
||||
proccreate(_threadwaitproc, nil, 32*1024);
|
||||
}
|
||||
unlock(&lk);
|
||||
}
|
||||
rv = _threadexec(c, fd, prog, args, freeargs);
|
||||
nbsendul(_threadexecwaitchan, 1);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from mainlauncher before threadmain.
|
||||
* Some threaded applications want to run in the background.
|
||||
* Calling fork() and exiting in the parent will result in a child
|
||||
* with a single pthread (if we are using pthreads), and will screw
|
||||
* up our internal process info if we are using clone/rfork.
|
||||
* Instead, apps should call threadbackground(), which takes
|
||||
* care of this.
|
||||
*
|
||||
* _threadbackgroundinit is called from main.
|
||||
*/
|
||||
void
|
||||
_threadmaininit(void)
|
||||
{
|
||||
_threadexecchan = chancreate(sizeof(ulong), 1);
|
||||
proccreate(_threadwaitproc, nil, 32*1024);
|
||||
|
||||
/*
|
||||
* Sleazy: decrement threadnprocs so that
|
||||
* the existence of the _threadwaitproc proc
|
||||
* doesn't keep us from exiting.
|
||||
*/
|
||||
lock(&_threadpq.lock);
|
||||
--_threadnprocs;
|
||||
/* print("change %d -> %d\n", _threadnprocs+1, _threadnprocs); */
|
||||
unlock(&_threadpq.lock);
|
||||
static int mainpid, passerpid;
|
||||
|
||||
static void
|
||||
passer(void *x, char *msg)
|
||||
{
|
||||
Waitmsg *w;
|
||||
|
||||
USED(x);
|
||||
if(strcmp(msg, "sys: usr2") == 0)
|
||||
_exit(0); /* daemonize */
|
||||
else if(strcmp(msg, "sys: child") == 0){
|
||||
/* child exited => so should we */
|
||||
w = wait();
|
||||
if(w == nil)
|
||||
_exit(1);
|
||||
_exit(atoi(w->msg));
|
||||
}else
|
||||
postnote(PNGROUP, mainpid, msg);
|
||||
}
|
||||
|
||||
void
|
||||
_threadbackgroundinit(void)
|
||||
{
|
||||
int pid;
|
||||
sigset_t mask;
|
||||
|
||||
sigfillset(&mask);
|
||||
pthread_sigmask(SIG_BLOCK, &mask, 0);
|
||||
|
||||
return;
|
||||
|
||||
passerpid = getpid();
|
||||
switch(pid = fork()){
|
||||
case -1:
|
||||
sysfatal("fork: %r");
|
||||
|
||||
case 0:
|
||||
rfork(RFNOTEG);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mainpid = pid;
|
||||
notify(passer);
|
||||
notifyon("sys: child");
|
||||
notifyon("sys: usr2"); /* should already be on */
|
||||
for(;;)
|
||||
pause();
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
threadbackground(void)
|
||||
{
|
||||
if(passerpid <= 1)
|
||||
return;
|
||||
postnote(PNPROC, passerpid, "sys: usr2");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after forking the exec child.
|
||||
* Notes.
|
||||
*/
|
||||
void
|
||||
_threadafterexec(void)
|
||||
Channel *_threadnotechan;
|
||||
static ulong sigs;
|
||||
static Lock _threadnotelk;
|
||||
static void _threadnoteproc(void*);
|
||||
extern int _p9strsig(char*);
|
||||
extern char *_p9sigstr(int);
|
||||
|
||||
Channel*
|
||||
threadnotechan(void)
|
||||
{
|
||||
nbsendul(_threadexecchan, 1);
|
||||
if(_threadnotechan == nil){
|
||||
lock(&_threadnotelk);
|
||||
if(_threadnotechan == nil){
|
||||
_threadnotechan = chancreate(sizeof(char*), 1);
|
||||
proccreate(_threadnoteproc, nil, 32*1024);
|
||||
}
|
||||
unlock(&_threadnotelk);
|
||||
}
|
||||
return _threadnotechan;
|
||||
}
|
||||
|
||||
void
|
||||
_threadnote(void *x, char *msg)
|
||||
{
|
||||
USED(x);
|
||||
|
||||
if(_threadexitsallstatus)
|
||||
_kthreadexitproc(_threadexitsallstatus);
|
||||
|
||||
if(strcmp(msg, "sys: usr2") == 0)
|
||||
noted(NCONT);
|
||||
|
||||
if(_threadnotechan == nil)
|
||||
noted(NDFLT);
|
||||
|
||||
sigs |= 1<<_p9strsig(msg);
|
||||
noted(NCONT);
|
||||
}
|
||||
|
||||
void
|
||||
_threadnoteproc(void *x)
|
||||
{
|
||||
int i;
|
||||
sigset_t none;
|
||||
Channel *c;
|
||||
|
||||
_threadinternalproc();
|
||||
sigemptyset(&none);
|
||||
pthread_sigmask(SIG_SETMASK, &none, 0);
|
||||
|
||||
c = _threadnotechan;
|
||||
for(;;){
|
||||
if(sigs == 0)
|
||||
pause();
|
||||
for(i=0; i<32; i++){
|
||||
if((sigs&(1<<i)) == 0)
|
||||
continue;
|
||||
sigs &= ~(1<<i);
|
||||
if(i == 0)
|
||||
continue;
|
||||
sendp(c, _p9sigstr(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_threadschednote(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
_kmaininit(void)
|
||||
{
|
||||
sigset_t all;
|
||||
|
||||
sigfillset(&all);
|
||||
pthread_sigmask(SIG_SETMASK, &all, 0);
|
||||
}
|
||||
|
|
|
@ -18,13 +18,12 @@ _threadscheduler(void *arg)
|
|||
p = arg;
|
||||
|
||||
_threadlinkmain();
|
||||
_threadinitproc(p);
|
||||
_threadsetproc(p);
|
||||
|
||||
for(;;){
|
||||
/*
|
||||
* Clean up zombie children.
|
||||
*/
|
||||
_threadwaitkids(p);
|
||||
|
||||
/*
|
||||
* Find next thread to run.
|
||||
|
@ -154,6 +153,7 @@ runthread(Proc *p)
|
|||
if(p->nthreads==0 || (p->nthreads==1 && p->idle))
|
||||
return nil;
|
||||
|
||||
_threadschednote();
|
||||
lock(&p->readylock);
|
||||
q = &p->ready;
|
||||
if(q->head == nil){
|
||||
|
@ -180,7 +180,10 @@ runthread(Proc *p)
|
|||
*/
|
||||
q->asleep = 1;
|
||||
p->rend.l = &p->readylock;
|
||||
_procsleep(&p->rend);
|
||||
while(q->asleep){
|
||||
_procsleep(&p->rend);
|
||||
_threadschednote();
|
||||
}
|
||||
|
||||
/*
|
||||
* Maybe we were awakened to exit?
|
||||
|
@ -284,6 +287,25 @@ _threadsetidle(int id)
|
|||
unlock(&p->readylock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark proc as internal so that if all but internal procs exit, we exit.
|
||||
*/
|
||||
void
|
||||
_threadinternalproc(void)
|
||||
{
|
||||
Proc *p;
|
||||
|
||||
p = _threadgetproc();
|
||||
if(p->internal)
|
||||
return;
|
||||
lock(&_threadpq.lock);
|
||||
if(p->internal == 0){
|
||||
p->internal = 1;
|
||||
--_threadnprocs;
|
||||
}
|
||||
unlock(&_threadpq.lock);
|
||||
}
|
||||
|
||||
static void
|
||||
schedexit(Proc *p)
|
||||
{
|
||||
|
@ -301,7 +323,10 @@ schedexit(Proc *p)
|
|||
break;
|
||||
}
|
||||
}
|
||||
n = --_threadnprocs;
|
||||
if(p->internal)
|
||||
n = _threadnprocs;
|
||||
else
|
||||
n = --_threadnprocs;
|
||||
unlock(&_threadpq.lock);
|
||||
|
||||
strncpy(ex, p->exitstr, sizeof ex);
|
||||
|
@ -309,10 +334,10 @@ schedexit(Proc *p)
|
|||
free(p);
|
||||
if(n == 0){
|
||||
_threaddebug(DBGSCHED, "procexit; no more procs");
|
||||
_threadexitallproc(ex);
|
||||
_kthreadexitallproc(ex);
|
||||
}else{
|
||||
_threaddebug(DBGSCHED, "procexit");
|
||||
_threadexitproc(ex);
|
||||
_kthreadexitproc(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,3 +36,4 @@ _threadwakeup(_Procrend *r)
|
|||
_threadready(t);
|
||||
unlock(&t->proc->lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
if [ `uname` = Linux ]
|
||||
then
|
||||
case "`uname | awk '{print $3}'`" in
|
||||
*)
|
||||
echo Linux-clone
|
||||
;;
|
||||
case `uname -r` in
|
||||
2.[6789]*)
|
||||
echo pthread
|
||||
;;
|
||||
*)
|
||||
echo Linux-clone
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo pthread
|
||||
|
|
|
@ -28,6 +28,14 @@ typedef struct Proc Proc;
|
|||
typedef struct Tqueue Tqueue;
|
||||
typedef struct Pqueue Pqueue;
|
||||
typedef struct Execargs Execargs;
|
||||
typedef struct Jmp Jmp;
|
||||
|
||||
/* sync with ../lib9/notify.c */
|
||||
struct Jmp
|
||||
{
|
||||
p9jmp_buf b;
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -126,6 +134,7 @@ struct Proc
|
|||
Proc *newproc; /* fork argument */
|
||||
char exitstr[ERRMAX]; /* exit status */
|
||||
|
||||
int internal;
|
||||
int rforkflag;
|
||||
int nthreads;
|
||||
Tqueue threads; /* All threads of this proc */
|
||||
|
@ -138,6 +147,7 @@ struct Proc
|
|||
uint nextID; /* ID of most recently created thread */
|
||||
Proc *next; /* linked list of Procs */
|
||||
|
||||
Jmp sigjmp; /* for notify implementation */
|
||||
|
||||
void (*schedfn)(Proc*); /* function to call in scheduler */
|
||||
|
||||
|
@ -161,8 +171,6 @@ struct Proc
|
|||
void _swaplabel(Label*, Label*);
|
||||
Proc* _newproc(void);
|
||||
int _newthread(Proc*, void(*)(void*), void*, uint, char*, int);
|
||||
int _procsplhi(void);
|
||||
void _procsplx(int);
|
||||
int _sched(void);
|
||||
int _schedexec(Execargs*);
|
||||
void _schedexecwait(void);
|
||||
|
@ -178,14 +186,14 @@ void _threadexitsall(char*);
|
|||
Proc* _threadgetproc(void);
|
||||
extern void _threadmultiproc(void);
|
||||
Proc* _threaddelproc(void);
|
||||
void _threadinitproc(Proc*);
|
||||
void _threadwaitkids(Proc*);
|
||||
void _kthreadinitproc(Proc*);
|
||||
void _threadsetproc(Proc*);
|
||||
void _threadinitstack(Thread*, void(*)(void*), void*);
|
||||
void _threadlinkmain(void);
|
||||
void* _threadmalloc(long, int);
|
||||
void _threadnote(void*, char*);
|
||||
void _threadready(Thread*);
|
||||
void _threadschednote(void);
|
||||
void _threadsetidle(int);
|
||||
void _threadsleep(_Procrend*);
|
||||
void _threadwakeup(_Procrend*);
|
||||
|
@ -195,12 +203,18 @@ long _xdec(long*);
|
|||
void _xinc(long*);
|
||||
void _threadremove(Proc*, Thread*);
|
||||
void threadstatus(void);
|
||||
void _threadstartproc(Proc*);
|
||||
void _threadexitproc(char*);
|
||||
void _threadexitallproc(char*);
|
||||
void _threadefork(int[3], int[2], char*, char**);
|
||||
Jmp* _threadgetjmp(void);
|
||||
void _kthreadinit(void);
|
||||
void _kthreadsetproc(Proc*);
|
||||
Proc* _kthreadgetproc(void);
|
||||
void _kthreadstartproc(Proc*);
|
||||
void _kthreadexitproc(char*);
|
||||
void _kthreadexitallproc(char*);
|
||||
void _threadinternalproc(void);
|
||||
void _threadbackgroundinit(void);
|
||||
void _kmaininit(void);
|
||||
|
||||
extern int _threadmainpid;
|
||||
extern int _threadnprocs;
|
||||
extern int _threaddebuglevel;
|
||||
extern char* _threadexitsallstatus;
|
||||
|
@ -222,8 +236,6 @@ extern void _threadstacklimit(void*, void*);
|
|||
extern void _procdelthread(Proc*, Thread*);
|
||||
extern void _procaddthread(Proc*, Thread*);
|
||||
|
||||
extern void _threadafterexec(void);
|
||||
extern void _threadmaininit(void);
|
||||
extern void _threadfirstexec(void);
|
||||
extern int _threadexec(Channel*, int[3], char*, char*[], int);
|
||||
extern int _callthreadexec(Channel*, int[3], char*, char*[], int);
|
||||
extern int _kthreadexec(Channel*, int[3], char*, char*[], int);
|
||||
|
|
Loading…
Reference in a new issue