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: default avatarHyang-Ah Hana Kim <hyangah@gmail.com>
parent f279cadf
...@@ -150,8 +150,10 @@ func run(bin string, args []string) (err error) { ...@@ -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 // 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 // of moving parts in an iOS test harness (notably lldb) that can
// swallow useful stdio or cause its own ruckus. // swallow useful stdio or cause its own ruckus.
brTimeout := 5 * time.Second
var timedout chan struct{} var timedout chan struct{}
if t := parseTimeout(args); t > 1*time.Second { if t := parseTimeout(args); t > 1*time.Second {
brTimeout = t / 4
timedout = make(chan struct{}) timedout = make(chan struct{})
time.AfterFunc(t-1*time.Second, func() { time.AfterFunc(t-1*time.Second, func() {
close(timedout) close(timedout)
...@@ -163,7 +165,7 @@ func run(bin string, args []string) (err error) { ...@@ -163,7 +165,7 @@ func run(bin string, args []string) (err error) {
exited <- cmd.Wait() exited <- cmd.Wait()
}() }()
waitFor := func(stage, str string) error { waitFor := func(stage, str string, timeout time.Duration) error {
select { select {
case <-timedout: case <-timedout:
w.printBuf() w.printBuf()
...@@ -174,20 +176,24 @@ func run(bin string, args []string) (err error) { ...@@ -174,20 +176,24 @@ func run(bin string, args []string) (err error) {
case err := <-exited: case err := <-exited:
w.printBuf() w.printBuf()
return fmt.Errorf("failed (stage %s): %v", stage, err) return fmt.Errorf("failed (stage %s): %v", stage, err)
case i := <-w.find(str): case i := <-w.find(str, timeout):
w.clearTo(i + len(str)) if i >= 0 {
w.clearTo(i + len(str))
} else {
log.Printf("timed out on stage %s, continuing", stage)
}
return nil return nil
} }
} }
do := func(cmd string) { do := func(cmd string) {
fmt.Fprintln(lldb, cmd) 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}) panic(waitPanic{err})
} }
} }
// Wait for installation and connection. // 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 return err
} }
...@@ -201,10 +207,12 @@ func run(bin string, args []string) (err error) { ...@@ -201,10 +207,12 @@ func run(bin string, args []string) (err error) {
do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
fmt.Fprintln(lldb, `run`) 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 return err
} }
if err := waitFor("br getwd prompt", "(lldb)"); err != nil { if err := waitFor("br getwd prompt", "(lldb)", 0); err != nil {
return err return err
} }
...@@ -218,11 +226,11 @@ func run(bin string, args []string) (err error) { ...@@ -218,11 +226,11 @@ func run(bin string, args []string) (err error) {
// Watch for SIGSEGV. Ideally lldb would never break on SIGSEGV. // Watch for SIGSEGV. Ideally lldb would never break on SIGSEGV.
// http://golang.org/issue/10043 // http://golang.org/issue/10043
go func() { 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 // cannot use do here, as the defer/recover is not available
// on this goroutine. // on this goroutine.
fmt.Fprintln(lldb, `bt`) fmt.Fprintln(lldb, `bt`)
waitFor("finish backtrace", "(lldb)") waitFor("finish backtrace", "(lldb)", 0)
w.printBuf() w.printBuf()
if p := cmd.Process; p != nil { if p := cmd.Process; p != nil {
p.Kill() p.Kill()
...@@ -261,8 +269,9 @@ type bufWriter struct { ...@@ -261,8 +269,9 @@ type bufWriter struct {
buf []byte buf []byte
suffix []byte // remove from each Write suffix []byte // remove from each Write
findTxt []byte // search buffer on each Write findTxt []byte // search buffer on each Write
findCh chan int // report find position findCh chan int // report find position
findAfter *time.Timer
} }
func (w *bufWriter) Write(in []byte) (n int, err error) { func (w *bufWriter) Write(in []byte) (n int, err error) {
...@@ -280,6 +289,10 @@ 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) close(w.findCh)
w.findTxt = nil w.findTxt = nil
w.findCh = nil w.findCh = nil
if w.findAfter != nil {
w.findAfter.Stop()
w.findAfter = nil
}
} }
} }
return n, nil return n, nil
...@@ -307,7 +320,12 @@ func (w *bufWriter) clearTo(i int) { ...@@ -307,7 +320,12 @@ func (w *bufWriter) clearTo(i int) {
w.buf = w.buf[i:] 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() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
if len(w.findTxt) > 0 { if len(w.findTxt) > 0 {
...@@ -321,6 +339,19 @@ func (w *bufWriter) find(str string) <-chan int { ...@@ -321,6 +339,19 @@ func (w *bufWriter) find(str string) <-chan int {
} else { } else {
w.findTxt = txt w.findTxt = txt
w.findCh = ch 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 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