Patchwork libgo patch committed: Make runtime.Stack work

login
register
mail settings
Submitter Ian Taylor
Date May 24, 2012, 9:07 p.m.
Message ID <mcrpq9tnv8r.fsf@dhcp-172-18-216-180.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/161217/
State New
Headers show

Comments

Ian Taylor - May 24, 2012, 9:07 p.m.
This patch makes the function runtime.Stack actually work, rather than
simply hang the program.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline and 4.7 branch.

Ian

Patch

Index: libgo/runtime/mprof.goc
===================================================================
--- libgo/runtime/mprof.goc	(revision 187623)
+++ libgo/runtime/mprof.goc	(working copy)
@@ -343,6 +343,7 @@  func ThreadCreateProfile(p Slice) (n int
 
 func Stack(b Slice, all bool) (n int32) {
 	byte *pc, *sp;
+	bool enablegc;
 	
 	sp = runtime_getcallersp(&b);
 	pc = runtime_getcallerpc(&b);
@@ -351,6 +352,8 @@  func Stack(b Slice, all bool) (n int32) 
 		runtime_semacquire(&runtime_worldsema);
 		runtime_m()->gcing = 1;
 		runtime_stoptheworld();
+		enablegc = mstats.enablegc;
+		mstats.enablegc = false;
 	}
 
 	if(b.__count == 0)
@@ -373,33 +376,31 @@  func Stack(b Slice, all bool) (n int32) 
 	
 	if(all) {
 		runtime_m()->gcing = 0;
+		mstats.enablegc = enablegc;
 		runtime_semrelease(&runtime_worldsema);
 		runtime_starttheworld(false);
 	}
 }
 
 static void
-saveg(byte *pc, byte *sp, G *g, TRecord *r)
+saveg(G *g, TRecord *r)
 {
 	int32 n;
 
-	USED(pc);
-	USED(sp);
-	USED(g);
-	// n = runtime_gentraceback(pc, sp, 0, g, 0, r->stk, nelem(r->stk));
-	n = 0;
+	if(g == runtime_g())
+		n = runtime_callers(0, r->stk, nelem(r->stk));
+	else {
+		// FIXME: Not implemented.
+		n = 0;
+	}
 	if((size_t)n < nelem(r->stk))
 		r->stk[n] = 0;
 }
 
 func GoroutineProfile(b Slice) (n int32, ok bool) {
-	byte *pc, *sp;
 	TRecord *r;
 	G *gp;
 	
-	sp = runtime_getcallersp(&b);
-	pc = runtime_getcallerpc(&b);
-	
 	ok = false;
 	n = runtime_gcount();
 	if(n <= b.__count) {
@@ -412,12 +413,11 @@  func GoroutineProfile(b Slice) (n int32,
 			G* g = runtime_g();
 			ok = true;
 			r = (TRecord*)b.__values;
-			saveg(pc, sp, g, r++);
+			saveg(g, r++);
 			for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
 				if(gp == g || gp->status == Gdead)
 					continue;
-				//saveg(gp->sched.pc, gp->sched.sp, gp, r++);
-				r++;
+				saveg(gp, r++);
 			}
 		}
 	
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 187848)
+++ libgo/runtime/runtime.h	(working copy)
@@ -71,6 +71,8 @@  typedef	struct	__go_panic_stack	Panic;
 typedef struct	__go_func_type		FuncType;
 typedef struct	__go_map_type		MapType;
 
+typedef struct  Traceback	Traceback;
+
 /*
  * per-cpu declaration.
  */
@@ -151,7 +153,7 @@  struct	G
 	// uintptr	sigpc;
 	uintptr	gopc;	// pc of go statement that created this goroutine
 
-	G*	dotraceback;
+	Traceback* traceback;
 
 	ucontext_t	context;
 	void*		stack_context[10];
@@ -299,6 +301,7 @@  void	runtime_goroutineheader(G*);
 void	runtime_goroutinetrailer(G*);
 void	runtime_traceback();
 void	runtime_tracebackothers(G*);
+void	runtime_printtrace(uintptr*, int32);
 String	runtime_gostringnocopy(const byte*);
 void*	runtime_mstart(void*);
 G*	runtime_malg(int32, byte**, size_t*);
Index: libgo/runtime/proc.c
===================================================================
--- libgo/runtime/proc.c	(revision 187777)
+++ libgo/runtime/proc.c	(working copy)
@@ -348,7 +348,7 @@  runtime_mcall(void (*pfn)(G*))
 		mp = runtime_m();
 		gp = runtime_g();
 
-		if(gp->dotraceback != nil)
+		if(gp->traceback != nil)
 			gtraceback(gp);
 	}
 	if (gp == nil || !gp->fromgogo) {
@@ -542,11 +542,20 @@  runtime_goroutinetrailer(G *g)
 	}
 }
 
+struct Traceback
+{
+	G* gp;
+	uintptr pcbuf[100];
+	int32 c;
+};
+
 void
 runtime_tracebackothers(G * volatile me)
 {
 	G * volatile g;
+	Traceback traceback;
 
+	traceback.gp = me;
 	for(g = runtime_allg; g != nil; g = g->alllink) {
 		if(g == me || g->status == Gdead)
 			continue;
@@ -567,16 +576,19 @@  runtime_tracebackothers(G * volatile me)
 			continue;
 		}
 
-		g->dotraceback = me;
+		g->traceback = &traceback;
 
 #ifdef USING_SPLIT_STACK
 		__splitstack_getcontext(&me->stack_context[0]);
 #endif
 		getcontext(&me->context);
 
-		if(g->dotraceback) {
+		if(g->traceback != nil) {
 			runtime_gogo(g);
 		}
+
+		runtime_printtrace(traceback.pcbuf, traceback.c);
+		runtime_goroutinetrailer(g);
 	}
 }
 
@@ -586,13 +598,13 @@  runtime_tracebackothers(G * volatile me)
 static void
 gtraceback(G* gp)
 {
-	G* ret;
+	Traceback* traceback;
 
-	runtime_traceback(nil);
-	runtime_goroutinetrailer(gp);
-	ret = gp->dotraceback;
-	gp->dotraceback = nil;
-	runtime_gogo(ret);
+	traceback = gp->traceback;
+	gp->traceback = nil;
+	traceback->c = runtime_callers(1, traceback->pcbuf,
+		sizeof traceback->pcbuf / sizeof traceback->pcbuf[0]);
+	runtime_gogo(traceback->gp);
 }
 
 // Mark this g as m's idle goroutine.
Index: libgo/runtime/go-traceback.c
===================================================================
--- libgo/runtime/go-traceback.c	(revision 187623)
+++ libgo/runtime/go-traceback.c	(working copy)
@@ -6,57 +6,37 @@ 
 
 #include "config.h"
 
-#include "unwind.h"
-
 #include "runtime.h"
 #include "go-string.h"
 
-static _Unwind_Reason_Code
-traceback (struct _Unwind_Context *context, void *varg)
-{
-  int *parg = (int *) varg;
-  uintptr pc;
-  int ip_before_insn = 0;
-  struct __go_string fn;
-  struct __go_string file;
-  int line;
-
-#ifdef HAVE_GETIPINFO
-  pc = _Unwind_GetIPInfo (context, &ip_before_insn);
-#else
-  pc = _Unwind_GetIP (context);
-#endif
-
-  if (*parg > 100)
-    return _URC_END_OF_STACK;
-  ++*parg;
-
-  /* FIXME: If PC is in the __morestack routine, we should ignore
-     it.  */
-
-  /* Back up to the call instruction.  */
-  if (!ip_before_insn)
-    --pc;
-
-  if (!__go_file_line (pc, &fn, &file, &line))
-    return _URC_END_OF_STACK;
+/* Print a stack trace for the current goroutine.  */
 
-  if (runtime_showframe (fn.__data))
-    {
-      runtime_printf ("%s\n", fn.__data);
-      runtime_printf ("\t%s:%d\n", file.__data, line);
-    }
+void
+runtime_traceback ()
+{
+  uintptr pcbuf[100];
+  int32 c;
 
-  return _URC_NO_REASON;
+  c = runtime_callers (1, pcbuf, sizeof pcbuf / sizeof pcbuf[0]);
+  runtime_printtrace (pcbuf, c);
 }
 
-/* Print a stack trace for the current goroutine.  */
-
 void
-runtime_traceback ()
+runtime_printtrace (uintptr *pcbuf, int32 c)
 {
-  int c;
+  int32 i;
 
-  c = 0;
-  _Unwind_Backtrace (traceback, &c);
+  for (i = 0; i < c; ++i)
+    {
+      struct __go_string fn;
+      struct __go_string file;
+      int line;
+
+      if (__go_file_line (pcbuf[i], &fn, &file, &line)
+	  && runtime_showframe (fn.__data))
+	{
+	  runtime_printf ("%s\n", fn.__data);
+	  runtime_printf ("\t%s:%d\n", file.__data, line);
+	}
+    }
 }