mirror of
https://github.com/go-delve/delve.git
synced 2025-10-27 20:23:41 +08:00
proc/*: remove Process.Running
Implementing proc.Process.Running in a thread safe way is complicated and nothing actually uses it besides tests, so we are better off rewriting the tests without Running and removing it. In particular: * The call to d.target.Running() in service/debugger/debugger.go (Restart) can never return true because that line executes while holding processMutex and all continue operations are also executed while holding processMutex. * The call to dbp.Running() pkg/proc/native/proc.go (Detach) can never return true, because it's only called from debugger.(*Debugger).detach() which is also always called while holding processMutex. Since some tests are hard to write correctly without Process.Running a simpler interface, Process.NotifyResumed, is introduced. Fixes #830
This commit is contained in:
committed by
Alessandro Arzilli
parent
98142c695b
commit
16d8bd647f
@ -304,8 +304,7 @@ func (p *Process) Pid() int {
|
|||||||
return p.core.Pid
|
return p.core.Pid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) Running() bool {
|
func (p *Process) ResumeNotify(chan<- struct{}) {
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) SelectedGoroutine() *proc.G {
|
func (p *Process) SelectedGoroutine() *proc.G {
|
||||||
|
|||||||
@ -490,8 +490,8 @@ func (p *Process) Exited() bool {
|
|||||||
return p.exited
|
return p.exited
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) Running() bool {
|
func (p *Process) ResumeNotify(ch chan<- struct{}) {
|
||||||
return p.conn.running
|
p.conn.resumeChan = ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) FindThread(threadID int) (proc.Thread, bool) {
|
func (p *Process) FindThread(threadID int) (proc.Thread, bool) {
|
||||||
|
|||||||
@ -23,7 +23,8 @@ type gdbConn struct {
|
|||||||
inbuf []byte
|
inbuf []byte
|
||||||
outbuf bytes.Buffer
|
outbuf bytes.Buffer
|
||||||
|
|
||||||
running bool
|
running bool
|
||||||
|
resumeChan chan<- struct{}
|
||||||
|
|
||||||
direction proc.Direction // direction of execution
|
direction proc.Direction // direction of execution
|
||||||
|
|
||||||
@ -543,6 +544,10 @@ func (conn *gdbConn) resume(sig uint8, tu *threadUpdater) (string, uint8, error)
|
|||||||
defer func() {
|
defer func() {
|
||||||
conn.running = false
|
conn.running = false
|
||||||
}()
|
}()
|
||||||
|
if conn.resumeChan != nil {
|
||||||
|
close(conn.resumeChan)
|
||||||
|
conn.resumeChan = nil
|
||||||
|
}
|
||||||
return conn.waitForvContStop("resume", "-1", tu)
|
return conn.waitForvContStop("resume", "-1", tu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,8 +52,10 @@ type Checkpoint struct {
|
|||||||
// Info is an interface that provides general information on the target.
|
// Info is an interface that provides general information on the target.
|
||||||
type Info interface {
|
type Info interface {
|
||||||
Pid() int
|
Pid() int
|
||||||
|
// ResumeNotify specifies a channel that will be closed the next time
|
||||||
|
// ContinueOnce finishes resuming the target.
|
||||||
|
ResumeNotify(chan<- struct{})
|
||||||
Exited() bool
|
Exited() bool
|
||||||
Running() bool
|
|
||||||
BinInfo() *BinaryInfo
|
BinInfo() *BinaryInfo
|
||||||
|
|
||||||
ThreadInfo
|
ThreadInfo
|
||||||
|
|||||||
@ -39,6 +39,7 @@ type Process struct {
|
|||||||
firstStart bool
|
firstStart bool
|
||||||
haltMu sync.Mutex
|
haltMu sync.Mutex
|
||||||
halt bool
|
halt bool
|
||||||
|
resumeChan chan<- struct{}
|
||||||
exited bool
|
exited bool
|
||||||
ptraceChan chan func()
|
ptraceChan chan func()
|
||||||
ptraceDoneChan chan interface{}
|
ptraceDoneChan chan interface{}
|
||||||
@ -89,11 +90,6 @@ func (dbp *Process) Detach(kill bool) (err error) {
|
|||||||
dbp.bi.Close()
|
dbp.bi.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if dbp.Running() {
|
|
||||||
if err = dbp.Halt(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !kill {
|
if !kill {
|
||||||
// Clean up any breakpoints we've set.
|
// Clean up any breakpoints we've set.
|
||||||
for _, bp := range dbp.breakpoints {
|
for _, bp := range dbp.breakpoints {
|
||||||
@ -124,15 +120,8 @@ func (dbp *Process) Exited() bool {
|
|||||||
return dbp.exited
|
return dbp.exited
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running returns whether the debugged
|
func (dbp *Process) ResumeNotify(ch chan<- struct{}) {
|
||||||
// process is currently executing.
|
dbp.resumeChan = ch
|
||||||
func (dbp *Process) Running() bool {
|
|
||||||
for _, th := range dbp.threads {
|
|
||||||
if th.running {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbp *Process) Pid() int {
|
func (dbp *Process) Pid() int {
|
||||||
@ -275,6 +264,11 @@ func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
|||||||
th.clearBreakpointState()
|
th.clearBreakpointState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dbp.resumeChan != nil {
|
||||||
|
close(dbp.resumeChan)
|
||||||
|
dbp.resumeChan = nil
|
||||||
|
}
|
||||||
|
|
||||||
trapthread, err := dbp.trapWait(-1)
|
trapthread, err := dbp.trapWait(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -213,27 +213,22 @@ func TestHalt(t *testing.T) {
|
|||||||
_, err := setFunctionBreakpoint(p, "main.loop")
|
_, err := setFunctionBreakpoint(p, "main.loop")
|
||||||
assertNoError(err, t, "SetBreakpoint")
|
assertNoError(err, t, "SetBreakpoint")
|
||||||
assertNoError(proc.Continue(p), t, "Continue")
|
assertNoError(proc.Continue(p), t, "Continue")
|
||||||
if p.Running() {
|
|
||||||
t.Fatal("process still running")
|
|
||||||
}
|
|
||||||
if p, ok := p.(*native.Process); ok {
|
if p, ok := p.(*native.Process); ok {
|
||||||
for _, th := range p.ThreadList() {
|
for _, th := range p.ThreadList() {
|
||||||
_, err := th.Registers(false)
|
_, err := th.Registers(false)
|
||||||
assertNoError(err, t, "Registers")
|
assertNoError(err, t, "Registers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
resumeChan := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
<-resumeChan
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
if p.Running() {
|
if err := p.RequestManualStop(); err != nil {
|
||||||
if err := p.RequestManualStop(); err != nil {
|
t.Fatal(err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
stopChan <- nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
stopChan <- nil
|
||||||
}()
|
}()
|
||||||
|
p.ResumeNotify(resumeChan)
|
||||||
assertNoError(proc.Continue(p), t, "Continue")
|
assertNoError(proc.Continue(p), t, "Continue")
|
||||||
<-stopChan
|
<-stopChan
|
||||||
// Loop through threads and make sure they are all
|
// Loop through threads and make sure they are all
|
||||||
@ -601,9 +596,6 @@ func TestNextNetHTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
withTestProcess("testnextnethttp", t, func(p proc.Process, fixture protest.Fixture) {
|
withTestProcess("testnextnethttp", t, func(p proc.Process, fixture protest.Fixture) {
|
||||||
go func() {
|
go func() {
|
||||||
for !p.Running() {
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
}
|
|
||||||
// Wait for program to start listening.
|
// Wait for program to start listening.
|
||||||
for {
|
for {
|
||||||
conn, err := net.Dial("tcp", "localhost:9191")
|
conn, err := net.Dial("tcp", "localhost:9191")
|
||||||
@ -1934,10 +1926,6 @@ func TestIssue462(t *testing.T) {
|
|||||||
}
|
}
|
||||||
withTestProcess("testnextnethttp", t, func(p proc.Process, fixture protest.Fixture) {
|
withTestProcess("testnextnethttp", t, func(p proc.Process, fixture protest.Fixture) {
|
||||||
go func() {
|
go func() {
|
||||||
for !p.Running() {
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for program to start listening.
|
// Wait for program to start listening.
|
||||||
for {
|
for {
|
||||||
conn, err := net.Dial("tcp", "localhost:9191")
|
conn, err := net.Dial("tcp", "localhost:9191")
|
||||||
|
|||||||
@ -25,24 +25,21 @@ func TestIssue419(t *testing.T) {
|
|||||||
_, err := setFunctionBreakpoint(p, "main.main")
|
_, err := setFunctionBreakpoint(p, "main.main")
|
||||||
assertNoError(err, t, "SetBreakpoint()")
|
assertNoError(err, t, "SetBreakpoint()")
|
||||||
assertNoError(proc.Continue(p), t, "Continue()")
|
assertNoError(proc.Continue(p), t, "Continue()")
|
||||||
|
resumeChan := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
time.Sleep(500 * time.Millisecond)
|
||||||
time.Sleep(500 * time.Millisecond)
|
<-resumeChan
|
||||||
if p.Running() {
|
if p.Pid() <= 0 {
|
||||||
time.Sleep(2 * time.Second)
|
// if we don't stop the inferior the test will never finish
|
||||||
if p.Pid() <= 0 {
|
p.RequestManualStop()
|
||||||
// if we don't stop the inferior the test will never finish
|
p.Kill()
|
||||||
p.RequestManualStop()
|
t.Fatalf("Pid is zero or negative: %d", p.Pid())
|
||||||
p.Kill()
|
return
|
||||||
t.Fatalf("Pid is zero or negative: %d", p.Pid())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
|
||||||
assertNoError(err, t, "syscall.Kill")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
||||||
|
assertNoError(err, t, "syscall.Kill")
|
||||||
}()
|
}()
|
||||||
|
p.ResumeNotify(resumeChan)
|
||||||
err = proc.Continue(p)
|
err = proc.Continue(p)
|
||||||
if _, exited := err.(proc.ProcessExitedError); !exited {
|
if _, exited := err.(proc.ProcessExitedError); !exited {
|
||||||
t.Fatalf("Unexpected error after Continue(): %v\n", err)
|
t.Fatalf("Unexpected error after Continue(): %v\n", err)
|
||||||
|
|||||||
@ -200,9 +200,6 @@ func (d *Debugger) Restart(pos string) ([]api.DiscardedBreakpoint, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !d.target.Exited() {
|
if !d.target.Exited() {
|
||||||
if d.target.Running() {
|
|
||||||
d.target.Halt()
|
|
||||||
}
|
|
||||||
// Ensure the process is in a PTRACE_STOP.
|
// Ensure the process is in a PTRACE_STOP.
|
||||||
if err := stopProcess(d.ProcessPid()); err != nil {
|
if err := stopProcess(d.ProcessPid()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Reference in New Issue
Block a user