]> Cypherpunks repositories - gostls13.git/commitdiff
misc/ios: timeout and continue waiting for getwd
authorDavid Crawshaw <crawshaw@golang.org>
Wed, 25 Mar 2015 00:52:11 +0000 (20:52 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Wed, 25 Mar 2015 16:31:38 +0000 (16:31 +0000)
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 <hyangah@gmail.com>
misc/ios/go_darwin_arm_exec.go

index eb930054da27b2f2941b07cd68a57d2608533579..f81e07e85b97a300a4ee8521e458416f51c3be3b 100644 (file)
@@ -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
 }