Reviewers: golang-dev_googlegroups.com,
Message:
Hello golang-dev@googlegroups.com,
I'd like you to review this change to
https://go.googlecode.com/hg/
Description:
runtime, runtime/cgo: track memory allocated by non-Go code
Otherwise a poorly timed GC can collect the memory before it
is returned to the Go program.
Please review this at http://codereview.appspot.com/6819119/
Affected files:
M src/pkg/runtime/cgo/callbacks.c
M src/pkg/runtime/cgocall.c
M src/pkg/runtime/runtime.h
Index: src/pkg/runtime/cgo/callbacks.c
===================================================================
--- a/src/pkg/runtime/cgo/callbacks.c
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -33,7 +33,13 @@
static void
_cgo_allocate_internal(uintptr len, byte *ret)
{
+ CgoMal *c;
+
ret = runtime·mal(len);
+ c = runtime·mal(sizeof(*c));
+ c->next = g->cgomal;
+ c->alloc = ret;
+ g->cgomal = c;
FLUSH(&ret);
}
Index: src/pkg/runtime/cgocall.c
===================================================================
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -135,6 +135,8 @@
g->defer = &d;
}
+ g->ncgo++;
+
/*
* Announce we are entering a system call
* so that the scheduler knows to create another
@@ -150,6 +152,14 @@
runtime·asmcgocall(fn, arg);
runtime·exitsyscall();
+ g->ncgo--;
+ if(g->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.
+ g->cgomal = nil;
+ }
+
if(d.nofree) {
if(g->defer != &d || d.fn != (byte*)unlockm)
runtime·throw("runtime: bad defer entry in cgocallback");
Index: src/pkg/runtime/runtime.h
===================================================================
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -81,6 +81,7 @@
typedef struct LFNode LFNode;
typedef struct ParFor ParFor;
typedef struct ParForThread ParForThread;
+typedef struct CgoMal CgoMal;
/*
* Per-CPU declaration.
@@ -221,6 +222,8 @@
uintptr sigcode1;
uintptr sigpc;
uintptr gopc; // pc of go statement that created this goroutine
+ int32 ncgo; // number of cgo calls in progress
+ CgoMal* cgomal;
uintptr end[];
};
struct M
@@ -414,6 +417,14 @@
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