mirror of
https://github.com/golang/go
synced 2024-11-18 15:44:41 -07:00
Library support for cgo export.
These functions are used to call from a C function back to a Go function. This only includes 386 support. R=rsc CC=golang-dev https://golang.org/cl/834045
This commit is contained in:
parent
2d0ff3f1a6
commit
2e20386fc7
@ -35,3 +35,27 @@ EXT(crosscall_386):
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
/*
|
||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
||||
*
|
||||
* Save registers and call fn with two arguments.
|
||||
*/
|
||||
.globl EXT(crosscall2)
|
||||
EXT(crosscall2):
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
pushl 16(%ebp)
|
||||
pushl 12(%ebp)
|
||||
mov 8(%ebp), %eax
|
||||
call *%eax
|
||||
addl $8,%esp
|
||||
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
@ -351,16 +351,53 @@ TEXT runcgo(SB),7,$16
|
||||
// Now on a scheduling stack (a pthread-created stack).
|
||||
SUBL $16, SP
|
||||
ANDL $~15, SP // alignment for gcc ABI
|
||||
MOVL g(DI), BP
|
||||
MOVL BP, 8(SP)
|
||||
MOVL SI, g(DI)
|
||||
MOVL CX, 4(SP)
|
||||
MOVL BX, 0(SP)
|
||||
CALL AX
|
||||
|
||||
// Back; switch to original stack, re-establish
|
||||
// Back; switch to original g and stack, re-establish
|
||||
// "DF is clear" invariant.
|
||||
CLD
|
||||
get_tls(DI)
|
||||
MOVL 8(SP), SI
|
||||
MOVL SI, g(DI)
|
||||
MOVL 4(SP), SP
|
||||
RET
|
||||
|
||||
// runcgocallback(G *g1, void* sp, void (*fn)(void))
|
||||
// Switch to g1 and sp, call fn, switch back. fn's arguments are on
|
||||
// the new stack.
|
||||
TEXT runcgocallback(SB),7,$32
|
||||
MOVL g1+0(FP), DX
|
||||
MOVL sp+4(FP), AX
|
||||
MOVL fn+8(FP), BX
|
||||
|
||||
// We are running on m's scheduler stack. Save current SP
|
||||
// into m->sched.sp so that a recursive call to runcgo doesn't
|
||||
// clobber our stack, and also so that we can restore
|
||||
// the SP when the call finishes. Reusing m->sched.sp
|
||||
// for this purpose depends on the fact that there is only
|
||||
// one possible gosave of m->sched.
|
||||
get_tls(CX)
|
||||
MOVL DX, g(CX)
|
||||
MOVL m(CX), CX
|
||||
MOVL SP, (m_sched+gobuf_sp)(CX)
|
||||
|
||||
// Set new SP, call fn
|
||||
MOVL AX, SP
|
||||
CALL BX
|
||||
|
||||
// Restore old g and SP, return
|
||||
get_tls(CX)
|
||||
MOVL m(CX), DX
|
||||
MOVL m_g0(DX), BX
|
||||
MOVL BX, g(CX)
|
||||
MOVL (m_sched+gobuf_sp)(DX), SP
|
||||
RET
|
||||
|
||||
// check that SP is in range [g->stackbase, g->stackguard)
|
||||
TEXT stackcheck(SB), 7, $0
|
||||
get_tls(CX)
|
||||
|
@ -13,11 +13,21 @@ void ·exitsyscall(void);
|
||||
void
|
||||
cgocall(void (*fn)(void*), void *arg)
|
||||
{
|
||||
G *oldlock;
|
||||
|
||||
if(initcgo == nil)
|
||||
throw("cgocall unavailable");
|
||||
|
||||
ncgocall++;
|
||||
|
||||
/*
|
||||
* Lock g to m to ensure we stay on the same stack if we do a
|
||||
* cgo callback.
|
||||
*/
|
||||
oldlock = m->lockedg;
|
||||
m->lockedg = g;
|
||||
g->lockedm = m;
|
||||
|
||||
/*
|
||||
* Announce we are entering a system call
|
||||
* so that the scheduler knows to create another
|
||||
@ -27,9 +37,49 @@ cgocall(void (*fn)(void*), void *arg)
|
||||
·entersyscall();
|
||||
runcgo(fn, arg);
|
||||
·exitsyscall();
|
||||
|
||||
m->lockedg = oldlock;
|
||||
if(oldlock == nil)
|
||||
g->lockedm = nil;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// When a C function calls back into Go, the wrapper function will
|
||||
// call this. This switches to a Go stack, copies the arguments
|
||||
// (arg/argsize) on to the stack, calls the function, copies the
|
||||
// arguments back where they came from, and finally returns to the old
|
||||
// stack.
|
||||
void
|
||||
cgocallback(void (*fn)(void), void *arg, int32 argsize)
|
||||
{
|
||||
Gobuf oldsched;
|
||||
G *g1;
|
||||
void *sp;
|
||||
|
||||
if(g != m->g0)
|
||||
throw("bad g in cgocallback");
|
||||
|
||||
oldsched = m->sched;
|
||||
|
||||
g1 = m->curg;
|
||||
|
||||
startcgocallback(g1);
|
||||
|
||||
sp = g1->sched.sp - argsize;
|
||||
if(sp < g1->stackguard)
|
||||
throw("g stack overflow in cgocallback");
|
||||
mcpy(sp, arg, argsize);
|
||||
|
||||
runcgocallback(g1, sp, fn);
|
||||
|
||||
mcpy(arg, sp, argsize);
|
||||
|
||||
endcgocallback(g1);
|
||||
|
||||
m->sched = oldsched;
|
||||
}
|
||||
|
||||
void
|
||||
·Cgocalls(int64 ret)
|
||||
{
|
||||
|
@ -7,5 +7,6 @@
|
||||
*/
|
||||
|
||||
void cgocall(void (*fn)(void*), void*);
|
||||
void cgocallback(void (*fn)(void), void*, int32);
|
||||
void *cmalloc(uintptr);
|
||||
void cfree(void*);
|
||||
|
@ -544,8 +544,8 @@ gosched(void)
|
||||
|
||||
// The goroutine g is about to enter a system call.
|
||||
// Record that it's not using the cpu anymore.
|
||||
// This is called only from the go syscall library, not
|
||||
// from the low-level system calls used by the runtime.
|
||||
// This is called only from the go syscall library and cgocall,
|
||||
// not from the low-level system calls used by the runtime.
|
||||
void
|
||||
·entersyscall(void)
|
||||
{
|
||||
@ -604,6 +604,28 @@ void
|
||||
gosched();
|
||||
}
|
||||
|
||||
// Start scheduling g1 again for a cgo callback.
|
||||
void
|
||||
startcgocallback(G* g1)
|
||||
{
|
||||
lock(&sched);
|
||||
g1->status = Grunning;
|
||||
sched.msyscall--;
|
||||
sched.mcpu++;
|
||||
unlock(&sched);
|
||||
}
|
||||
|
||||
// Stop scheduling g1 after a cgo callback.
|
||||
void
|
||||
endcgocallback(G* g1)
|
||||
{
|
||||
lock(&sched);
|
||||
g1->status = Gsyscall;
|
||||
sched.mcpu--;
|
||||
sched.msyscall++;
|
||||
unlock(&sched);
|
||||
}
|
||||
|
||||
/*
|
||||
* stack layout parameters.
|
||||
* known to linkers.
|
||||
|
@ -196,8 +196,6 @@ struct G
|
||||
bool ispanic;
|
||||
M* m; // for debuggers, but offset not hard-coded
|
||||
M* lockedm;
|
||||
void (*cgofn)(void*); // for cgo/ffi
|
||||
void *cgoarg;
|
||||
int32 sig;
|
||||
uintptr sigcode0;
|
||||
uintptr sigcode1;
|
||||
@ -432,8 +430,11 @@ void breakpoint(void);
|
||||
void gosched(void);
|
||||
void goexit(void);
|
||||
void runcgo(void (*fn)(void*), void*);
|
||||
void runcgocallback(G*, void*, void (*fn)());
|
||||
void ·entersyscall(void);
|
||||
void ·exitsyscall(void);
|
||||
void startcgocallback(G*);
|
||||
void endcgocallback(G*);
|
||||
G* newproc1(byte*, byte*, int32, int32);
|
||||
void siginit(void);
|
||||
bool sigsend(int32 sig);
|
||||
|
Loading…
Reference in New Issue
Block a user