mirror of
https://github.com/golang/go
synced 2024-11-23 00:00:07 -07:00
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 <hyangah@gmail.com>
This commit is contained in:
parent
f279cadfa4
commit
ed92862522
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user