diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go index 9c02e547..905e2ebc 100644 --- a/go/ssa/interp/external.go +++ b/go/ssa/interp/external.go @@ -15,6 +15,7 @@ import ( "os" "runtime" "strings" + "sync/atomic" "syscall" "time" "unsafe" @@ -104,6 +105,7 @@ func init() { "runtime.Gosched": ext۰runtime۰Gosched, "runtime.init": ext۰runtime۰init, "runtime.NumCPU": ext۰runtime۰NumCPU, + "runtime.NumGoroutine": ext۰runtime۰NumGoroutine, "runtime.ReadMemStats": ext۰runtime۰ReadMemStats, "runtime.SetFinalizer": ext۰runtime۰SetFinalizer, "(*runtime.Func).Entry": ext۰runtime۰Func۰Entry, @@ -387,6 +389,10 @@ func ext۰runtime۰NumCPU(fr *frame, args []value) value { return runtime.NumCPU() } +func ext۰runtime۰NumGoroutine(fr *frame, args []value) value { + return int(atomic.LoadInt32(&fr.i.goroutines)) +} + func ext۰runtime۰ReadMemStats(fr *frame, args []value) value { // TODO(adonovan): populate args[0].(Struct) return nil diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go index b855645f..730d0f55 100644 --- a/go/ssa/interp/interp.go +++ b/go/ssa/interp/interp.go @@ -53,6 +53,7 @@ import ( "os" "reflect" "runtime" + "sync/atomic" "golang.org/x/tools/go/ssa" ) @@ -86,6 +87,7 @@ type interpreter struct { rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface. runtimeErrorString types.Type // the runtime.errorString type sizes types.Sizes // the effective type-sizing function + goroutines int32 // atomically updated } type deferred struct { @@ -269,7 +271,11 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation { case *ssa.Go: fn, args := prepareCall(fr, &instr.Call) - go call(fr.i, nil, instr.Pos(), fn, args) + atomic.AddInt32(&fr.i.goroutines, 1) + go func() { + call(fr.i, nil, instr.Pos(), fn, args) + atomic.AddInt32(&fr.i.goroutines, -1) + }() case *ssa.MakeChan: fr.env[instr] = make(chan value, asInt(fr.get(instr.Size))) @@ -660,10 +666,11 @@ func deleteBodies(pkg *ssa.Package, except ...string) { // func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) { i := &interpreter{ - prog: mainpkg.Prog, - globals: make(map[ssa.Value]*value), - mode: mode, - sizes: sizes, + prog: mainpkg.Prog, + globals: make(map[ssa.Value]*value), + mode: mode, + sizes: sizes, + goroutines: 1, } runtimePkg := i.prog.ImportedPackage("runtime") if runtimePkg == nil {