mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 02:07:58 +08:00
command (next): Improvements for parallel programs
This patch aims to improve how Delve tracks the current goroutine, especially in very highly parallel programs. The main spirit of this patch is to ensure that even in situations where the goroutine we care about is not executing (common for len(g) > len(m)) we still end up back on that goroutine as a result of executing the 'next' command. We accomplish this by tracking our original goroutine id, and any time a breakpoint is hit or a threads stops, we examine the stopped threads and see if any are executing the goroutine we care about. If not, we set 'next' breakpoint for them again and continue them. This is done so that one of those threads can eventually pick up the goroutine we care about and begin executing it again.
This commit is contained in:
@ -115,6 +115,12 @@ func (thread *Thread) Location() (*Location, error) {
|
||||
return &Location{PC: pc, File: f, Line: l, Fn: fn}, nil
|
||||
}
|
||||
|
||||
type ThreadBlockedError struct{}
|
||||
|
||||
func (tbe ThreadBlockedError) Error() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Set breakpoints for potential next lines.
|
||||
//
|
||||
// There are two modes of operation for this method. First,
|
||||
@ -129,11 +135,23 @@ func (thread *Thread) Location() (*Location, error) {
|
||||
// at every single line within the current function, and
|
||||
// another at the functions return address, in case we're at
|
||||
// the end.
|
||||
func (thread *Thread) SetNextBreakpoints() (err error) {
|
||||
func (thread *Thread) setNextBreakpoints() (err error) {
|
||||
if thread.blocked() {
|
||||
return ThreadBlockedError{}
|
||||
}
|
||||
curpc, err := thread.PC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g, err := thread.GetG()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if g.DeferPC != 0 {
|
||||
if _, err = thread.dbp.SetTempBreakpoint(g.DeferPC); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Grab info on our current stack frame. Used to determine
|
||||
// whether we may be stepping outside of the current function.
|
||||
@ -148,15 +166,11 @@ func (thread *Thread) SetNextBreakpoints() (err error) {
|
||||
return err
|
||||
}
|
||||
if filepath.Ext(loc.File) == ".go" {
|
||||
if err = thread.next(curpc, fde, loc.File, loc.Line); err != nil {
|
||||
return err
|
||||
}
|
||||
err = thread.next(curpc, fde, loc.File, loc.Line)
|
||||
} else {
|
||||
if err = thread.cnext(curpc, fde); err != nil {
|
||||
return err
|
||||
}
|
||||
err = thread.cnext(curpc, fde)
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Go routine is exiting.
|
||||
@ -278,3 +292,10 @@ func (thread *Thread) GetG() (g *G, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Returns whether the thread is stopped at
|
||||
// the operating system level. Actual implementation
|
||||
// is OS dependant, look in OS thread file.
|
||||
func (thread *Thread) Stopped() bool {
|
||||
return thread.stopped()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user