Inject SIGTRAP for manual stop

Instead of fighting against the normal flow, just signal a SIGTRAP and
let the existing flow handle it, as long as we set the halt flag
correctly the system should halt.
This commit is contained in:
Derek Parker 2015-07-07 15:51:19 -05:00
parent 8b68ae0bf5
commit 4d1dc5ad0e
5 changed files with 17 additions and 39 deletions

@ -1,16 +1,14 @@
package main
import (
"fmt"
"time"
)
import "fmt"
func loop() {
i := 0
for {
i++
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
if (i % 100000) == 0 {
fmt.Println(i)
}
}
fmt.Println(i)
}

@ -72,14 +72,6 @@ func New(pid int) *Process {
return dbp
}
// A ManualStopError happens when the user triggers a
// manual stop via SIGERM.
type ManualStopError struct{}
func (mse ManualStopError) Error() string {
return "Manual stop requested"
}
// ProcessExitedError indicates that the process has exited and contains both
// process id and exit status.
type ProcessExitedError struct {
@ -208,15 +200,7 @@ func (dbp *Process) FindLocation(str string) (uint64, error) {
// execution. Sends SIGSTOP to all threads.
func (dbp *Process) RequestManualStop() error {
dbp.halt = true
err := dbp.requestManualStop()
if err != nil {
return err
}
err = dbp.Halt()
if err != nil {
return err
}
return nil
return dbp.requestManualStop()
}
// Sets a breakpoint at addr, and stores it in the process wide
@ -668,14 +652,11 @@ func (dbp *Process) run(fn func() error) error {
if dbp.exited {
return fmt.Errorf("process has already exited")
}
dbp.halt = false
for _, th := range dbp.Threads {
th.CurrentBreakpoint = nil
}
if err := fn(); err != nil {
if _, ok := err.(ManualStopError); !ok {
return err
}
return err
}
return nil
}

@ -250,7 +250,7 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
// process natural death _sometimes_.
continue
}
return nil, ManualStopError{}
return nil, nil
case 0:
return nil, fmt.Errorf("error while waiting for task")
}
@ -261,6 +261,10 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
th, err = dbp.handleBreakpointOnThread(int(port))
if err != nil {
if _, ok := err.(NoBreakpointError); ok {
if dbp.halt {
dbp.halt = false
return dbp.Threads[int(port)], nil
}
th := dbp.Threads[int(port)]
if dbp.firstStart || dbp.singleStepping || th.singleStepping {
dbp.firstStart = false

@ -57,7 +57,7 @@ func Launch(cmd []string) (*Process, error) {
}
func (dbp *Process) requestManualStop() (err error) {
return sys.Kill(dbp.Pid, sys.SIGSTOP)
return sys.Kill(dbp.Pid, sys.SIGTRAP)
}
// Attach to a newly created thread, and store that thread in our list of
@ -277,18 +277,15 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
// Sometimes we get an unknown thread, ignore it?
continue
}
if status.StopSignal() == sys.SIGTRAP && dbp.halt {
th.running = false
dbp.halt = false
return th, nil
}
if status.StopSignal() == sys.SIGTRAP {
th.running = false
return dbp.handleBreakpointOnThread(wpid)
}
if status.StopSignal() == sys.SIGTRAP && dbp.halt {
th.running = false
return th, nil
}
if status.StopSignal() == sys.SIGSTOP && dbp.halt {
th.running = false
return nil, ManualStopError{}
}
if th != nil {
// TODO(dp) alert user about unexpected signals here.
if err := th.Continue(); err != nil {

@ -7,7 +7,6 @@ import (
"path/filepath"
"runtime"
"testing"
"time"
protest "github.com/derekparker/delve/proc/test"
)
@ -111,7 +110,6 @@ func TestHalt(t *testing.T) {
go func() {
for {
if p.Running() {
time.Sleep(time.Millisecond)
if err := p.RequestManualStop(); err != nil {
t.Fatal(err)
}