commit - 048610b7ea50507c6987d5b0cc0c4810cda87d53
commit + 5093c3fa40717e78b0a63955640a8ac9071b5c07
blob - fb4c674667cb33586e8ca767c7ec208a20223ea5
blob + 313c2be5fa5ee8932e6022879936268ce7cfbc9a
--- src/libthread/386.c
+++ src/libthread/386.c
+#if defined(__linux__)
#include "ucontext.c"
+#else
-#ifdef OLD
-
#include "threadimpl.h"
/*
* To use this you need some patches to Valgrind that
blob - 290c52a8162df41d2bfd597d42fab968625dcdd8
blob + d2f4be259f5934c4d0624d72b9c6a1e0e56eede2
--- src/libthread/create.c
+++ src/libthread/create.c
t = _threadmalloc(sizeof(Thread), 1);
t->proc = p;
+ t->nextproc = p;
+ t->homeproc = p;
+
t->grp = grp;
t->id = id = newthreadid();
if(name)
* Add thread to proc.
*/
lock(&p->lock);
- p->nthreads++;
- if(p->threads.head == nil)
- p->threads.head = t;
- else{
- t->prevt = p->threads.tail;
- t->prevt->nextt = t;
- }
- p->threads.tail = t;
- t->next = (Thread*)~0;
+ _procaddthread(p, t);
/*
* Mark thread as ready to run.
{
int id;
- assert(_threadnprocs == 1);
+ assert(_threadpq.head->next == nil); /* only 1 */
id = threadcreate(f, arg, stacksize);
_threaddebug(DBGSCHED, "idle is %d", id);
return i;
}
+/*
+ * Add thread to proc's list.
+ */
+void
+_procaddthread(Proc *p, Thread *t)
+{
+ p->nthreads++;
+ if(p->threads.head == nil)
+ p->threads.head = t;
+ else{
+ t->prevt = p->threads.tail;
+ t->prevt->nextt = t;
+ }
+ p->threads.tail = t;
+ t->next = (Thread*)~0;
+}
+
+/*
+ * Remove thread from proc's list.
+ */
+void
+_procdelthread(Proc *p, Thread *t)
+{
+ if(t->prevt)
+ t->prevt->nextt = t->nextt;
+ else
+ p->threads.head = t->nextt;
+ if(t->nextt)
+ t->nextt->prevt = t->prevt;
+ else
+ p->threads.tail = t->prevt;
+ p->nthreads--;
+}
blob - 73a2faf7467b66059d35e96c7ac55c28c7526a21
blob + f69fedcab30760353f432aeebcd39dd14cbc2745
--- src/libthread/exec-unix.c
+++ src/libthread/exec-unix.c
#include "threadimpl.h"
static void efork(int[3], int[2], char*, char**);
-static int
+int
_threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
{
int pfd[2];
void
threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
{
- if(_threadexec(pidc, fd, prog, args, 0) >= 0)
+ if(_callthreadexec(pidc, fd, prog, args, 0) >= 0)
threadexits(nil);
}
int
threadspawn(int fd[3], char *prog, char *args[])
{
- return _threadexec(nil, fd, prog, args, 0);
+ return _callthreadexec(nil, fd, prog, args, 0);
}
/*
args[n] = 0;
va_end(arg);
- if(_threadexec(pidc, fd, f, args, 1) >= 0)
+ if(_callthreadexec(pidc, fd, f, args, 1) >= 0)
threadexits(nil);
}
blob - 8768e60df715c4d78e23a552a8977bcebabf3f1b
blob + a46ea4567248428d791a631ae2a6cf5b77e72451
--- src/libthread/fdwait.c
+++ src/libthread/fdwait.c
if(!setup){
setup = 1;
- threadcreateidle(pollidle, nil, 16384);
+ proccreate(pollidle, nil, 16384);
}
}
blob - 83ee177c379149a93c5ccbd015a32c6f6b7c2289
blob + ec0854304fd33a201f8503daf168d6120ecba7cb
--- src/libthread/main.c
+++ src/libthread/main.c
char **argv;
};
+int _threadmainpid;
int mainstacksize;
+int _callsthreaddaemonize;
+static int passtomainpid;
+
extern void (*_sysfatal)(char*, va_list);
static void
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;
/*
- * XXX Do daemonize hack here.
+ * Do daemonize hack here.
*/
+ 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);
+ }
+ }
+
/*
* Instruct QLock et al. to use our scheduling functions
* so that they can operate at the thread level.
blob - 20d08e09279c21a97d009ec841bc8063d54fe7de
blob + e51d195f32727b7d174beda4ab7ffb3f25358a07
--- src/libthread/mkfile
+++ src/libthread/mkfile
<$PLAN9/src/mkhdr
LIB=libthread.a
-
+THREAD=`sh ./thread.sh`
OFILES=\
$OBJTYPE.$O\
+ $THREAD.$O\
asm-$SYSNAME-$OBJTYPE.$O\
channel.$O\
chanprint.$O\
create.$O\
+ daemon.$O\
debug.$O\
exec-unix.$O\
exit.$O\
memset.$O\
memsetd.$O\
note.$O\
- pthread.$O\
read9pmsg.$O\
ref.$O\
sched.$O\
CFLAGS=$CFLAGS $VG
+Linux-clone.$O: execproc.ch exit-getpid.ch proctab.ch procstack.ch
blob - 94bf236a3374ebd8ff61c71fc5119be701276fc5
blob + ed40c08fb5d956428270200a53d4cb5cf8642dbf
--- src/libthread/note.c
+++ src/libthread/note.c
#include "threadimpl.h"
+
int _threadnopasser;
#define NFN 33
blob - a914f433d12dbb51efa02f75e7a318095137209f
blob + 8d661c166e0ad6786f0615081cb181da7dec4668
--- src/libthread/pthread.c
+++ src/libthread/pthread.c
}
/*
+ * Called to start a new proc.
+ */
+void
+_threadstartproc(Proc *p)
+{
+ Proc *np;
+ pthread_t tid;
+ sigset_t all;
+
+ np = p->newproc;
+ sigfillset(&all);
+ pthread_sigmask(SIG_SETMASK, &all, nil);
+ if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler,
+ np) < 0)
+ sysfatal("pthread_create: %r");
+ np->pthreadid = tid;
+}
+
+/*
* Called to associate p with the current pthread.
*/
void
/*
* Separate process to wait for child messages.
+ * Also runs signal handlers.
*/
-Channel *_threadexecchan;
-void
+static Channel *_threadexecchan;
+static void
_threadwaitproc(void *v)
{
Channel *c;
{
}
+/*
+ * Called from mainlauncher before threadmain.
+ */
void
_threadmaininit(void)
{
unlock(&_threadpq.lock);
}
+/*
+ * Called after forking the exec child.
+ */
void
_threadafterexec(void)
{
nbsendul(_threadexecchan, 1);
}
-/*
- * Called to start a new proc.
- */
-void
-_threadstartproc(Proc *p)
-{
- Proc *np;
- pthread_t tid;
- sigset_t all;
-
- np = p->newproc;
- sigfillset(&all);
- pthread_sigmask(SIG_SETMASK, &all, nil);
- if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler,
- np) < 0)
- sysfatal("pthread_create: %r");
- np->pthreadid = tid;
-}
blob - 55898f08198ada2ac6a5de9e127525f4eb31638b
blob + 7e430193545527a15372f10801f57097f69d82e7
--- src/libthread/sched.c
+++ src/libthread/sched.c
/*
* If thread needs to die, kill it.
+ * t->proc == p may not be true if we're
+ * trying to jump into the exec proc (see exec-unix.c).
*/
if(t->moribund){
_threaddebug(DBGSCHED, "moribund %d.%d", p->id, t->id);
+ if(t->moribund != 1)
+ print("moribund broke %p %d\n", &t->moribund, t->moribund);
assert(t->moribund == 1);
t->state = Dead;
- if(t->prevt)
- t->prevt->nextt = t->nextt;
- else
- p->threads.head = t->nextt;
- if(t->nextt)
- t->nextt->prevt = t->prevt;
- else
- p->threads.tail = t->prevt;
+ _procdelthread(p, t);
unlock(&p->lock);
_threadfree(t);
- p->nthreads--;
t = nil;
continue;
}
+
+ /*
+ * If the thread has asked to move to another proc,
+ * let it go (only to be used in *very* special situations).
+ if(t->nextproc != p)
+ _procdelthread(p, t);
+ */
+
unlock(&p->lock);
/*
+ * If the thread has asked to move to another proc,
+ * add it to the new proc.
+ */
+ if(t->nextproc != p){
+ // lock(&t->nextproc->lock);
+ // _procaddthread(t->nextproc, t);
+ // unlock(&t->nextproc->lock);
+ t->proc = t->nextproc;
+ }
+
+ /*
* If there is a request to run a function on the
* scheduling stack, do so.
*/
* Move the thread along.
*/
t->state = t->nextstate;
- _threaddebug(DBGSCHED, "moveon %d.%d", p->id, t->id);
+ _threaddebug(DBGSCHED, "moveon %d.%d", t->proc->id, t->id);
if(t->state == Ready)
_threadready(t);
}
blob - bcfabee6d8c5739f1d5d2546d308f7b312d8f798
blob + c9682e35d7d1035174554824dc570b5032cf36e6
--- src/libthread/texec.c
+++ src/libthread/texec.c
{
Channel *c;
Waitmsg *w;
+ int (*mk)(void(*)(void*), void*, uint);
+ mk = threadcreate;
ARGBEGIN{
case 'D':
_threaddebuglevel = ~0;
break;
+ case 'p':
+ mk = proccreate;
+ break;
}ARGEND
c = threadwaitchan();
- proccreate(doexec, argv, 8192);
+ mk(doexec, argv, 8192);
w = recvp(c);
if(w == nil)
print("exec/recvp failed: %r\n");
blob - 7c9a66bbfece1cb4785eb3e4759949089fa73f7c
blob + 8d7a7a75d5dc30eb01af9111011dd01dad90bff7
--- src/libthread/threadimpl.h
+++ src/libthread/threadimpl.h
int asleep; /* thread is in _threadsleep */
Label context; /* for context switches */
int grp; /* thread group */
+ Proc *homeproc; /* ``home'' proc */
int id; /* thread id */
int moribund; /* thread needs to die */
char *name; /* name of thread */
Thread *next; /* next on ready queue */
Thread *nextt; /* next on list of threads in this proc */
+ Proc *nextproc; /* next proc in which to run (rarely changes) */
State nextstate; /* next run state */
Proc *proc; /* proc of this thread */
Thread *prevt; /* prev on list of threads in this proc */
Thread *thread; /* running thread */
Thread *idle; /* idle thread */
int id;
+ int procid;
int needexec;
Execargs exec; /* exec argument */
void _threadstartproc(Proc*);
void _threadexitproc(char*);
void _threadexitallproc(char*);
+void _threadefork(int[3], int[2], char*, char**);
+extern int _threadmainpid;
extern int _threadnprocs;
extern int _threaddebuglevel;
extern char* _threadexitsallstatus;
extern void _threaddebugmemset(void*, int, int);
extern int _threadprocs;
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);