tstill more files - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 24f4e66b12cf0501d0f239ade10b2963f46e6755
 (DIR) parent cf4f3eafc6016ccdb57773215dcdd5ebac95c07d
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon,  8 Nov 2004 16:04:01 +0000
       
       still more files
       
       Diffstat:
         A src/libthread/Linux-clone.c         |     185 ++++++++++++++++++++++++++++++
         A src/libthread/pid.c                 |      25 +++++++++++++++++++++++++
         A src/libthread/setproc.c             |      36 +++++++++++++++++++++++++++++++
         A src/libthread/sysofiles.sh          |      11 +++++++++++
         A src/libthread/tsignal.c             |      43 ++++++++++++++++++++++++++++++
       
       5 files changed, 300 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/libthread/Linux-clone.c b/src/libthread/Linux-clone.c
       t@@ -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)
       +{
       +}
       +
 (DIR) diff --git a/src/libthread/pid.c b/src/libthread/pid.c
       t@@ -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);
       +                }
       +        }
       +
 (DIR) diff --git a/src/libthread/setproc.c b/src/libthread/setproc.c
       t@@ -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);
       +}
 (DIR) diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh
       t@@ -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
 (DIR) diff --git a/src/libthread/tsignal.c b/src/libthread/tsignal.c
       t@@ -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);
       +}