proc: move AllGCache to a common struct

Add a new method "Common" to proc.Process that returns a pointer to a
struct that pkg/proc can use to store its things, independently of the
backend.

This is used here to replace the AllGCache typecasts, it will also be
used to store the return values of the stepout breakpoint and the state
for injected function calls.
This commit is contained in:
aarzilli
2018-05-10 21:25:59 +02:00
committed by Alessandro Arzilli
parent d04c60e0b9
commit f38a2816d1
6 changed files with 28 additions and 32 deletions

View File

@ -147,7 +147,7 @@ type Process struct {
breakpoints proc.BreakpointMap breakpoints proc.BreakpointMap
currentThread *Thread currentThread *Thread
selectedGoroutine *proc.G selectedGoroutine *proc.G
allGCache []*proc.G common proc.CommonProcess
} }
type Thread struct { type Thread struct {
@ -298,8 +298,8 @@ func (p *Process) Exited() bool {
return false return false
} }
func (p *Process) AllGCache() *[]*proc.G { func (p *Process) Common() *proc.CommonProcess {
return &p.allGCache return &p.common
} }
func (p *Process) Pid() int { func (p *Process) Pid() int {

View File

@ -121,7 +121,7 @@ type Process struct {
process *os.Process process *os.Process
waitChan chan *os.ProcessState waitChan chan *os.ProcessState
allGCache []*proc.G common proc.CommonProcess
} }
// Thread is a thread. // Thread is a thread.
@ -584,8 +584,8 @@ func (p *Process) CurrentThread() proc.Thread {
return p.currentThread return p.currentThread
} }
func (p *Process) AllGCache() *[]*proc.G { func (p *Process) Common() *proc.CommonProcess {
return &p.allGCache return &p.common
} }
func (p *Process) SelectedGoroutine() *proc.G { func (p *Process) SelectedGoroutine() *proc.G {
@ -615,7 +615,7 @@ func (p *Process) ContinueOnce() (proc.Thread, error) {
} }
} }
p.allGCache = nil p.common.ClearAllGCache()
for _, th := range p.threads { for _, th := range p.threads {
th.clearBreakpointState() th.clearBreakpointState()
} }
@ -710,7 +710,7 @@ func (p *Process) StepInstruction() error {
} }
thread = p.selectedGoroutine.Thread.(*Thread) thread = p.selectedGoroutine.Thread.(*Thread)
} }
p.allGCache = nil p.common.ClearAllGCache()
if p.exited { if p.exited {
return &proc.ProcessExitedError{Pid: p.conn.pid} return &proc.ProcessExitedError{Pid: p.conn.pid}
} }
@ -819,7 +819,7 @@ func (p *Process) Restart(pos string) error {
p.exited = false p.exited = false
p.allGCache = nil p.common.ClearAllGCache()
for _, th := range p.threads { for _, th := range p.threads {
th.clearBreakpointState() th.clearBreakpointState()
} }

View File

@ -62,6 +62,8 @@ type Info interface {
ResumeNotify(chan<- struct{}) ResumeNotify(chan<- struct{})
Exited() bool Exited() bool
BinInfo() *BinaryInfo BinInfo() *BinaryInfo
// Common returns a struct with fields common to all backends
Common() *CommonProcess
ThreadInfo ThreadInfo
GoroutineInfo GoroutineInfo
@ -100,3 +102,11 @@ type BreakpointManipulation interface {
ClearBreakpoint(addr uint64) (*Breakpoint, error) ClearBreakpoint(addr uint64) (*Breakpoint, error)
ClearInternalBreakpoints() error ClearInternalBreakpoints() error
} }
type CommonProcess struct {
allGCache []*G
}
func (p *CommonProcess) ClearAllGCache() {
p.allGCache = nil
}

View File

@ -29,7 +29,7 @@ type Process struct {
// Normally selectedGoroutine is currentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread // Normally selectedGoroutine is currentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread
selectedGoroutine *proc.G selectedGoroutine *proc.G
allGCache []*proc.G common proc.CommonProcess
os *OSProcessDetails os *OSProcessDetails
firstStart bool firstStart bool
stopMu sync.Mutex stopMu sync.Mutex
@ -230,7 +230,7 @@ func (dbp *Process) ContinueOnce() (proc.Thread, error) {
return nil, err return nil, err
} }
dbp.allGCache = nil dbp.common.ClearAllGCache()
for _, th := range dbp.threads { for _, th := range dbp.threads {
th.CurrentBreakpoint.Clear() th.CurrentBreakpoint.Clear()
} }
@ -266,7 +266,7 @@ func (dbp *Process) StepInstruction() (err error) {
} }
thread = dbp.selectedGoroutine.Thread.(*Thread) thread = dbp.selectedGoroutine.Thread.(*Thread)
} }
dbp.allGCache = nil dbp.common.ClearAllGCache()
if dbp.exited { if dbp.exited {
return &proc.ProcessExitedError{Pid: dbp.Pid()} return &proc.ProcessExitedError{Pid: dbp.Pid()}
} }
@ -397,6 +397,6 @@ func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error {
return err return err
} }
func (dbp *Process) AllGCache() *[]*proc.G { func (dbp *Process) Common() *proc.CommonProcess {
return &dbp.allGCache return &dbp.common
} }

View File

@ -373,22 +373,14 @@ func StepOut(dbp Process) error {
return Continue(dbp) return Continue(dbp)
} }
// If the argument of GoroutinesInfo implements AllGCache GoroutinesInfo
// will use the pointer returned by AllGCache as a cache.
type AllGCache interface {
AllGCache() *[]*G
}
// GoroutinesInfo returns an array of G structures representing the information // GoroutinesInfo returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure. // Delve cares about from the internal runtime G structure.
func GoroutinesInfo(dbp Process) ([]*G, error) { func GoroutinesInfo(dbp Process) ([]*G, error) {
if dbp.Exited() { if dbp.Exited() {
return nil, &ProcessExitedError{Pid: dbp.Pid()} return nil, &ProcessExitedError{Pid: dbp.Pid()}
} }
if dbp, ok := dbp.(AllGCache); ok { if dbp.Common().allGCache != nil {
if allGCache := dbp.AllGCache(); *allGCache != nil { return dbp.Common().allGCache, nil
return *allGCache, nil
}
} }
var ( var (
@ -458,10 +450,7 @@ func GoroutinesInfo(dbp Process) ([]*G, error) {
allg = append(allg, g) allg = append(allg, g)
} }
} }
if dbp, ok := dbp.(AllGCache); ok { dbp.Common().allGCache = allg
allGCache := dbp.AllGCache()
*allGCache = allg
}
return allg, nil return allg, nil
} }

View File

@ -1515,10 +1515,7 @@ func BenchmarkGoroutinesInfo(b *testing.B) {
withTestProcess("testvariables2", b, func(p proc.Process, fixture protest.Fixture) { withTestProcess("testvariables2", b, func(p proc.Process, fixture protest.Fixture) {
assertNoError(proc.Continue(p), b, "Continue()") assertNoError(proc.Continue(p), b, "Continue()")
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if p, ok := p.(proc.AllGCache); ok { p.Common().ClearAllGCache()
allgcache := p.AllGCache()
*allgcache = nil
}
_, err := proc.GoroutinesInfo(p) _, err := proc.GoroutinesInfo(p)
assertNoError(err, b, "GoroutinesInfo") assertNoError(err, b, "GoroutinesInfo")
} }