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 { ...@@ -22,6 +22,11 @@ struct timespec {
int64 tv_nsec; int64 tv_nsec;
}; };
struct timeval {
time_t tv_sec;
int64 tv_usec;
};
struct stat { // really a stat64 struct stat { // really a stat64
dev_t st_dev; dev_t st_dev;
mode_t st_mode; mode_t st_mode;
...@@ -43,3 +48,19 @@ struct stat { // really a stat64 ...@@ -43,3 +48,19 @@ struct stat { // really a stat64
}; };
#define O_CREAT 0x0200 #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 { ...@@ -49,5 +49,5 @@ struct stat {
// Linux-specific system calls // Linux-specific system calls
int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32); int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32);
int64 clone(int32, void*, M*, G*, void(*)(void)); 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 @@ ...@@ -4,9 +4,8 @@
#include "runtime.h" #include "runtime.h"
// TODO locking of select
static int32 debug = 0; static int32 debug = 0;
static Lock chanlock;
typedef struct Hchan Hchan; typedef struct Hchan Hchan;
typedef struct Link Link; typedef struct Link Link;
...@@ -32,7 +31,6 @@ struct WaitQ ...@@ -32,7 +31,6 @@ struct WaitQ
struct Hchan struct Hchan
{ {
Lock;
uint32 elemsize; uint32 elemsize;
uint32 dataqsiz; // size of the circular q uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q uint32 qcount; // total data in the q
...@@ -162,7 +160,7 @@ sendchan(Hchan *c, byte *ep, bool *pres) ...@@ -162,7 +160,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
prints("\n"); prints("\n");
} }
lock(c); lock(&chanlock);
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
goto asynch; goto asynch;
...@@ -173,7 +171,7 @@ sendchan(Hchan *c, byte *ep, bool *pres) ...@@ -173,7 +171,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
unlock(c); unlock(&chanlock);
ready(gp); ready(gp);
if(pres != nil) if(pres != nil)
...@@ -182,7 +180,7 @@ sendchan(Hchan *c, byte *ep, bool *pres) ...@@ -182,7 +180,7 @@ sendchan(Hchan *c, byte *ep, bool *pres)
} }
if(pres != nil) { if(pres != nil) {
unlock(c); unlock(&chanlock);
*pres = false; *pres = false;
return; return;
} }
...@@ -193,13 +191,13 @@ sendchan(Hchan *c, byte *ep, bool *pres) ...@@ -193,13 +191,13 @@ sendchan(Hchan *c, byte *ep, bool *pres)
g->param = nil; g->param = nil;
g->status = Gwaiting; g->status = Gwaiting;
enqueue(&c->sendq, sg); enqueue(&c->sendq, sg);
unlock(c); unlock(&chanlock);
sys·gosched(); sys·gosched();
lock(c); lock(&chanlock);
sg = g->param; sg = g->param;
freesg(c, sg); freesg(c, sg);
unlock(c); unlock(&chanlock);
return; return;
asynch: asynch:
...@@ -208,9 +206,9 @@ asynch: ...@@ -208,9 +206,9 @@ asynch:
sg = allocsg(c); sg = allocsg(c);
g->status = Gwaiting; g->status = Gwaiting;
enqueue(&c->sendq, sg); enqueue(&c->sendq, sg);
unlock(c); unlock(&chanlock);
sys·gosched(); sys·gosched();
lock(c); lock(&chanlock);
} }
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, c->senddataq->elem, ep); c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
...@@ -221,10 +219,10 @@ asynch: ...@@ -221,10 +219,10 @@ asynch:
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
freesg(c, sg); freesg(c, sg);
unlock(c); unlock(&chanlock);
ready(gp); ready(gp);
}else }else
unlock(c); unlock(&chanlock);
} }
static void static void
...@@ -239,7 +237,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres) ...@@ -239,7 +237,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
prints("\n"); prints("\n");
} }
lock(c); lock(&chanlock);
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
goto asynch; goto asynch;
...@@ -249,7 +247,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres) ...@@ -249,7 +247,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
unlock(c); unlock(&chanlock);
ready(gp); ready(gp);
if(pres != nil) if(pres != nil)
...@@ -258,7 +256,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres) ...@@ -258,7 +256,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
} }
if(pres != nil) { if(pres != nil) {
unlock(c); unlock(&chanlock);
*pres = false; *pres = false;
return; return;
} }
...@@ -267,14 +265,14 @@ chanrecv(Hchan* c, byte *ep, bool* pres) ...@@ -267,14 +265,14 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
g->param = nil; g->param = nil;
g->status = Gwaiting; g->status = Gwaiting;
enqueue(&c->recvq, sg); enqueue(&c->recvq, sg);
unlock(c); unlock(&chanlock);
sys·gosched(); sys·gosched();
lock(c); lock(&chanlock);
sg = g->param; sg = g->param;
c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg); freesg(c, sg);
unlock(c); unlock(&chanlock);
return; return;
asynch: asynch:
...@@ -282,9 +280,9 @@ asynch: ...@@ -282,9 +280,9 @@ asynch:
sg = allocsg(c); sg = allocsg(c);
g->status = Gwaiting; g->status = Gwaiting;
enqueue(&c->recvq, sg); enqueue(&c->recvq, sg);
unlock(c); unlock(&chanlock);
sys·gosched(); sys·gosched();
lock(c); lock(&chanlock);
} }
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link; c->recvdataq = c->recvdataq->link;
...@@ -293,10 +291,10 @@ asynch: ...@@ -293,10 +291,10 @@ asynch:
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
freesg(c, sg); freesg(c, sg);
unlock(c); unlock(&chanlock);
ready(gp); ready(gp);
}else }else
unlock(c); unlock(&chanlock);
} }
// chansend1(hchan *chan any, elem any); // chansend1(hchan *chan any, elem any);
...@@ -371,12 +369,14 @@ sys·newselect(int32 size, Select *sel) ...@@ -371,12 +369,14 @@ sys·newselect(int32 size, Select *sel)
if(size > 1) if(size > 1)
n = size-1; n = size-1;
lock(&chanlock);
sel = nil; sel = nil;
if(size >= 1 && size < nelem(selfree)) { if(size >= 1 && size < nelem(selfree)) {
sel = selfree[size]; sel = selfree[size];
if(sel != nil) if(sel != nil)
selfree[size] = sel->link; selfree[size] = sel->link;
} }
unlock(&chanlock);
if(sel == nil) if(sel == nil)
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0])); sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
...@@ -517,6 +517,8 @@ sys·selectgo(Select *sel) ...@@ -517,6 +517,8 @@ sys·selectgo(Select *sel)
p %= sel->ncase; p %= sel->ncase;
o %= sel->ncase; o %= sel->ncase;
lock(&chanlock);
// pass 1 - look for something already waiting // pass 1 - look for something already waiting
for(i=0; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o]; cas = &sel->scase[o];
...@@ -598,8 +600,10 @@ sys·selectgo(Select *sel) ...@@ -598,8 +600,10 @@ sys·selectgo(Select *sel)
// (rsc) not correct to set Gwaiting after queueing; // (rsc) not correct to set Gwaiting after queueing;
// might already have been readied. // might already have been readied.
g->status = Gwaiting; g->status = Gwaiting;
unlock(&chanlock);
sys·gosched(); sys·gosched();
lock(&chanlock);
sg = g->param; sg = g->param;
o = sg->offset; o = sg->offset;
cas = &sel->scase[o]; cas = &sel->scase[o];
...@@ -629,6 +633,7 @@ sys·selectgo(Select *sel) ...@@ -629,6 +633,7 @@ sys·selectgo(Select *sel)
asynr: asynr:
asyns: asyns:
unlock(&chanlock);
throw("asyn"); throw("asyn");
return; // compiler doesn't know throw doesn't return return; // compiler doesn't know throw doesn't return
...@@ -671,6 +676,7 @@ retc: ...@@ -671,6 +676,7 @@ retc:
sel->link = selfree[sel->ncase]; sel->link = selfree[sel->ncase];
selfree[sel->ncase] = sel; selfree[sel->ncase] = sel;
} }
unlock(&chanlock);
sys·setcallerpc(&sel, cas->pc); sys·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so; as = (byte*)&sel + cas->so;
......
...@@ -341,8 +341,6 @@ scheduler(void) ...@@ -341,8 +341,6 @@ scheduler(void)
{ {
G* gp; G* gp;
// Initialization.
m->procid = getprocid();
lock(&sched); lock(&sched);
if(gosave(&m->sched)){ if(gosave(&m->sched)){
...@@ -472,7 +470,7 @@ oldstack(void) ...@@ -472,7 +470,7 @@ oldstack(void)
mcpy(top->oldsp+16, sp, siz2); 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->stackbase = top->oldbase;
m->curg->stackguard = top->oldguard; m->curg->stackguard = top->oldguard;
m->morestack.SP = top->oldsp+8; m->morestack.SP = top->oldsp+8;
......
...@@ -33,6 +33,7 @@ TEXT _rt0_amd64(SB),7,$-8 ...@@ -33,6 +33,7 @@ TEXT _rt0_amd64(SB),7,$-8
MOVQ 24(SP), AX // copy argv MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP) MOVQ AX, 8(SP)
CALL args(SB) CALL args(SB)
CALL osinit(SB)
CALL schedinit(SB) CALL schedinit(SB)
CALL main·init_function(SB) // initialization CALL main·init_function(SB) // initialization
......
This diff is collapsed.
...@@ -427,3 +427,7 @@ sys·sleep(int64 ms) ...@@ -427,3 +427,7 @@ sys·sleep(int64 ms)
select(0, nil, nil, nil, &tv); select(0, nil, nil, nil, &tv);
} }
void
osinit(void)
{
}
...@@ -44,7 +44,7 @@ typedef struct M M; ...@@ -44,7 +44,7 @@ typedef struct M M;
typedef struct Stktop Stktop; typedef struct Stktop Stktop;
typedef struct Alg Alg; typedef struct Alg Alg;
typedef struct Lock Lock; typedef struct Lock Lock;
typedef struct Note Note; typedef union Note Note;
typedef struct Mem Mem; typedef struct Mem Mem;
/* /*
...@@ -78,10 +78,17 @@ enum ...@@ -78,10 +78,17 @@ enum
struct Lock struct Lock
{ {
uint32 key; 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 struct String
{ {
...@@ -149,6 +156,7 @@ struct M ...@@ -149,6 +156,7 @@ struct M
G* g0; // g0 w interrupt stack - must not move G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move uint64 morearg; // arg to morestack - must not move
uint64 cret; // return value from C - 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* curg; // current running goroutine
G* lastg; // last running goroutine - to emulate fifo G* lastg; // last running goroutine - to emulate fifo
Gobuf sched; Gobuf sched;
...@@ -159,8 +167,8 @@ struct M ...@@ -159,8 +167,8 @@ struct M
Note havenextg; Note havenextg;
G* nextg; G* nextg;
M* schedlink; M* schedlink;
int32 procid; // for debuggers
Mem mem; Mem mem;
uint32 machport; // Return address for Mach IPC (OS X)
}; };
struct Stktop struct Stktop
{ {
...@@ -239,7 +247,6 @@ void ready(G*); ...@@ -239,7 +247,6 @@ void ready(G*);
byte* getenv(int8*); byte* getenv(int8*);
int32 atoi(byte*); int32 atoi(byte*);
void newosproc(M *m, G *g, void *stk, void (*fn)(void)); void newosproc(M *m, G *g, void *stk, void (*fn)(void));
int32 getprocid(void);
/* /*
* mutual exclusion locks. in the uncontended case, * mutual exclusion locks. in the uncontended case,
......
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
// //
// System calls and other sys.stuff for AMD64, Darwin // 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! // Exit the entire program (like C exit)
// It looks like sys·exit is correct (exits the entire program)
// and exit1 should be mimicking the OS X library routine
// __bsdthread_terminate.
TEXT sys·exit(SB),7,$-8 TEXT sys·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry MOVL $(0x2000000+1), AX // syscall entry
...@@ -17,9 +16,11 @@ TEXT sys·exit(SB),7,$-8 ...@@ -17,9 +16,11 @@ TEXT sys·exit(SB),7,$-8
CALL notok(SB) CALL notok(SB)
RET RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
TEXT exit1(SB),7,$-8 TEXT exit1(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry MOVL $(0x2000000+361), AX // syscall entry
SYSCALL SYSCALL
CALL notok(SB) CALL notok(SB)
RET RET
...@@ -130,3 +131,127 @@ TEXT sys·setcallerpc+0(SB),7,$0 ...@@ -130,3 +131,127 @@ TEXT sys·setcallerpc+0(SB),7,$0
MOVQ x+8(FP), BX MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc MOVQ BX, -8(AX) // set calling pc
RET 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 ...@@ -162,10 +162,17 @@ TEXT clone(SB),7,$0
JEQ 2(PC) JEQ 2(PC)
RET RET
// In child, call fn on new stack // In child, set up new stack
MOVQ SI, SP MOVQ SI, SP
MOVQ R8, R14 // m MOVQ R8, R14 // m
MOVQ R9, R15 // g MOVQ R9, R15 // g
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
MOVQ AX, 24(R14)
// Call fn
CALL R12 CALL R12
// It shouldn't return. If it does, exi // It shouldn't return. If it does, exi
...@@ -174,7 +181,7 @@ TEXT clone(SB),7,$0 ...@@ -174,7 +181,7 @@ TEXT clone(SB),7,$0
SYSCALL SYSCALL
JMP -3(PC) // keep exiting 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 TEXT select(SB),7,$0
MOVL 8(SP), DI MOVL 8(SP), DI
MOVQ 16(SP), SI MOVQ 16(SP), SI
...@@ -185,16 +192,3 @@ TEXT select(SB),7,$0 ...@@ -185,16 +192,3 @@ TEXT select(SB),7,$0
SYSCALL SYSCALL
RET 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