提交 7b19fe9e 编写于 作者: A Alessandro Arzilli 提交者: Derek Parker

proc: add test for attach/detach, fix detach (#773)

Detach did not work for processes we attach to via PID.

Linux: we were only detaching from the main thread, all threads are
detached independently

Windows: we must resume all threads before detaching.

macOS: still broken.

Updates #772
上级 ecc2eb6d
......@@ -12,5 +12,13 @@ func main() {
header := w.Header().Get("Content-Type")
w.Write([]byte(msg + header))
})
http.ListenAndServe(":9191", nil)
http.HandleFunc("/nobp", func(w http.ResponseWriter, req *http.Request) {
msg := "hello, world!"
header := w.Header().Get("Content-Type")
w.Write([]byte(msg + header))
})
err := http.ListenAndServe(":9191", nil)
if err != nil {
panic(err)
}
}
......@@ -132,7 +132,7 @@ func (dbp *Process) Detach(kill bool) (err error) {
}
}
dbp.execPtraceFunc(func() {
err = PtraceDetach(dbp.pid, 0)
err = dbp.detach()
if err != nil {
return
}
......
......@@ -509,3 +509,7 @@ func (dbp *Process) resume() error {
}
return nil
}
func (dbp *Process) detach() error {
return PtraceDetach(dbp.pid, 0)
}
......@@ -484,6 +484,24 @@ func (dbp *Process) resume() error {
return nil
}
func (dbp *Process) detach() error {
for threadID := range dbp.threads {
err := PtraceDetach(threadID, 0)
if err != nil {
return err
}
}
// For some reason the process will sometimes enter stopped state after a
// detach, this doesn't happen immediately either.
// We have to wait a bit here, then check if the main thread is stopped and
// SIGCONT it if it is.
time.Sleep(50 * time.Millisecond)
if s := status(dbp.pid, dbp.os.comm); s == 'T' {
sys.Kill(dbp.pid, sys.SIGCONT)
}
return nil
}
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)
}
......@@ -6,6 +6,7 @@ import (
"go/ast"
"go/constant"
"go/token"
"io/ioutil"
"net"
"net/http"
"os"
......@@ -2581,3 +2582,55 @@ func TestStacktraceWithBarriers(t *testing.T) {
}
})
}
func TestAttachDetach(t *testing.T) {
if runtime.GOOS == "darwin" {
// does not work on darwin
return
}
fixture := protest.BuildFixture("testnextnethttp")
cmd := exec.Command(fixture.Path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
assertNoError(cmd.Start(), t, "starting fixture")
// wait for testnextnethttp to start listening
t0 := time.Now()
for {
conn, err := net.Dial("tcp", "localhost:9191")
if err == nil {
conn.Close()
break
}
time.Sleep(50 * time.Millisecond)
if time.Since(t0) > 10*time.Second {
t.Fatal("fixture did not start")
}
}
p, err := Attach(cmd.Process.Pid)
assertNoError(err, t, "Attach")
go func() {
time.Sleep(1 * time.Second)
http.Get("http://localhost:9191")
}()
assertNoError(p.Continue(), t, "Continue")
f, ln := currentLineNumber(p, t)
if ln != 11 {
t.Fatalf("Expected line :11 got %s:%d", f, ln)
}
assertNoError(p.Detach(false), t, "Detach")
resp, err := http.Get("http://localhost:9191/nobp")
assertNoError(err, t, "Page request after detach")
bs, err := ioutil.ReadAll(resp.Body)
assertNoError(err, t, "Reading /nobp page")
if out := string(bs); strings.Index(out, "hello, world!") < 0 {
t.Fatalf("/nobp page does not contain \"hello, world!\": %q", out)
}
cmd.Process.Kill()
}
......@@ -663,6 +663,16 @@ func (dbp *Process) resume() error {
return nil
}
func (dbp *Process) detach() error {
for _, thread := range dbp.threads {
_, err := _ResumeThread(thread.os.hThread)
if err != nil {
return err
}
}
return PtraceDetach(dbp.pid, 0)
}
func killProcess(pid int) error {
p, err := os.FindProcess(pid)
if err != nil {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册