diff --git a/cmd/xgo/version.go b/cmd/xgo/version.go index e1ec5d15..bffe0ac2 100644 --- a/cmd/xgo/version.go +++ b/cmd/xgo/version.go @@ -3,8 +3,8 @@ package main import "fmt" const VERSION = "1.0.1" -const REVISION = "6eca2e984823b4e5d9621e9bd82e4d8db2b18895+1" -const NUMBER = 81 +const REVISION = "cbdc296ff629fdba79e44589f2ce7fa1891c85f1+1" +const NUMBER = 82 func getRevision() string { return fmt.Sprintf("%s %s BUILD_%d", VERSION, REVISION, NUMBER) diff --git a/runtime/core/version.go b/runtime/core/version.go index dc56bc18..ef8b19ca 100644 --- a/runtime/core/version.go +++ b/runtime/core/version.go @@ -1,5 +1,5 @@ package core const VERSION = "1.0.1" -const REVISION = "6eca2e984823b4e5d9621e9bd82e4d8db2b18895+1" -const NUMBER = 81 +const REVISION = "cbdc296ff629fdba79e44589f2ce7fa1891c85f1+1" +const NUMBER = 82 diff --git a/runtime/trace/trace.go b/runtime/trace/trace.go index 34debd58..6d531368 100644 --- a/runtime/trace/trace.go +++ b/runtime/trace/trace.go @@ -5,11 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "strconv" "sync" + "testing" "time" "unsafe" @@ -19,13 +19,43 @@ import ( const __XGO_SKIP_TRAP = true +// hold goroutine stacks, keyed by goroutine ptr +var stackMap sync.Map // uintptr(goroutine) -> *Root +var testInfoMaping sync.Map // uintptr(goroutine) -> *testInfo + +type testInfo struct { + name string +} + +func init() { + __xgo_link_on_test_start(func(t *testing.T, fn func(t *testing.T)) { + name := t.Name() + if name == "" { + return + } + key := uintptr(__xgo_link_getcurg()) + testInfoMaping.LoadOrStore(key, &testInfo{ + name: name, + }) + }) + __xgo_link_on_goexit(func() { + key := uintptr(__xgo_link_getcurg()) + testInfoMaping.Delete(key) + }) +} + +// link by compiler +func __xgo_link_on_test_start(fn func(t *testing.T, fn func(t *testing.T))) { +} + // link by compiler func __xgo_link_getcurg() unsafe.Pointer { panic(errors.New("failed to link __xgo_link_getcurg")) } -// hold goroutine stacks, keyed by goroutine ptr -var stackMap sync.Map // uintptr(goroutine) -> *Root +func __xgo_link_on_goexit(fn func()) { + panic("failed to link __xgo_link_on_goexit") +} type Root struct { // current executed function @@ -115,41 +145,72 @@ func SetMarshalStack(fn func(stack *Stack) ([]byte, error)) { marshalStack = fn } -// this should also be marked as trap.Skip() -func emitTrace(stack *Stack) error { - // write to file - var trace []byte - var err error +func fmtStack(stack *Stack) (data []byte, err error) { + defer func() { + if e := recover(); e != nil { + if pe, ok := e.(error); ok { + err = pe + } else { + err = fmt.Errorf("panic: %v", e) + } + return + } + }() if marshalStack != nil { - trace, err = marshalStack(stack) - } else { - trace, err = json.Marshal(stack) - } - if err != nil { - return err + return marshalStack(stack) } + return json.Marshal(stack) +} + +// this should also be marked as trap.Skip() +// TODO: may add callback for this +func emitTrace(stack *Stack) error { + var testName string - traceIDNum := int64(1) - ghex := fmt.Sprintf("g_%x", __xgo_link_getcurg()) - traceID := "t_" + strconv.FormatInt(traceIDNum, 10) + key := uintptr(__xgo_link_getcurg()) + tinfo, ok := testInfoMaping.Load(key) + if ok { + testName = tinfo.(*testInfo).name + } xgoTraceOutput := getTraceOutput() - if xgoTraceOutput == "" { - xgoTraceOutput = time.Now().Format("trace_20060102_150405") + useStdout := xgoTraceOutput == "stdout" + subName := testName + if testName == "" { + traceIDNum := int64(1) + ghex := fmt.Sprintf("g_%x", __xgo_link_getcurg()) + traceID := "t_" + strconv.FormatInt(traceIDNum, 10) + if xgoTraceOutput == "" { + traceDir := time.Now().Format("trace_20060102_150405") + subName = filepath.Join(traceDir, ghex, traceID) + } else if useStdout { + subName = fmt.Sprintf("%s/%s", ghex, traceID) + } else { + subName = filepath.Join(xgoTraceOutput, ghex, traceID) + } + } + + if useStdout { + fmt.Printf("%s: ", subName) } - if xgoTraceOutput == "stdout" { - // TODO: may add callback for this - fmt.Printf("%s/%s: ", ghex, traceID) - fmt.Println(string(trace)) + var traceOut []byte + trace, stackErr := fmtStack(stack) + if stackErr != nil { + traceOut = []byte("error:" + stackErr.Error()) + } else { + traceOut = trace + } + + if useStdout { + fmt.Print(traceOut) return nil } - dir := filepath.Join(xgoTraceOutput, ghex) - err = os.MkdirAll(dir, 0755) + subFile := subName + ".json" + subDir := filepath.Dir(subFile) + err := os.MkdirAll(subDir, 0755) if err != nil { return err } - file := filepath.Join(dir, traceID+".json") - - return ioutil.WriteFile(file, trace, 0755) + return os.WriteFile(subFile, traceOut, 0755) }