mirror of
https://github.com/golang/go.git
synced 2024-09-29 14:26:50 +00:00
go threads for OS X
R=r OCL=14944 CL=15013
This commit is contained in:
parent
c59d2f13aa
commit
376898ca8b
@ -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
|
|||||||
};
|
};
|
||||||
|
|
||||||
#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 {
|
|||||||
// 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 @@
|
|||||||
|
|
||||||
#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
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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:
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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:
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
// (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)
|
|||||||
|
|
||||||
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:
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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
|
|||||||
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
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "amd64_darwin.h"
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
|
|
||||||
typedef uint64 __uint64_t;
|
typedef uint64 __uint64_t;
|
||||||
@ -185,53 +186,494 @@ unimplemented(int8 *name)
|
|||||||
void
|
void
|
||||||
sys·sleep(int64 ms)
|
sys·sleep(int64 ms)
|
||||||
{
|
{
|
||||||
unimplemented("sleep");
|
struct timeval tv;
|
||||||
|
|
||||||
|
tv.tv_sec = ms/1000;
|
||||||
|
tv.tv_usec = ms%1000 * 1000;
|
||||||
|
select(0, nil, nil, nil, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thread-safe allocation of a semaphore.
|
||||||
|
// Psema points at a kernel semaphore key.
|
||||||
|
// It starts out zero, meaning no semaphore.
|
||||||
|
// Fill it in, being careful of others calling initsema
|
||||||
|
// simultaneously.
|
||||||
|
static void
|
||||||
|
initsema(uint32 *psema)
|
||||||
|
{
|
||||||
|
uint32 sema;
|
||||||
|
|
||||||
|
if(*psema != 0) // already have one
|
||||||
|
return;
|
||||||
|
|
||||||
|
sema = semcreate();
|
||||||
|
if(!cas(psema, 0, sema)){
|
||||||
|
// Someone else filled it in. Use theirs.
|
||||||
|
semdestroy(sema);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Atomic add and return new value.
|
||||||
|
static uint32
|
||||||
|
xadd(uint32 volatile *val, int32 delta)
|
||||||
|
{
|
||||||
|
uint32 oval, nval;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
oval = *val;
|
||||||
|
nval = oval + delta;
|
||||||
|
if(cas(val, oval, nval))
|
||||||
|
return nval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Blocking locks.
|
||||||
|
|
||||||
|
// Implement Locks, using semaphores.
|
||||||
|
// l->key is the number of threads who want the lock.
|
||||||
|
// In a race, one thread increments l->key from 0 to 1
|
||||||
|
// and the others increment it from >0 to >1. The thread
|
||||||
|
// who does the 0->1 increment gets the lock, and the
|
||||||
|
// others wait on the semaphore. When the 0->1 thread
|
||||||
|
// releases the lock by decrementing l->key, l->key will
|
||||||
|
// be >0, so it will increment the semaphore to wake up
|
||||||
|
// one of the others. This is the same algorithm used
|
||||||
|
// in Plan 9's user-space locks.
|
||||||
|
//
|
||||||
|
// Note that semaphores are never destroyed (the kernel
|
||||||
|
// will clean up when the process exits). We assume for now
|
||||||
|
// that Locks are only used for long-lived structures like M and G.
|
||||||
|
|
||||||
void
|
void
|
||||||
lock(Lock *l)
|
lock(Lock *l)
|
||||||
{
|
{
|
||||||
if(cas(&l->key, 0, 1))
|
// Allocate semaphore if needed.
|
||||||
return;
|
if(l->sema == 0)
|
||||||
unimplemented("lock wait");
|
initsema(&l->sema);
|
||||||
|
|
||||||
|
if(xadd(&l->key, 1) > 1) // someone else has it; wait
|
||||||
|
semacquire(l->sema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
unlock(Lock *l)
|
unlock(Lock *l)
|
||||||
{
|
{
|
||||||
if(cas(&l->key, 1, 0))
|
if(xadd(&l->key, -1) > 0) // someone else is waiting
|
||||||
return;
|
semrelease(l->sema);
|
||||||
unimplemented("unlock wakeup");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Event notifications.
|
||||||
void
|
void
|
||||||
noteclear(Note *n)
|
noteclear(Note *n)
|
||||||
{
|
{
|
||||||
n->lock.key = 0;
|
n->wakeup = 0;
|
||||||
lock(&n->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
notesleep(Note *n)
|
notesleep(Note *n)
|
||||||
{
|
{
|
||||||
lock(&n->lock);
|
if(n->sema == 0)
|
||||||
unlock(&n->lock);
|
initsema(&n->sema);
|
||||||
|
while(!n->wakeup)
|
||||||
|
semacquire(n->sema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
notewakeup(Note *n)
|
notewakeup(Note *n)
|
||||||
{
|
{
|
||||||
unlock(&n->lock);
|
if(n->sema == 0)
|
||||||
|
initsema(&n->sema);
|
||||||
|
n->wakeup = 1;
|
||||||
|
semrelease(n->sema);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// BSD interface for threading.
|
||||||
|
void
|
||||||
|
osinit(void)
|
||||||
|
{
|
||||||
|
// Register our thread-creation callback (see sys_amd64_darwin.s).
|
||||||
|
bsdthread_register();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
newosproc(M *mm, G *gg, void *stk, void (*fn)(void))
|
newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
||||||
{
|
{
|
||||||
unimplemented("newosproc");
|
bsdthread_create(stk, m, g, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
|
||||||
getprocid(void)
|
// Mach IPC, to get at semaphores
|
||||||
|
// Definitions are in /usr/include/mach on a Mac.
|
||||||
|
|
||||||
|
static void
|
||||||
|
macherror(kern_return_t r, int8 *fn)
|
||||||
{
|
{
|
||||||
|
prints("mach error ");
|
||||||
|
prints(fn);
|
||||||
|
prints(": ");
|
||||||
|
sys·printint(r);
|
||||||
|
prints("\n");
|
||||||
|
throw("mach error");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DebugMach = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int32 mach_msg_option_t;
|
||||||
|
typedef uint32 mach_msg_bits_t;
|
||||||
|
typedef uint32 mach_msg_id_t;
|
||||||
|
typedef uint32 mach_msg_size_t;
|
||||||
|
typedef uint32 mach_msg_timeout_t;
|
||||||
|
typedef uint32 mach_port_name_t;
|
||||||
|
typedef uint64 mach_vm_address_t;
|
||||||
|
|
||||||
|
typedef struct mach_msg_header_t mach_msg_header_t;
|
||||||
|
typedef struct mach_msg_body_t mach_msg_body_t;
|
||||||
|
typedef struct mach_msg_port_descriptor_t mach_msg_port_descriptor_t;
|
||||||
|
typedef struct NDR_record_t NDR_record_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MACH_MSG_TYPE_MOVE_RECEIVE = 16,
|
||||||
|
MACH_MSG_TYPE_MOVE_SEND = 17,
|
||||||
|
MACH_MSG_TYPE_MOVE_SEND_ONCE = 18,
|
||||||
|
MACH_MSG_TYPE_COPY_SEND = 19,
|
||||||
|
MACH_MSG_TYPE_MAKE_SEND = 20,
|
||||||
|
MACH_MSG_TYPE_MAKE_SEND_ONCE = 21,
|
||||||
|
MACH_MSG_TYPE_COPY_RECEIVE = 22,
|
||||||
|
|
||||||
|
MACH_MSG_PORT_DESCRIPTOR = 0,
|
||||||
|
MACH_MSG_OOL_DESCRIPTOR = 1,
|
||||||
|
MACH_MSG_OOL_PORTS_DESCRIPTOR = 2,
|
||||||
|
MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 3,
|
||||||
|
|
||||||
|
MACH_MSGH_BITS_COMPLEX = 0x80000000,
|
||||||
|
|
||||||
|
MACH_SEND_MSG = 1,
|
||||||
|
MACH_RCV_MSG = 2,
|
||||||
|
MACH_RCV_LARGE = 4,
|
||||||
|
|
||||||
|
MACH_SEND_TIMEOUT = 0x10,
|
||||||
|
MACH_SEND_INTERRUPT = 0x40,
|
||||||
|
MACH_SEND_CANCEL = 0x80,
|
||||||
|
MACH_SEND_ALWAYS = 0x10000,
|
||||||
|
MACH_SEND_TRAILER = 0x20000,
|
||||||
|
MACH_RCV_TIMEOUT = 0x100,
|
||||||
|
MACH_RCV_NOTIFY = 0x200,
|
||||||
|
MACH_RCV_INTERRUPT = 0x400,
|
||||||
|
MACH_RCV_OVERWRITE = 0x1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
mach_port_t mach_task_self(void);
|
||||||
|
mach_port_t mach_thread_self(void);
|
||||||
|
|
||||||
|
#pragma pack on
|
||||||
|
struct mach_msg_header_t
|
||||||
|
{
|
||||||
|
mach_msg_bits_t bits;
|
||||||
|
mach_msg_size_t size;
|
||||||
|
mach_port_t remote_port;
|
||||||
|
mach_port_t local_port;
|
||||||
|
mach_msg_size_t reserved;
|
||||||
|
mach_msg_id_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mach_msg_body_t
|
||||||
|
{
|
||||||
|
uint32 descriptor_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mach_msg_port_descriptor_t
|
||||||
|
{
|
||||||
|
mach_port_t name;
|
||||||
|
uint32 pad1;
|
||||||
|
uint16 pad2;
|
||||||
|
uint8 disposition;
|
||||||
|
uint8 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NDR_PROTOCOL_2_0 = 0,
|
||||||
|
NDR_INT_BIG_ENDIAN = 0,
|
||||||
|
NDR_INT_LITTLE_ENDIAN = 1,
|
||||||
|
NDR_FLOAT_IEEE = 0,
|
||||||
|
NDR_CHAR_ASCII = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NDR_record_t
|
||||||
|
{
|
||||||
|
uint8 mig_vers;
|
||||||
|
uint8 if_vers;
|
||||||
|
uint8 reserved1;
|
||||||
|
uint8 mig_encoding;
|
||||||
|
uint8 int_rep;
|
||||||
|
uint8 char_rep;
|
||||||
|
uint8 float_rep;
|
||||||
|
uint8 reserved2;
|
||||||
|
};
|
||||||
|
#pragma pack off
|
||||||
|
|
||||||
|
static NDR_record_t zerondr;
|
||||||
|
|
||||||
|
#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
|
||||||
|
|
||||||
|
// Mach system calls (in sys_amd64_darwin.s)
|
||||||
|
kern_return_t mach_msg_trap(mach_msg_header_t*,
|
||||||
|
mach_msg_option_t, mach_msg_size_t, mach_msg_size_t,
|
||||||
|
mach_port_name_t, mach_msg_timeout_t, mach_port_name_t);
|
||||||
|
mach_port_t mach_reply_port(void);
|
||||||
|
mach_port_t mach_task_self(void);
|
||||||
|
mach_port_t mach_thread_self(void);
|
||||||
|
|
||||||
|
static kern_return_t
|
||||||
|
mach_msg(mach_msg_header_t *h,
|
||||||
|
mach_msg_option_t op,
|
||||||
|
mach_msg_size_t send_size,
|
||||||
|
mach_msg_size_t rcv_size,
|
||||||
|
mach_port_name_t rcv_name,
|
||||||
|
mach_msg_timeout_t timeout,
|
||||||
|
mach_port_name_t notify)
|
||||||
|
{
|
||||||
|
// TODO: Loop on interrupt.
|
||||||
|
return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Mach RPC (MIG)
|
||||||
|
// I'm not using the Mach names anymore. They're too long.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MinMachMsg = 48,
|
||||||
|
Reply = 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack on
|
||||||
|
typedef struct CodeMsg CodeMsg;
|
||||||
|
struct CodeMsg
|
||||||
|
{
|
||||||
|
mach_msg_header_t h;
|
||||||
|
NDR_record_t NDR;
|
||||||
|
kern_return_t code;
|
||||||
|
};
|
||||||
|
#pragma pack off
|
||||||
|
|
||||||
|
static kern_return_t
|
||||||
|
machcall(mach_msg_header_t *h, int32 maxsize, int32 rxsize)
|
||||||
|
{
|
||||||
|
uint32 *p;
|
||||||
|
int32 i, ret, id;
|
||||||
|
mach_port_t port;
|
||||||
|
CodeMsg *c;
|
||||||
|
|
||||||
|
if((port = m->machport) == 0){
|
||||||
|
port = mach_reply_port();
|
||||||
|
m->machport = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
|
||||||
|
h->local_port = port;
|
||||||
|
h->reserved = 0;
|
||||||
|
id = h->id;
|
||||||
|
|
||||||
|
if(DebugMach){
|
||||||
|
p = (uint32*)h;
|
||||||
|
prints("send:\t");
|
||||||
|
for(i=0; i<h->size/sizeof(p[0]); i++){
|
||||||
|
prints(" ");
|
||||||
|
sys·printpointer((void*)p[i]);
|
||||||
|
if(i%8 == 7)
|
||||||
|
prints("\n\t");
|
||||||
|
}
|
||||||
|
if(i%8)
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
|
||||||
|
h->size, maxsize, port, 0, 0);
|
||||||
|
if(ret != 0){
|
||||||
|
if(DebugMach){
|
||||||
|
prints("mach_msg error ");
|
||||||
|
sys·printint(ret);
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(DebugMach){
|
||||||
|
p = (uint32*)h;
|
||||||
|
prints("recv:\t");
|
||||||
|
for(i=0; i<h->size/sizeof(p[0]); i++){
|
||||||
|
prints(" ");
|
||||||
|
sys·printpointer((void*)p[i]);
|
||||||
|
if(i%8 == 7)
|
||||||
|
prints("\n\t");
|
||||||
|
}
|
||||||
|
if(i%8)
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h->id != id+Reply){
|
||||||
|
if(DebugMach){
|
||||||
|
prints("mach_msg reply id mismatch ");
|
||||||
|
sys·printint(h->id);
|
||||||
|
prints(" != ");
|
||||||
|
sys·printint(id+Reply);
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
return -303; // MIG_REPLY_MISMATCH
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a response giving the return value.
|
||||||
|
// Any call can send this back with an error,
|
||||||
|
// and some calls only have return values so they
|
||||||
|
// send it back on success too. I don't quite see how
|
||||||
|
// you know it's one of these and not the full response
|
||||||
|
// format, so just look if the message is right.
|
||||||
|
c = (CodeMsg*)h;
|
||||||
|
if(h->size == sizeof(CodeMsg)
|
||||||
|
&& !(h->bits & MACH_MSGH_BITS_COMPLEX)){
|
||||||
|
if(DebugMach){
|
||||||
|
prints("mig result ");
|
||||||
|
sys·printint(c->code);
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
return c->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h->size != rxsize){
|
||||||
|
if(DebugMach){
|
||||||
|
prints("mach_msg reply size mismatch ");
|
||||||
|
sys·printint(h->size);
|
||||||
|
prints(" != ");
|
||||||
|
sys·printint(rxsize);
|
||||||
|
prints("\n");
|
||||||
|
}
|
||||||
|
return -307; // MIG_ARRAY_TOO_LARGE
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Semaphores!
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Tsemcreate = 3418,
|
||||||
|
Rsemcreate = Tsemcreate + Reply,
|
||||||
|
|
||||||
|
Tsemdestroy = 3419,
|
||||||
|
Rsemdestroy = Tsemdestroy + Reply,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TsemcreateMsg TsemcreateMsg;
|
||||||
|
typedef struct RsemcreateMsg RsemcreateMsg;
|
||||||
|
typedef struct TsemdestroyMsg TsemdestroyMsg;
|
||||||
|
// RsemdestroyMsg = CodeMsg
|
||||||
|
|
||||||
|
#pragma pack on
|
||||||
|
struct TsemcreateMsg
|
||||||
|
{
|
||||||
|
mach_msg_header_t h;
|
||||||
|
NDR_record_t ndr;
|
||||||
|
int32 policy;
|
||||||
|
int32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RsemcreateMsg
|
||||||
|
{
|
||||||
|
mach_msg_header_t h;
|
||||||
|
mach_msg_body_t body;
|
||||||
|
mach_msg_port_descriptor_t semaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TsemdestroyMsg
|
||||||
|
{
|
||||||
|
mach_msg_header_t h;
|
||||||
|
mach_msg_body_t body;
|
||||||
|
mach_msg_port_descriptor_t semaphore;
|
||||||
|
};
|
||||||
|
#pragma pack off
|
||||||
|
|
||||||
|
mach_port_t
|
||||||
|
semcreate(void)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
TsemcreateMsg tx;
|
||||||
|
RsemcreateMsg rx;
|
||||||
|
uint8 pad[MinMachMsg];
|
||||||
|
} m;
|
||||||
|
kern_return_t r;
|
||||||
|
|
||||||
|
m.tx.h.bits = 0;
|
||||||
|
m.tx.h.size = sizeof(m.tx);
|
||||||
|
m.tx.h.remote_port = mach_task_self();
|
||||||
|
m.tx.h.id = Tsemcreate;
|
||||||
|
m.tx.ndr = zerondr;
|
||||||
|
|
||||||
|
m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
|
||||||
|
m.tx.value = 0;
|
||||||
|
|
||||||
|
if((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0)
|
||||||
|
macherror(r, "semaphore_create");
|
||||||
|
if(m.rx.body.descriptor_count != 1)
|
||||||
|
unimplemented("semcreate desc count");
|
||||||
|
return m.rx.semaphore.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
semdestroy(mach_port_t sem)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
TsemdestroyMsg tx;
|
||||||
|
uint8 pad[MinMachMsg];
|
||||||
|
} m;
|
||||||
|
kern_return_t r;
|
||||||
|
|
||||||
|
m.tx.h.bits = MACH_MSGH_BITS_COMPLEX;
|
||||||
|
m.tx.h.size = sizeof(m.tx);
|
||||||
|
m.tx.h.remote_port = mach_task_self();
|
||||||
|
m.tx.h.id = Tsemdestroy;
|
||||||
|
m.tx.body.descriptor_count = 1;
|
||||||
|
m.tx.semaphore.name = sem;
|
||||||
|
m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
|
||||||
|
m.tx.semaphore.type = 0;
|
||||||
|
|
||||||
|
if((r = machcall(&m.tx.h, sizeof m, 0)) != 0)
|
||||||
|
macherror(r, "semaphore_destroy");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The other calls have simple system call traps
|
||||||
|
// in sys_amd64_darwin.s
|
||||||
|
kern_return_t mach_semaphore_wait(uint32 sema);
|
||||||
|
kern_return_t mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
|
||||||
|
kern_return_t mach_semaphore_signal(uint32 sema);
|
||||||
|
kern_return_t mach_semaphore_signal_all(uint32 sema);
|
||||||
|
|
||||||
|
void
|
||||||
|
semacquire(mach_port_t sem)
|
||||||
|
{
|
||||||
|
kern_return_t r;
|
||||||
|
|
||||||
|
if((r = mach_semaphore_wait(sem)) != 0)
|
||||||
|
macherror(r, "semaphore_wait");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
semrelease(mach_port_t sem)
|
||||||
|
{
|
||||||
|
kern_return_t r;
|
||||||
|
|
||||||
|
if((r = mach_semaphore_signal(sem)) != 0)
|
||||||
|
macherror(r, "semaphore_signal");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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*);
|
|||||||
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 @@
|
|||||||
|
|
||||||
//
|
//
|
||||||
// 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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user