]> Cypherpunks repositories - gostls13.git/commitdiff
Library support for cgo export.
authorIan Lance Taylor <iant@golang.org>
Fri, 9 Apr 2010 20:30:35 +0000 (13:30 -0700)
committerIan Lance Taylor <iant@golang.org>
Fri, 9 Apr 2010 20:30:35 +0000 (13:30 -0700)
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

src/libcgo/386.S
src/pkg/runtime/386/asm.s
src/pkg/runtime/cgocall.c
src/pkg/runtime/cgocall.h
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h

index 278c5293ce977c8eef45a268823d96ea6f5e5950..cca79cdd516d55a430b807092056e2c73c30c9ec 100755 (executable)
@@ -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
index 0002a3e10477e6bd8bb985ec0938aa2014c937ab..614c026eafd786c21ffc195d2253882ab5841c37 100644 (file)
@@ -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)
index 2f1f66c7e4794d35774e6a232374602c3d3083f6..f673d1b6ecce535e1cf2d177d89a9c6fb87605d0 100644 (file)
@@ -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)
 {
index 816c426d78e6196cca2c5969b4365c558a9eb66a..9cdb409a30c3bc3badfaafc199b901a77323c701 100644 (file)
@@ -7,5 +7,6 @@
  */
 
 void cgocall(void (*fn)(void*), void*);
+void cgocallback(void (*fn)(void), void*, int32);
 void *cmalloc(uintptr);
 void cfree(void*);
index 1a1895dcb44640b4edb335920863d28fef87ee27..169f90b7330c1c5af1cc8129ce357b487b452d25 100644 (file)
@@ -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.
index f3297e7e05d2bcfb4389e838338fc18a63e7ea95..7063a9fc6da186559cce68207a8414ac72111787 100644 (file)
@@ -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);