Commit 376898ca authored by Russ Cox's avatar Russ Cox

go threads for OS X

R=r
OCL=14944
CL=15013
parent c59d2f13
......@@ -22,6 +22,11 @@ struct timespec {
int64 tv_nsec;
};
struct timeval {
time_t tv_sec;
int64 tv_usec;
};
struct stat { // really a stat64
dev_t st_dev;
mode_t st_mode;
......@@ -43,3 +48,19 @@ struct stat { // really a stat64
};
#define O_CREAT 0x0200
void bsdthread_create(void*, M*, G*, void(*)(void));
void bsdthread_register(void);
int64 select(int32, void*, void*, void*, struct timeval*);
// Mach calls
typedef int32 kern_return_t;
typedef uint32 mach_port_t;
mach_port_t semcreate(void);
void semacquire(mach_port_t);
void semrelease(mach_port_t);
void semreset(mach_port_t);
void semdestroy(mach_port_t);
......@@ -49,5 +49,5 @@ struct stat {
// Linux-specific system calls
int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32);
int64 clone(int32, void*, M*, G*, void(*)(void));
int64 select(int32, void*, void*, void*, void*);
int64 select(int32, void*, void*, void*, struct timeval*);
......@@ -4,9 +4,8 @@
#include "runtime.h"
// TODO locking of select
static int32 debug = 0;
static Lock chanlock;
typedef struct Hchan Hchan;
typedef struct Link Link;
......@@ -32,7 +31,6 @@ struct WaitQ
struct Hchan
{
Lock;
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
......@@ -162,7 +160,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
prints("\n");
}
lock(c);
lock(&chanlock);
if(c->dataqsiz > 0)
goto asynch;
......@@ -173,7 +171,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
gp = sg->g;
gp->param = sg;
unlock(c);
unlock(&chanlock);
ready(gp);
if(pres != nil)
......@@ -182,7 +180,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
}
if(pres != nil) {
unlock(c);
unlock(&chanlock);
*pres = false;
return;
}
......@@ -193,13 +191,13 @@ sendchan(Hchan *c, byte *ep, bool *pres)
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(c);
unlock(&chanlock);
sys·gosched();
lock(c);
lock(&chanlock);
sg = g->param;
freesg(c, sg);
unlock(c);
unlock(&chanlock);
return;
asynch:
......@@ -208,9 +206,9 @@ asynch:
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(c);
unlock(&chanlock);
sys·gosched();
lock(c);
lock(&chanlock);
}
if(ep != nil)
c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
......@@ -221,10 +219,10 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
unlock(c);
unlock(&chanlock);
ready(gp);
}else
unlock(c);
unlock(&chanlock);
}
static void
......@@ -239,7 +237,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
prints("\n");
}
lock(c);
lock(&chanlock);
if(c->dataqsiz > 0)
goto asynch;
......@@ -249,7 +247,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
gp = sg->g;
gp->param = sg;
unlock(c);
unlock(&chanlock);
ready(gp);
if(pres != nil)
......@@ -258,7 +256,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
}
if(pres != nil) {
unlock(c);
unlock(&chanlock);
*pres = false;
return;
}
......@@ -267,14 +265,14 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(c);
unlock(&chanlock);
sys·gosched();
lock(c);
lock(&chanlock);
sg = g->param;
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
unlock(c);
unlock(&chanlock);
return;
asynch:
......@@ -282,9 +280,9 @@ asynch:
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(c);
unlock(&chanlock);
sys·gosched();
lock(c);
lock(&chanlock);
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
......@@ -293,10 +291,10 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
unlock(c);
unlock(&chanlock);
ready(gp);
}else
unlock(c);
unlock(&chanlock);
}
// chansend1(hchan *chan any, elem any);
......@@ -371,12 +369,14 @@ sys·newselect(int32 size, Select *sel)
if(size > 1)
n = size-1;
lock(&chanlock);
sel = nil;
if(size >= 1 && size < nelem(selfree)) {
sel = selfree[size];
if(sel != nil)
selfree[size] = sel->link;
}
unlock(&chanlock);
if(sel == nil)
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
......@@ -517,6 +517,8 @@ sys·selectgo(Select *sel)
p %= sel->ncase;
o %= sel->ncase;
lock(&chanlock);
// pass 1 - look for something already waiting
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
......@@ -598,8 +600,10 @@ sys·selectgo(Select *sel)
// (rsc) not correct to set Gwaiting after queueing;
// might already have been readied.
g->status = Gwaiting;
unlock(&chanlock);
sys·gosched();
lock(&chanlock);
sg = g->param;
o = sg->offset;
cas = &sel->scase[o];
......@@ -629,6 +633,7 @@ sys·selectgo(Select *sel)
asynr:
asyns:
unlock(&chanlock);
throw("asyn");
return; // compiler doesn't know throw doesn't return
......@@ -671,6 +676,7 @@ retc:
sel->link = selfree[sel->ncase];
selfree[sel->ncase] = sel;
}
unlock(&chanlock);
sys·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
......
......@@ -341,8 +341,6 @@ scheduler(void)
{
G* gp;
// Initialization.
m->procid = getprocid();
lock(&sched);
if(gosave(&m->sched)){
......@@ -472,7 +470,7 @@ oldstack(void)
mcpy(top->oldsp+16, sp, siz2);
}
// call no more functions after this point - limit register disagrees with R15
// call no more functions after this point - stackguard disagrees with SP
m->curg->stackbase = top->oldbase;
m->curg->stackguard = top->oldguard;
m->morestack.SP = top->oldsp+8;
......
......@@ -33,6 +33,7 @@ TEXT _rt0_amd64(SB),7,$-8
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL args(SB)
CALL osinit(SB)
CALL schedinit(SB)
CALL main·init_function(SB) // initialization
......
This diff is collapsed.
......@@ -427,3 +427,7 @@ sys·sleep(int64 ms)
select(0, nil, nil, nil, &tv);
}
void
osinit(void)
{
}
......@@ -44,7 +44,7 @@ typedef struct M M;
typedef struct Stktop Stktop;
typedef struct Alg Alg;
typedef struct Lock Lock;
typedef struct Note Note;
typedef union Note Note;
typedef struct Mem Mem;
/*
......@@ -78,10 +78,17 @@ enum
struct Lock
{
uint32 key;
uint32 sema; // for OS X
};
struct Note
union Note
{
Lock lock;
struct { // Linux
Lock lock;
};
struct { // OS X
int32 wakeup;
uint32 sema;
};
};
struct String
{
......@@ -149,6 +156,7 @@ struct M
G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move
uint64 cret; // return value from C - must not move
uint64 procid; // for debuggers - must not move
G* curg; // current running goroutine
G* lastg; // last running goroutine - to emulate fifo
Gobuf sched;
......@@ -159,8 +167,8 @@ struct M
Note havenextg;
G* nextg;
M* schedlink;
int32 procid; // for debuggers
Mem mem;
uint32 machport; // Return address for Mach IPC (OS X)
};
struct Stktop
{
......@@ -239,7 +247,6 @@ void ready(G*);
byte* getenv(int8*);
int32 atoi(byte*);
void newosproc(M *m, G *g, void *stk, void (*fn)(void));
int32 getprocid(void);
/*
* mutual exclusion locks. in the uncontended case,
......
......@@ -4,12 +4,11 @@
//
// System calls and other sys.stuff for AMD64, Darwin
// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
//
// TODO(rsc): Either sys·exit or exit1 is wrong!
// It looks like sys·exit is correct (exits the entire program)
// and exit1 should be mimicking the OS X library routine
// __bsdthread_terminate.
// Exit the entire program (like C exit)
TEXT sys·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
......@@ -17,9 +16,11 @@ TEXT sys·exit(SB),7,$-8
CALL notok(SB)
RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
TEXT exit1(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
CALL notok(SB)
RET
......@@ -130,3 +131,127 @@ TEXT sys·setcallerpc+0(SB),7,$0
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
TEXT bsdthread_create(SB),7,$-8
// Set up arguments to bsdthread_create system call.
// The ones in quotes pass through to the thread callback
// uninterpreted, so we can put whatever we want there.
MOVQ fn+32(SP), DI // "func"
MOVQ m+16(SP), SI // "arg"
MOVQ stk+8(SP), DX // stack
MOVQ g+24(SP), R10 // "pthread"
MOVQ $0, R10 // flags
MOVQ $(0x2000000+360), AX // bsdthread_create
SYSCALL
JCC 2(PC)
CALL notok(SB)
RET
// The thread that bsdthread_create creates starts executing here,
// because we registered this function using bsdthread_register
// at startup.
// DI = "pthread" (= g)
// SI = mach thread port
// DX = "func" (= fn)
// CX = "arg" (= m)
// R8 = stack
// R9 = flags (= 0)
// SP = stack - C_64_REDZONE_LEN (= stack - 128)
TEXT bsdthread_start(SB),7,$-8
MOVQ CX, R14 // m
MOVQ DI, R15 // g
MOVQ SI, 24(R14) // thread port is m->procid
CALL DX // fn
CALL exit1(SB)
RET
// void bsdthread_register(void)
// registers callbacks for threadstart (see bsdthread_create above
// and wqthread and pthsize (not used). returns 0 on success.
TEXT bsdthread_register(SB),7,$-8
MOVQ $bsdthread_start(SB), DI // threadstart
MOVQ $0, SI // wqthread, not used by us
MOVQ $0, DX // pthsize, not used by us
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 2(PC)
CALL notok(SB)
RET
// int64 select(int32, void*, void*, void*, void*)
TEXT select(SB),7,$0
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
MOVQ 32(SP), R10
MOVQ 40(SP), R8
MOVL $(0x2000000+407), AX // select_nocancel
SYSCALL
RET
// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
TEXT mach_msg_trap(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
MOVL 24(SP), R10
MOVL 28(SP), R8
MOVL 32(SP), R9
MOVL 36(SP), R11
PUSHQ R11 // seventh arg, on stack
MOVL $(0x1000000+31), AX // mach_msg_trap
SYSCALL
POPQ R11
RET
TEXT mach_task_self(SB),7,$0
MOVL $(0x1000000+28), AX // task_self_trap
SYSCALL
RET
TEXT mach_thread_self(SB),7,$0
MOVL $(0x1000000+27), AX // thread_self_trap
SYSCALL
RET
TEXT mach_reply_port(SB),7,$0
MOVL $(0x1000000+26), AX // mach_reply_port
SYSCALL
RET
// Mach provides trap versions of the semaphore ops,
// instead of requiring the use of RPC.
// uint32 mach_semaphore_wait(uint32)
TEXT mach_semaphore_wait(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+36), AX // semaphore_wait_trap
SYSCALL
RET
// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
TEXT mach_semaphore_timedwait(SB),7,$0
MOVL 8(SP), DI
MOVL 12(SP), SI
MOVL 16(SP), DX
MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
SYSCALL
RET
// uint32 mach_semaphore_signal(uint32)
TEXT mach_semaphore_signal(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+33), AX // semaphore_signal_trap
SYSCALL
RET
// uint32 mach_semaphore_signal_all(uint32)
TEXT mach_semaphore_signal_all(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
SYSCALL
RET
......@@ -162,10 +162,17 @@ TEXT clone(SB),7,$0
JEQ 2(PC)
RET
// In child, call fn on new stack
// In child, set up new stack
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
MOVQ AX, 24(R14)
// Call fn
CALL R12
// It shouldn't return. If it does, exi
......@@ -174,7 +181,7 @@ TEXT clone(SB),7,$0
SYSCALL
JMP -3(PC) // keep exiting
// int64 select(int32, void*, void*, void*, void*)
// int64 select(int32, void*, void*, void*, struct timeval*)
TEXT select(SB),7,$0
MOVL 8(SP), DI
MOVQ 16(SP), SI
......@@ -185,16 +192,3 @@ TEXT select(SB),7,$0
SYSCALL
RET
// Linux allocates each thread its own pid, like Plan 9.
// But the getpid() system call returns the pid of the
// original thread (the one that exec started with),
// no matter which thread asks. This system call,
// which Linux calls gettid, returns the actual pid of
// the calling thread, not the fake one.
//
// int32 getprocid(void)
TEXT getprocid(SB),7,$0
MOVL $186, AX
SYSCALL
RET
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment