tMore Darwin. - 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 a46395ecf932ea4e91ad047e92d1c70395e15673
 (DIR) parent a995e477ffb4dd1184da87e9e46a9e57f3178c63
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed,  1 Oct 2003 02:53:00 +0000
       
       More Darwin.
       
       Diffstat:
         A src/lib9/ffork-Darwin.c             |      26 ++++++++++++++++++++++++++
         D src/lib9/lib9.h                     |     246 -------------------------------
         A src/lib9/rendez-Darwin.c            |       2 ++
         A src/lib9/rendez-FreeBSD.c           |       1 +
         A src/lib9/rendez-Linux.c             |       1 +
         A src/lib9/rendez-pthread.c           |     168 +++++++++++++++++++++++++++++++
         R src/lib9/rendez.c -> src/lib9/rend… |       0 
         A src/libthread/Darwin.c              |       5 +++++
         A src/libthread/PowerMacintosh.c      |      28 ++++++++++++++++++++++++++++
         A src/libthread/asm-Darwin-PowerMaci… |      80 +++++++++++++++++++++++++++++++
       
       10 files changed, 311 insertions(+), 246 deletions(-)
       ---
 (DIR) diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c
       t@@ -0,0 +1,26 @@
       +#include <lib9.h>
       +#include <pthread.h>
       +
       +extern int __isthreaded;
       +int
       +ffork(int flags, void(*fn)(void*), void *arg)
       +{
       +        void *p;
       +        pthread_t tid;
       +
       +        if(flags != (RFMEM|RFNOWAIT)){
       +                werrstr("ffork unsupported");
       +                return -1;
       +        }
       +
       +        if(pthread_create(&tid, NULL, (void*(*)(void*))fn, arg) < 0)
       +                return -1;
       +        return (int)tid;
       +}
       +
       +int
       +getfforkid(void)
       +{
       +        return (int)pthread_self();
       +}
       +
 (DIR) diff --git a/src/lib9/lib9.h b/src/lib9/lib9.h
       t@@ -1,246 +0,0 @@
       -/*
       - * Lib9 is miscellany from the Plan 9 C library that doesn't
       - * fit into libutf or into libfmt, but is still missing from traditional
       - * Unix C libraries.
       - */
       -#ifndef _LIB9H_
       -#define _LIB9H_ 1
       -
       -#if defined(__cplusplus)
       -extern "C" {
       -#endif
       -                                                                                
       -
       -#include <unistd.h>
       -#include <string.h>
       -#include <stdlib.h>
       -#include <stdarg.h>
       -#include <fcntl.h>
       -#include <assert.h>
       -
       -#ifndef _FMTH_
       -#        include <fmt.h>
       -#endif
       -
       -#define        nil        ((void*)0)
       -#define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
       -
       -#define _NEEDUCHAR 1
       -#define _NEEDUSHORT 1
       -#define _NEEDUINT 1
       -#define _NEEDULONG 1
       -
       -#if defined(__linux__)
       -#        include <sys/types.h>
       -#        if defined(__USE_MISC)
       -#                undef _NEEDUSHORT
       -#                undef _NEEDUINT
       -#                undef _NEEDULONG
       -#        endif
       -#endif
       -#if defined(__FreeBSD__)
       -#        include <sys/types.h>
       -#        if !defined(_POSIX_SOURCE)
       -#                undef _NEEDUSHORT
       -#                undef _NEEDUINT
       -#        endif
       -#endif
       -
       -typedef signed char schar;
       -typedef unsigned int u32int;
       -#ifdef _NEEDUCHAR
       -        typedef unsigned char uchar;
       -#endif
       -#ifdef _NEEDUSHORT
       -        typedef unsigned short ushort;
       -#endif
       -#ifdef _NEEDUINT
       -        typedef unsigned int uint;
       -#endif
       -#ifdef _NEEDULONG
       -        typedef unsigned long ulong;
       -#endif
       -typedef unsigned long long uvlong;
       -typedef long long vlong;
       -
       -/* rfork to create new process running fn(arg) */
       -
       -#if defined(__FreeBSD__)
       -#undef RFFDG
       -#undef RFNOTEG
       -#undef RFPROC
       -#undef RFMEM
       -#undef RFNOWAIT
       -#undef RFCFDG
       -#endif
       -
       -enum
       -{
       -/*        RFNAMEG                = (1<<0), */
       -/*        RFENVG                = (1<<1), */
       -        RFFDG                = (1<<2),
       -        RFNOTEG                = (1<<3),
       -        RFPROC                = (1<<4),
       -        RFMEM                = (1<<5),
       -        RFNOWAIT        = (1<<6),
       -/*        RFCNAMEG        = (1<<10), */
       -/*        RFCENVG                = (1<<11), */
       -        RFCFDG                = (1<<12),
       -/*        RFREND                = (1<<13), */
       -/*        RFNOMNT                = (1<<14) */
       -};
       -extern int                ffork(int, void(*)(void*), void*);
       -
       -/* wait for processes */
       -#define wait _p9wait
       -typedef struct Waitmsg Waitmsg;
       -struct Waitmsg
       -{
       -        int pid;        /* of loved one */
       -        ulong time[3];        /* of loved one & descendants */
       -        char        *msg;
       -};
       -extern        int                await(char*, int);
       -extern        Waitmsg*        wait(void);
       -
       -/* synchronization */
       -typedef struct Lock Lock;
       -struct Lock
       -{
       -        int val;
       -};
       -
       -extern int                _tas(void*);
       -extern void        lock(Lock*);
       -extern void        unlock(Lock*);
       -extern int                canlock(Lock*);
       -
       -typedef struct QLp QLp;
       -struct QLp
       -{
       -        int                inuse;
       -        QLp                *next;
       -        int                state;
       -};
       -
       -typedef struct QLock QLock;
       -struct QLock
       -{
       -        Lock        lock;
       -        int                locked;
       -        QLp                *head;
       -        QLp                *tail;
       -};
       -
       -extern void        qlock(QLock*);
       -extern void        qunlock(QLock*);
       -extern int                canqlock(QLock*);
       -extern void        _qlockinit(ulong (*)(ulong, ulong));
       -
       -typedef struct RWLock RWLock;
       -struct RWLock
       -{
       -        Lock        lock;
       -        int                readers;
       -        int                writer;
       -        QLp                *head;
       -        QLp                *tail;
       -};
       -
       -extern void        rlock(RWLock*);
       -extern void        runlock(RWLock*);
       -extern int                canrlock(RWLock*);
       -extern void        wlock(RWLock*);
       -extern void        wunlock(RWLock*);
       -extern int                canwlock(RWLock*);
       -
       -typedef struct Rendez Rendez;
       -struct Rendez
       -{
       -        QLock        *l;
       -        QLp                *head;
       -        QLp                *tail;
       -};
       -
       -extern void        rsleep(Rendez*);
       -extern int                rwakeup(Rendez*);
       -extern int                rwakeupall(Rendez*);
       -
       -extern ulong        rendezvous(ulong, ulong);
       -
       -/* one of a kind */
       -extern void        sysfatal(char*, ...);
       -extern int                nrand(int);
       -extern void        setmalloctag(void*, ulong);
       -extern void        setrealloctag(void*, ulong);
       -extern void        *mallocz(ulong, int);
       -extern long        readn(int, void*, long);
       -extern void        exits(char*);
       -extern void        _exits(char*);
       -extern ulong        getcallerpc(void*);
       -
       -/* string routines */
       -extern char*        strecpy(char*, char*, char*);
       -extern int                tokenize(char*, char**, int);
       -extern int                cistrncmp(char*, char*, int);
       -extern int                cistrcmp(char*, char*);
       -extern char*        cistrstr(char*, char*);
       -extern int                getfields(char*, char**, int, int, char*);
       -extern int                gettokens(char *, char **, int, char *);
       -
       -/* formatting helpers */
       -extern int                dec64(uchar*, int, char*, int);
       -extern int                enc64(char*, int, uchar*, int);
       -extern int                dec32(uchar*, int, char*, int);
       -extern int                enc32(char*, int, uchar*, int);
       -extern int                dec16(uchar*, int, char*, int);
       -extern int                enc16(char*, int, uchar*, int);
       -extern int                encodefmt(Fmt*);
       -
       -/* error string */
       -enum
       -{
       -        ERRMAX = 128
       -};
       -extern void        rerrstr(char*, uint);
       -extern void        werrstr(char*, ...);
       -extern int                errstr(char*, uint);
       -
       -/* compiler directives on plan 9 */
       -#define        USED(x)        if(x){}else{}
       -#define        SET(x)        ((x)=0)
       -
       -/* command line */
       -extern char        *argv0;
       -#define        ARGBEGIN        for((argv0||(argv0=*argv)),argv++,argc--;\
       -                            argv[0] && argv[0][0]=='-' && argv[0][1];\
       -                            argc--, argv++) {\
       -                                char *_args, *_argt;\
       -                                Rune _argc;\
       -                                _args = &argv[0][1];\
       -                                if(_args[0]=='-' && _args[1]==0){\
       -                                        argc--; argv++; break;\
       -                                }\
       -                                _argc = 0;\
       -                                while(*_args && (_args += chartorune(&_argc, _args)))\
       -                                switch(_argc)
       -#define        ARGEND                SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
       -#define        ARGF()                (_argt=_args, _args="",\
       -                                (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
       -#define        EARGF(x)        (_argt=_args, _args="",\
       -                                (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
       -
       -#define        ARGC()                _argc
       -
       -#define OREAD O_RDONLY
       -#define OWRITE O_WRONLY
       -#define AEXIST 0
       -#define AREAD 4
       -#define AWRITE 2
       -#define AEXEC 1
       -
       -#if defined(__cplusplus)
       -}
       -#endif
       -
       -#endif        /* _LIB9H_ */
 (DIR) diff --git a/src/lib9/rendez-Darwin.c b/src/lib9/rendez-Darwin.c
       t@@ -0,0 +1,2 @@
       +#include "rendez-pthread.c"
       +
 (DIR) diff --git a/src/lib9/rendez-FreeBSD.c b/src/lib9/rendez-FreeBSD.c
       t@@ -0,0 +1 @@
       +#include "rendez-signal.c"
 (DIR) diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c
       t@@ -0,0 +1 @@
       +#include "rendez-signal.c"
 (DIR) diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
       t@@ -0,0 +1,168 @@
       +/*
       +     NAME
       +          rendezvous - user level process synchronization
       +
       +     SYNOPSIS
       +          ulong rendezvous(ulong tag, ulong value)
       +
       +     DESCRIPTION
       +          The rendezvous system call allows two processes to synchro-
       +          nize and exchange a value.  In conjunction with the shared
       +          memory system calls (see segattach(2) and fork(2)), it
       +          enables parallel programs to control their scheduling.
       +
       +          Two processes wishing to synchronize call rendezvous with a
       +          common tag, typically an address in memory they share.  One
       +          process will arrive at the rendezvous first; it suspends
       +          execution until a second arrives.  When a second process
       +          meets the rendezvous the value arguments are exchanged
       +          between the processes and returned as the result of the
       +          respective rendezvous system calls.  Both processes are
       +          awakened when the rendezvous succeeds.
       +
       +          The set of tag values which two processes may use to
       +          rendezvous-their tag space-is inherited when a process
       +          forks, unless RFREND is set in the argument to rfork; see
       +          fork(2).
       +
       +          If a rendezvous is interrupted the return value is ~0, so
       +          that value should not be used in normal communication.
       +
       + * This assumes we're using pthreads and simulates rendezvous using
       + * shared memory and mutexes.
       + */
       +
       +#include <pthread.h>
       +#include <lib9.h>
       +
       +enum
       +{
       +        VOUSHASH = 257,
       +};
       +
       +typedef struct Vous Vous;
       +struct Vous
       +{
       +        Vous *link;
       +        Lock lk;
       +        ulong val;
       +        ulong tag;
       +        pthread_mutex_t mutex;
       +};
       +
       +static void
       +ign(int x)
       +{
       +        USED(x);
       +}
       +
       +void /*__attribute__((constructor))*/
       +ignusr1(void)
       +{
       +        signal(SIGUSR1, ign);
       +}
       +
       +static Vous vouspool[2048];
       +static int nvousused;
       +static Vous *vousfree;
       +static Vous *voushash[VOUSHASH];
       +static Lock vouslock;
       +
       +static Vous*
       +getvous(void)
       +{
       +        Vous *v;
       +
       +        if(vousfree){
       +                v = vousfree;
       +                vousfree = v->link;
       +        }else if(nvousused < nelem(vouspool)){
       +                v = &vouspool[nvousused++];
       +                pthread_mutex_init(&v->mutex, NULL);
       +        }else
       +                abort();
       +        return v;
       +}
       +
       +static void
       +putvous(Vous *v)
       +{
       +        lock(&vouslock);
       +        v->link = vousfree;
       +        vousfree = v;
       +        unlock(&vouslock);
       +}
       +
       +static Vous*
       +findvous(ulong tag, ulong val, int *found)
       +{
       +        int h;
       +        Vous *v, **l;
       +
       +        lock(&vouslock);
       +        h = tag%VOUSHASH;
       +        for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){
       +                if(v->tag == tag){
       +                        *l = v->link;
       +                        *found = 1;
       +                        unlock(&vouslock);
       +                        return v;
       +                }
       +        }
       +        v = getvous();
       +        v->link = voushash[h];
       +        v->val = val;
       +        v->tag = tag;
       +        lock(&v->lk);
       +        voushash[h] = v;
       +        unlock(&vouslock);
       +        *found = 0;
       +        return v;
       +}
       +
       +#define DBG 0
       +ulong
       +rendezvous(ulong tag, ulong val)
       +{
       +        int found;
       +        ulong rval;
       +        Vous *v;
       +
       +        v = findvous(tag, val, &found);
       +        if(!found){
       +                if(DBG)fprint(2, "tag %lux, sleeping on %p\n", tag, v);
       +                /*
       +                 * No rendezvous partner was found; the next guy
       +                 * through will find v and wake us, so we must go
       +                 * to sleep.  Do this by locking the mutex (it is
       +                 * unlocked) and then locking it again (our waker will
       +                 * unlock it for us).
       +                 */
       +                if(pthread_mutex_lock(&v->mutex) != 0)
       +                        abort();
       +                unlock(&v->lk);
       +                if(pthread_mutex_lock(&v->mutex) != 0)
       +                        abort();
       +                rval = v->val;
       +                pthread_mutex_unlock(&v->mutex);
       +                if(DBG)fprint(2, " awake on %p\n", v);
       +                unlock(&v->lk);
       +                putvous(v);
       +        }else{
       +                /*
       +                 * Found someone to meet.  Wake him:
       +                 *
       +                 *        A. lock v->lk (waits for him to lock the mutex once.
       +                 *        B. unlock the mutex (wakes him up)
       +                 */
       +                if(DBG)fprint(2, "found tag %lux on %p, waking\n", tag, v);
       +                lock(&v->lk);
       +                rval = v->val;
       +                v->val = val;
       +                if(pthread_mutex_unlock(&v->mutex) != 0)
       +                        abort();
       +                /* lock passes to him */
       +        }
       +        return rval;
       +}
       +
 (DIR) diff --git a/src/lib9/rendez.c b/src/lib9/rendez-signal.c
 (DIR) diff --git a/src/libthread/Darwin.c b/src/libthread/Darwin.c
       t@@ -0,0 +1,5 @@
       +int
       +_schedfork(Proc *p)
       +{
       +        return ffork(RFMEM|RFNOWAIT, _schedinit, p);
       +}
 (DIR) diff --git a/src/libthread/PowerMacintosh.c b/src/libthread/PowerMacintosh.c
       t@@ -0,0 +1,28 @@
       +#include "threadimpl.h"
       +
       +static void
       +launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
       +        void (*f)(void *arg), void *arg)
       +{
       +        (*f)(arg);
       +        threadexits(nil);
       +}
       +
       +void
       +_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       +{
       +        ulong *tos, *stk;
       +        int n;
       +
       +        tos = (ulong*)&t->stk[t->stksize&~7];
       +        stk = tos;
       +        --stk;
       +        --stk;
       +        --stk;
       +        --stk;
       +        *--stk = (ulong)arg;
       +        *--stk = (ulong)f;
       +        t->sched.pc = (ulong)launcherpower+LABELDPC;
       +        t->sched.sp = (ulong)tos-80;
       +}
       +
 (DIR) diff --git a/src/libthread/asm-Darwin-PowerMacintosh.s b/src/libthread/asm-Darwin-PowerMacintosh.s
       t@@ -0,0 +1,80 @@
       +/* get FPR and VR use flags with sc 0x7FF3 */
       +/* get vsave with mfspr reg, 256 */
       +
       +.text
       +.align 2
       +
       +.globl        __setlabel
       +
       +__setlabel:                                /* xxx: instruction scheduling */
       +        mflr        r0
       +        mfcr        r5
       +        mfctr        r6
       +        mfxer        r7
       +        stw        r0, 0*4(r3)
       +        stw        r5, 1*4(r3)
       +        stw        r6, 2*4(r3)
       +        stw        r7, 3*4(r3)
       +
       +        stw        r1, 4*4(r3)
       +        stw        r2, 5*4(r3)
       +
       +        stw        r13, (0+6)*4(r3)        /* callee-save GPRs */
       +        stw        r14, (1+6)*4(r3)        /* xxx: block move */
       +        stw        r15, (2+6)*4(r3)
       +        stw        r16, (3+6)*4(r3)
       +        stw        r17, (4+6)*4(r3)
       +        stw        r18, (5+6)*4(r3)
       +        stw        r19, (6+6)*4(r3)
       +        stw        r20, (7+6)*4(r3)
       +        stw        r21, (8+6)*4(r3)
       +        stw        r22, (9+6)*4(r3)
       +        stw        r23, (10+6)*4(r3)
       +        stw        r24, (11+6)*4(r3)
       +        stw        r25, (12+6)*4(r3)
       +        stw        r26, (13+6)*4(r3)
       +        stw        r27, (14+6)*4(r3)
       +        stw        r28, (15+6)*4(r3)
       +        stw        r29, (16+6)*4(r3)
       +        stw        r30, (17+6)*4(r3)
       +        stw        r31, (18+6)*4(r3)
       +
       +        li        r3, 0                        /* return */
       +        blr
       +
       +.globl        __gotolabel
       +
       +__gotolabel:
       +        lwz        r13, (0+6)*4(r3)        /* callee-save GPRs */
       +        lwz        r14, (1+6)*4(r3)        /* xxx: block move */
       +        lwz        r15, (2+6)*4(r3)
       +        lwz        r16, (3+6)*4(r3)
       +        lwz        r17, (4+6)*4(r3)
       +        lwz        r18, (5+6)*4(r3)
       +        lwz        r19, (6+6)*4(r3)
       +        lwz        r20, (7+6)*4(r3)
       +        lwz        r21, (8+6)*4(r3)
       +        lwz        r22, (9+6)*4(r3)
       +        lwz        r23, (10+6)*4(r3)
       +        lwz        r24, (11+6)*4(r3)
       +        lwz        r25, (12+6)*4(r3)
       +        lwz        r26, (13+6)*4(r3)
       +        lwz        r27, (14+6)*4(r3)
       +        lwz        r28, (15+6)*4(r3)
       +        lwz        r29, (16+6)*4(r3)
       +        lwz        r30, (17+6)*4(r3)
       +        lwz        r31, (18+6)*4(r3)
       +
       +        lwz        r1, 4*4(r3)
       +        lwz        r2, 5*4(r3)
       +
       +        lwz        r0, 0*4(r3)
       +        mtlr        r0
       +        lwz        r0, 1*4(r3)
       +        mtcr        r0                        /* mtcrf 0xFF, r0 */
       +        lwz        r0, 2*4(r3)
       +        mtctr        r0
       +        lwz        r0, 3*4(r3)
       +        mtxer        r0
       +        li        r3, 1
       +        blr