mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +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
|
||||
}
|
||||
|
||||
func (p *Process) Running() bool {
|
||||
return false
|
||||
func (p *Process) ResumeNotify(chan<- struct{}) {
|
||||
}
|
||||
|
||||
func (p *Process) SelectedGoroutine() *proc.G {
|
||||
|
||||
@ -490,8 +490,8 @@ func (p *Process) Exited() bool {
|
||||
return p.exited
|
||||
}
|
||||
|
||||
func (p *Process) Running() bool {
|
||||
return p.conn.running
|
||||
func (p *Process) ResumeNotify(ch chan<- struct{}) {
|
||||
p.conn.resumeChan = ch
|
||||
}
|
||||
|
||||
func (p *Process) FindThread(threadID int) (proc.Thread, bool) {
|
||||
|
||||
@ -23,7 +23,8 @@ type gdbConn struct {
|
||||
inbuf []byte
|
||||
outbuf bytes.Buffer
|
||||
|
||||
running bool
|
||||
running bool
|
||||
resumeChan chan<- struct{}
|
||||
|
||||
direction proc.Direction // direction of execution
|
||||
|
||||
@ -543,6 +544,10 @@ func (conn *gdbConn) resume(sig uint8, tu *threadUpdater) (string, uint8, error)
|
||||
defer func() {
|
||||
conn.running = false
|
||||
}()
|
||||
if conn.resumeChan != nil {
|
||||
close(conn.resumeChan)
|
||||
conn.resumeChan = nil
|
||||
}
|
||||
return conn.waitForvContStop("resume", "-1", tu)
|
||||
}
|
||||
|
||||
|
||||
@ -52,8 +52,10 @@ type Checkpoint struct {
|
||||
// Info is an interface that provides general information on the target.
|
||||
type Info interface {
|
||||
Pid() int
|
||||
// ResumeNotify specifies a channel that will be closed the next time
|
||||
// ContinueOnce finishes resuming the target.
|
||||
ResumeNotify(chan<- struct{})
|
||||
Exited() bool
|
||||
Running() bool
|
||||
BinInfo() *BinaryInfo
|
||||
|
||||
ThreadInfo
|
||||
|
||||
@ -39,6 +39,7 @@ type Process struct {
|
||||
firstStart bool
|
||||
haltMu sync.Mutex
|
||||
halt bool
|
||||
resumeChan chan<- struct{}
|
||||
exited bool
|
||||
ptraceChan chan func()
|
||||
ptraceDoneChan chan interface{}
|
||||
@ -89,11 +90,6 @@ func (dbp *Process) Detach(kill bool) (err error) {
|
||||
dbp.bi.Close()
|
||||
return nil
|
||||
}
|
||||
if dbp.Running() {
|
||||
if err = dbp.Halt(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if !kill {
|
||||
// Clean up any breakpoints we've set.
|
||||
for _, bp := range dbp.breakpoints {
|
||||
@ -124,15 +120,8 @@ func (dbp *Process) Exited() bool {
|
||||
return dbp.exited
|
||||
}
|
||||
|
||||
// Running returns whether the debugged
|
||||
// process is currently executing.
|
||||
func (dbp *Process) Running() bool {
|
||||
for _, th := range dbp.threads {
|
||||
if th.running {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (dbp *Process) ResumeNotify(ch chan<- struct{}) {
|
||||
dbp.resumeChan = ch
|
||||
}
|
||||
|
||||
func (dbp *Process) Pid() int {
|
||||
@ -275,6 +264,11 @@ func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
||||
th.clearBreakpointState()
|
||||
}
|
||||
|
||||
if dbp.resumeChan != nil {
|
||||
close(dbp.resumeChan)
|
||||
dbp.resumeChan = nil
|
||||
}
|
||||
|
||||
trapthread, err := dbp.trapWait(-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -213,27 +213,22 @@ func TestHalt(t *testing.T) {
|
||||
_, err := setFunctionBreakpoint(p, "main.loop")
|
||||
assertNoError(err, t, "SetBreakpoint")
|
||||
assertNoError(proc.Continue(p), t, "Continue")
|
||||
if p.Running() {
|
||||
t.Fatal("process still running")
|
||||
}
|
||||
if p, ok := p.(*native.Process); ok {
|
||||
for _, th := range p.ThreadList() {
|
||||
_, err := th.Registers(false)
|
||||
assertNoError(err, t, "Registers")
|
||||
}
|
||||
}
|
||||
resumeChan := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if p.Running() {
|
||||
if err := p.RequestManualStop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stopChan <- nil
|
||||
return
|
||||
}
|
||||
<-resumeChan
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := p.RequestManualStop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stopChan <- nil
|
||||
}()
|
||||
p.ResumeNotify(resumeChan)
|
||||
assertNoError(proc.Continue(p), t, "Continue")
|
||||
<-stopChan
|
||||
// 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) {
|
||||
go func() {
|
||||
for !p.Running() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
// Wait for program to start listening.
|
||||
for {
|
||||
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) {
|
||||
go func() {
|
||||
for !p.Running() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Wait for program to start listening.
|
||||
for {
|
||||
conn, err := net.Dial("tcp", "localhost:9191")
|
||||
|
||||
@ -25,24 +25,21 @@ func TestIssue419(t *testing.T) {
|
||||
_, err := setFunctionBreakpoint(p, "main.main")
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(proc.Continue(p), t, "Continue()")
|
||||
resumeChan := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
if p.Running() {
|
||||
time.Sleep(2 * time.Second)
|
||||
if p.Pid() <= 0 {
|
||||
// if we don't stop the inferior the test will never finish
|
||||
p.RequestManualStop()
|
||||
p.Kill()
|
||||
t.Fatalf("Pid is zero or negative: %d", p.Pid())
|
||||
return
|
||||
}
|
||||
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
||||
assertNoError(err, t, "syscall.Kill")
|
||||
return
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
<-resumeChan
|
||||
if p.Pid() <= 0 {
|
||||
// if we don't stop the inferior the test will never finish
|
||||
p.RequestManualStop()
|
||||
p.Kill()
|
||||
t.Fatalf("Pid is zero or negative: %d", p.Pid())
|
||||
return
|
||||
}
|
||||
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
||||
assertNoError(err, t, "syscall.Kill")
|
||||
}()
|
||||
p.ResumeNotify(resumeChan)
|
||||
err = proc.Continue(p)
|
||||
if _, exited := err.(proc.ProcessExitedError); !exited {
|
||||
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.Running() {
|
||||
d.target.Halt()
|
||||
}
|
||||
// Ensure the process is in a PTRACE_STOP.
|
||||
if err := stopProcess(d.ProcessPid()); err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user