still more files

This commit is contained in:
rsc 2004-11-08 16:04:01 +00:00
parent cf4f3eafc6
commit 24f4e66b12
5 changed files with 300 additions and 0 deletions

185
src/libthread/Linux-clone.c Normal file
View file

@ -0,0 +1,185 @@
#include <u.h>
#include <errno.h>
#include <sched.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include "threadimpl.h"
#define procid() getpid()
#define procexited(id) (kill((id), 0) < 0 && errno==ESRCH)
static int multi;
static Proc *theproc;
/*
* Run all execs forked from a special exec proc.
*/
#include "execproc.ch"
/*
* Use _exits to exit one proc, and signals to tear everyone else down.
*/
#include "exit-getpid.ch"
/*
* Use table for _threadmultiproc, _threadsetproc, _threadgetproc.
*/
#include "proctab.ch"
/*
* Use per-process stack allocation code.
*/
#include "procstack.ch"
/*
* Implement _threadstartproc using clone.
*
* Cannot use this on newer kernels (2.6+) because
* on those kernels clone allows you to set up a per-thread
* segment using %gs, and the C library and compilers
* assume that you've done this. I don't want to learn
* how to do this (the code below is scary enough),
* so on those more recent kernels we use nptl (the
* pthreads implementation), which is finally good enough.
*/
/*
* Trampoline to run f(arg).
*/
static int
tramp(void *v)
{
void (*fn)(void*), *arg;
void **v2;
void *p;
v2 = v;
fn = v2[0];
arg = v2[1];
p = v2[2];
free(v2);
fn(arg);
abort(); /* not reached! */
return 0;
}
/*
* Trampnowait runs in the child, and starts a granchild to run f(arg).
* When trampnowait proc exits, the connection between the
* grandchild running f(arg) and the parent/grandparent is lost, so the
* grandparent need not worry about cleaning up a zombie
* when the grandchild finally exits.
*/
static int
trampnowait(void *v)
{
int pid;
int cloneflag;
void **v2;
int *pidp;
void *p;
v2 = v;
cloneflag = (int)v2[4];
pidp = v2[3];
p = v2[2];
pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
*pidp = pid;
_exit(0);
return 0;
}
static int
ffork(int flags, void (*fn)(void*), void *arg)
{
void **v;
char *p;
int cloneflag, pid, thepid, status, nowait;
p = mallocstack();
v = malloc(sizeof(void*)*5);
if(p==nil || v==nil){
freestack(p);
free(v);
return -1;
}
cloneflag = 0;
flags &= ~RFPROC;
if(flags&RFMEM){
cloneflag |= CLONE_VM;
flags &= ~RFMEM;
}
if(!(flags&RFFDG))
cloneflag |= CLONE_FILES;
else
flags &= ~RFFDG;
nowait = flags&RFNOWAIT;
// if(!(flags&RFNOWAIT))
// cloneflag |= SIGCHLD;
// else
flags &= ~RFNOWAIT;
if(flags){
fprint(2, "unknown rfork flags %x\n", flags);
freestack(p);
free(v);
return -1;
}
v[0] = fn;
v[1] = arg;
v[2] = p;
v[3] = &thepid;
v[4] = (void*)cloneflag;
thepid = -1;
pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
if(pid > 0 && nowait){
if(wait4(pid, &status, __WALL, 0) < 0)
fprint(2, "ffork wait4: %r\n");
}else
thepid = pid;
if(thepid == -1)
freestack(p);
else{
((Stack*)p)->pid = thepid;
}
return thepid;
}
/*
* Called to start a new proc.
*/
void
_threadstartproc(Proc *p)
{
int pid;
Proc *np;
np = p->newproc;
pid = ffork(RFPROC|RFMEM|RFNOWAIT, _threadscheduler, np);
if(pid == -1)
sysfatal("starting new proc: %r");
np->pid = pid;
}
/*
* Called to associate p with the current pthread.
*/
void
_threadinitproc(Proc *p)
{
sigset_t mask;
p->pid = getpid();
sigemptyset(&mask);
sigaddset(&mask, WAITSIG);
sigprocmask(SIG_BLOCK, &mask, nil);
_threadsetproc(p);
}
/*
* Called from mainlauncher before threadmain.
*/
void
_threadmaininit(void)
{
}

25
src/libthread/pid.c Normal file
View file

@ -0,0 +1,25 @@
mypid = getpid();
/*
* signal others.
* copying all the pids first avoids other thread's
* teardown procedures getting in the way.
*/
lock(&_threadpq.lock);
npid = 0;
for(p=_threadpq.head; p; p=p->next)
npid++;
pid = _threadmalloc(npid*sizeof(pid[0]), 0);
npid = 0;
for(p = _threadpq.head; p; p=p->next)
pid[npid++] = p->pid;
unlock(&_threadpq.lock);
for(i=0; i<npid; i++){
_threaddebug(DBGSCHED, "threadexitsall kill %d", pid[i]);
if(pid[i]==0 || pid[i]==-1)
fprint(2, "bad pid in threadexitsall: %d\n", pid[i]);
else if(pid[i] != mypid){
kill(pid[i], SIGTERM);
}
}

36
src/libthread/setproc.c Normal file
View file

@ -0,0 +1,36 @@
/*
* Avoid using threading calls for single-proc programs.
*/
#include "threadimpl.h"
static int multi;
static Proc *theproc;
void
_threadsetproc(Proc *p)
{
if(!multi)
theproc = p;
else
_kthreadsetproc(p);
}
Proc*
_threadgetproc(void)
{
if(!multi)
return theproc;
return _kthreadgetproc();
}
void
_threadmultiproc(void)
{
if(multi)
return;
multi = 1;
_kthreadinit();
_threadsetproc(theproc);
}

View file

@ -0,0 +1,11 @@
#!/bin/sh
case "`uname`-`uname -r`" in
Linux-2.[01234]*)
echo Linux-clone.o ucontext.o
exit 0
;;
esac
echo pthread.o ucontext.o
exit 0

43
src/libthread/tsignal.c Normal file
View file

@ -0,0 +1,43 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
extern int _threaddebuglevel;
void
usage(void)
{
fprint(2, "usage: tsignal [-[ednf] note]*\n");
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
Channel *c;
char *msg;
ARGBEGIN{
case 'D':
_threaddebuglevel = ~0;
break;
default:
usage();
case 'e':
notifyenable(EARGF(usage()));
break;
case 'd':
notifydisable(EARGF(usage()));
break;
case 'n':
notifyon(EARGF(usage()));
break;
case 'f':
notifyoff(EARGF(usage()));
break;
}ARGEND
c = threadnotechan();
while((msg = recvp(c)) != nil)
print("note: %s\n", msg);
}