Commit ed928625 authored by David Crawshaw's avatar David Crawshaw

misc/ios: timeout and continue waiting for getwd

Split out from cl/8024 for clarity and improved approach.

Rarely, "stop reason = breakpoint" does not appear in the lldb stop
text. However the program is ready to proceed. To be a little more
robust about those cases, we wait for two seconds, and if that text
doesn't appear but a prompt does we continue and hope for the best.
Worst case, this results in a harder to read failure message.

Change-Id: Ib20aa92564cdccefd2b7260417c647cd44122b66
Reviewed-on: https://go-review.googlesource.com/8080Reviewed-by: 's avatarHyang-Ah Hana Kim <hyangah@gmail.com>
parent f279cadf
......@@ -150,8 +150,10 @@ func run(bin string, args []string) (err error) {
// Manage the -test.timeout here, outside of the test. There is a lot
// of moving parts in an iOS test harness (notably lldb) that can
// swallow useful stdio or cause its own ruckus.
brTimeout := 5 * time.Second
var timedout chan struct{}
if t := parseTimeout(args); t > 1*time.Second {
brTimeout = t / 4
timedout = make(chan struct{})
time.AfterFunc(t-1*time.Second, func() {
close(timedout)
......@@ -163,7 +165,7 @@ func run(bin string, args []string) (err error) {
exited <- cmd.Wait()
}()
waitFor := func(stage, str string) error {
waitFor := func(stage, str string, timeout time.Duration) error {
select {
case <-timedout:
w.printBuf()
......@@ -174,20 +176,24 @@ func run(bin string, args []string) (err error) {
case err := <-exited:
w.printBuf()
return fmt.Errorf("failed (stage %s): %v", stage, err)
case i := <-w.find(str):
w.clearTo(i + len(str))
case i := <-w.find(str, timeout):
if i >= 0 {
w.clearTo(i + len(str))
} else {
log.Printf("timed out on stage %s, continuing", stage)
}
return nil
}
}
do := func(cmd string) {
fmt.Fprintln(lldb, cmd)
if err := waitFor(fmt.Sprintf("prompt after %q", cmd), "(lldb)"); err != nil {
if err := waitFor(fmt.Sprintf("prompt after %q", cmd), "(lldb)", 0); err != nil {
panic(waitPanic{err})
}
}
// Wait for installation and connection.
if err := waitFor("ios-deploy before run", "(lldb) connect\r\nProcess 0 connected\r\n"); err != nil {
if err := waitFor("ios-deploy before run", "(lldb) connect\r\nProcess 0 connected\r\n", 0); err != nil {
return err
}
......@@ -201,10 +207,12 @@ func run(bin string, args []string) (err error) {
do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
fmt.Fprintln(lldb, `run`)
if err := waitFor("br getwd", "stop reason = breakpoint"); err != nil {
// Sometimes we don't see "reason = breakpoint", so we time out
// and try to continue.
if err := waitFor("br getwd", "stop reason = breakpoint", brTimeout); err != nil {
return err
}
if err := waitFor("br getwd prompt", "(lldb)"); err != nil {
if err := waitFor("br getwd prompt", "(lldb)", 0); err != nil {
return err
}
......@@ -218,11 +226,11 @@ func run(bin string, args []string) (err error) {
// Watch for SIGSEGV. Ideally lldb would never break on SIGSEGV.
// http://golang.org/issue/10043
go func() {
<-w.find("stop reason = EXC_BAD_ACCESS")
<-w.find("stop reason = EXC_BAD_ACCESS", 0)
// cannot use do here, as the defer/recover is not available
// on this goroutine.
fmt.Fprintln(lldb, `bt`)
waitFor("finish backtrace", "(lldb)")
waitFor("finish backtrace", "(lldb)", 0)
w.printBuf()
if p := cmd.Process; p != nil {
p.Kill()
......@@ -261,8 +269,9 @@ type bufWriter struct {
buf []byte
suffix []byte // remove from each Write
findTxt []byte // search buffer on each Write
findCh chan int // report find position
findTxt []byte // search buffer on each Write
findCh chan int // report find position
findAfter *time.Timer
}
func (w *bufWriter) Write(in []byte) (n int, err error) {
......@@ -280,6 +289,10 @@ func (w *bufWriter) Write(in []byte) (n int, err error) {
close(w.findCh)
w.findTxt = nil
w.findCh = nil
if w.findAfter != nil {
w.findAfter.Stop()
w.findAfter = nil
}
}
}
return n, nil
......@@ -307,7 +320,12 @@ func (w *bufWriter) clearTo(i int) {
w.buf = w.buf[i:]
}
func (w *bufWriter) find(str string) <-chan int {
// find returns a channel that will have exactly one byte index sent
// to it when the text str appears in the buffer. If the text does not
// appear before timeout, -1 is sent.
//
// A timeout of zero means no timeout.
func (w *bufWriter) find(str string, timeout time.Duration) <-chan int {
w.mu.Lock()
defer w.mu.Unlock()
if len(w.findTxt) > 0 {
......@@ -321,6 +339,19 @@ func (w *bufWriter) find(str string) <-chan int {
} else {
w.findTxt = txt
w.findCh = ch
if timeout > 0 {
w.findAfter = time.AfterFunc(timeout, func() {
w.mu.Lock()
defer w.mu.Unlock()
if w.findCh == ch {
w.findTxt = nil
w.findCh = nil
w.findAfter = nil
ch <- -1
close(ch)
}
})
}
}
return ch
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment