]> Cypherpunks repositories - gostls13.git/commitdiff
runtime, runtime/cgo: track memory allocated by non-Go code
authorIan Lance Taylor <iant@golang.org>
Sat, 10 Nov 2012 19:19:06 +0000 (11:19 -0800)
committerIan Lance Taylor <iant@golang.org>
Sat, 10 Nov 2012 19:19:06 +0000 (11:19 -0800)
Otherwise a poorly timed GC can collect the memory before it
is returned to the Go program.

R=golang-dev, dave, dvyukov, minux.ma
CC=golang-dev
https://golang.org/cl/6819119

src/pkg/runtime/cgo/callbacks.c
src/pkg/runtime/cgocall.c
src/pkg/runtime/runtime.h

index f36fb3fd7e31f7af4947a7d768cbad0c155a5bb8..cefd67de87dad808274c8958d988dd58ff27ebea 100644 (file)
 static void
 _cgo_allocate_internal(uintptr len, byte *ret)
 {
+       CgoMal *c;
+
        ret = runtime·mal(len);
+       c = runtime·mal(sizeof(*c));
+       c->next = m->cgomal;
+       c->alloc = ret;
+       m->cgomal = c;
        FLUSH(&ret);
 }
 
index b96c286f109e6f16d7be1193aa99e8ac0ddf2e41..7a20379a9d29a908fb54ddd2d89ebefc93129908 100644 (file)
@@ -135,6 +135,8 @@ runtime·cgocall(void (*fn)(void*), void *arg)
                g->defer = &d;
        }
 
+       m->ncgo++;
+
        /*
         * Announce we are entering a system call
         * so that the scheduler knows to create another
@@ -150,6 +152,14 @@ runtime·cgocall(void (*fn)(void*), void *arg)
        runtime·asmcgocall(fn, arg);
        runtime·exitsyscall();
 
+       m->ncgo--;
+       if(m->ncgo == 0) {
+               // We are going back to Go and are not in a recursive
+               // call.  Let the GC collect any memory allocated via
+               // _cgo_allocate that is no longer referenced.
+               m->cgomal = nil;
+       }
+
        if(d.nofree) {
                if(g->defer != &d || d.fn != (byte*)unlockm)
                        runtime·throw("runtime: bad defer entry in cgocallback");
index 51a5aeca91fa780e039d21748cadd97c77d4cd62..c6b30ac73c2637f4689dfd37418fc416905972c3 100644 (file)
@@ -81,6 +81,7 @@ typedef struct        GCStats         GCStats;
 typedef struct LFNode          LFNode;
 typedef struct ParFor          ParFor;
 typedef struct ParForThread    ParForThread;
+typedef struct CgoMal          CgoMal;
 
 /*
  * Per-CPU declaration.
@@ -249,7 +250,9 @@ struct      M
        int32   profilehz;
        int32   helpgc;
        uint32  fastrand;
-       uint64  ncgocall;
+       uint64  ncgocall;       // number of cgo calls in total
+       int32   ncgo;           // number of cgo calls currently in progress
+       CgoMal* cgomal;
        Note    havenextg;
        G*      nextg;
        M*      alllink;        // on allm
@@ -414,6 +417,14 @@ struct ParFor
        uint64 nsleep;
 };
 
+// Track memory allocated by code not written in Go during a cgo call,
+// so that the garbage collector can see them.
+struct CgoMal
+{
+       CgoMal  *next;
+       byte    *alloc;
+};
+
 /*
  * defined macros
  *    you need super-gopher-guru privilege