More Darwin.

This commit is contained in:
rsc 2003-10-01 02:53:00 +00:00
parent a995e477ff
commit a46395ecf9
10 changed files with 311 additions and 246 deletions

26
src/lib9/ffork-Darwin.c Normal file
View file

@ -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();
}

View file

@ -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_ */

2
src/lib9/rendez-Darwin.c Normal file
View file

@ -0,0 +1,2 @@
#include "rendez-pthread.c"

View file

@ -0,0 +1 @@
#include "rendez-signal.c"

1
src/lib9/rendez-Linux.c Normal file
View file

@ -0,0 +1 @@
#include "rendez-signal.c"

168
src/lib9/rendez-pthread.c Normal file
View file

@ -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;
}

5
src/libthread/Darwin.c Normal file
View file

@ -0,0 +1,5 @@
int
_schedfork(Proc *p)
{
return ffork(RFMEM|RFNOWAIT, _schedinit, p);
}

View file

@ -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;
}

View file

@ -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