From: David Crawshaw Date: Wed, 25 Mar 2015 00:52:11 +0000 (-0400) Subject: misc/ios: timeout and continue waiting for getwd X-Git-Tag: go1.5beta1~1432 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ed92862522d5630074e7830334d37af56c6264dc;p=gostls13.git 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/8080 Reviewed-by: Hyang-Ah Hana Kim --- diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go index eb930054da..f81e07e85b 100644 --- a/misc/ios/go_darwin_arm_exec.go +++ b/misc/ios/go_darwin_arm_exec.go @@ -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 }