github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/crash_cgo_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build cgo
     6  
     7  package runtime_test
     8  
     9  import (
    10  	"os/exec"
    11  	"runtime"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func TestCgoCrashHandler(t *testing.T) {
    17  	testCrashHandler(t, true)
    18  }
    19  
    20  func TestCgoSignalDeadlock(t *testing.T) {
    21  	if testing.Short() && runtime.GOOS == "windows" {
    22  		t.Skip("Skipping in short mode") // takes up to 64 seconds
    23  	}
    24  	got := executeTest(t, cgoSignalDeadlockSource, nil)
    25  	want := "OK\n"
    26  	if got != want {
    27  		t.Fatalf("expected %q, but got %q", want, got)
    28  	}
    29  }
    30  
    31  func TestCgoTraceback(t *testing.T) {
    32  	got := executeTest(t, cgoTracebackSource, nil)
    33  	want := "OK\n"
    34  	if got != want {
    35  		t.Fatalf("expected %q, but got %q", want, got)
    36  	}
    37  }
    38  
    39  func TestCgoExternalThreadPanic(t *testing.T) {
    40  	if runtime.GOOS == "plan9" {
    41  		t.Skipf("no pthreads on %s", runtime.GOOS)
    42  	}
    43  	csrc := cgoExternalThreadPanicC
    44  	if runtime.GOOS == "windows" {
    45  		csrc = cgoExternalThreadPanicC_windows
    46  	}
    47  	got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
    48  	want := "panic: BOOM"
    49  	if !strings.Contains(got, want) {
    50  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
    51  	}
    52  }
    53  
    54  func TestCgoExternalThreadSIGPROF(t *testing.T) {
    55  	// issue 9456.
    56  	switch runtime.GOOS {
    57  	case "plan9", "windows":
    58  		t.Skipf("no pthreads on %s", runtime.GOOS)
    59  	case "darwin":
    60  		// static constructor needs external linking, but we don't support
    61  		// external linking on OS X 10.6.
    62  		out, err := exec.Command("uname", "-r").Output()
    63  		if err != nil {
    64  			t.Fatalf("uname -r failed: %v", err)
    65  		}
    66  		// OS X 10.6 == Darwin 10.x
    67  		if strings.HasPrefix(string(out), "10.") {
    68  			t.Skipf("no external linking on OS X 10.6")
    69  		}
    70  	}
    71  	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
    72  		// TODO(austin) External linking not implemented on
    73  		// ppc64 (issue #8912)
    74  		t.Skipf("no external linking on ppc64")
    75  	}
    76  	got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
    77  	want := "OK\n"
    78  	if got != want {
    79  		t.Fatalf("expected %q, but got %q", want, got)
    80  	}
    81  }
    82  
    83  const cgoSignalDeadlockSource = `
    84  package main
    85  
    86  import "C"
    87  
    88  import (
    89  	"fmt"
    90  	"runtime"
    91  	"time"
    92  )
    93  
    94  func main() {
    95  	runtime.GOMAXPROCS(100)
    96  	ping := make(chan bool)
    97  	go func() {
    98  		for i := 0; ; i++ {
    99  			runtime.Gosched()
   100  			select {
   101  			case done := <-ping:
   102  				if done {
   103  					ping <- true
   104  					return
   105  				}
   106  				ping <- true
   107  			default:
   108  			}
   109  			func() {
   110  				defer func() {
   111  					recover()
   112  				}()
   113  				var s *string
   114  				*s = ""
   115  			}()
   116  		}
   117  	}()
   118  	time.Sleep(time.Millisecond)
   119  	for i := 0; i < 64; i++ {
   120  		go func() {
   121  			runtime.LockOSThread()
   122  			select {}
   123  		}()
   124  		go func() {
   125  			runtime.LockOSThread()
   126  			select {}
   127  		}()
   128  		time.Sleep(time.Millisecond)
   129  		ping <- false
   130  		select {
   131  		case <-ping:
   132  		case <-time.After(time.Second):
   133  			fmt.Printf("HANG\n")
   134  			return
   135  		}
   136  	}
   137  	ping <- true
   138  	select {
   139  	case <-ping:
   140  	case <-time.After(time.Second):
   141  		fmt.Printf("HANG\n")
   142  		return
   143  	}
   144  	fmt.Printf("OK\n")
   145  }
   146  `
   147  
   148  const cgoTracebackSource = `
   149  package main
   150  
   151  /* void foo(void) {} */
   152  import "C"
   153  
   154  import (
   155  	"fmt"
   156  	"runtime"
   157  )
   158  
   159  func main() {
   160  	C.foo()
   161  	buf := make([]byte, 1)
   162  	runtime.Stack(buf, true)
   163  	fmt.Printf("OK\n")
   164  }
   165  `
   166  
   167  const cgoExternalThreadPanicSource = `
   168  package main
   169  
   170  // void start(void);
   171  import "C"
   172  
   173  func main() {
   174  	C.start()
   175  	select {}
   176  }
   177  
   178  //export gopanic
   179  func gopanic() {
   180  	panic("BOOM")
   181  }
   182  `
   183  
   184  const cgoExternalThreadPanicC = `
   185  #include <stdlib.h>
   186  #include <stdio.h>
   187  #include <pthread.h>
   188  
   189  void gopanic(void);
   190  
   191  static void*
   192  die(void* x)
   193  {
   194  	gopanic();
   195  	return 0;
   196  }
   197  
   198  void
   199  start(void)
   200  {
   201  	pthread_t t;
   202  	if(pthread_create(&t, 0, die, 0) != 0)
   203  		printf("pthread_create failed\n");
   204  }
   205  `
   206  
   207  const cgoExternalThreadPanicC_windows = `
   208  #include <stdlib.h>
   209  #include <stdio.h>
   210  
   211  void gopanic(void);
   212  
   213  static void*
   214  die(void* x)
   215  {
   216  	gopanic();
   217  	return 0;
   218  }
   219  
   220  void
   221  start(void)
   222  {
   223  	if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
   224  		printf("_beginthreadex failed\n");
   225  }
   226  `
   227  
   228  const cgoExternalThreadSIGPROFSource = `
   229  package main
   230  
   231  /*
   232  #include <stdint.h>
   233  #include <signal.h>
   234  #include <pthread.h>
   235  
   236  volatile int32_t spinlock;
   237  
   238  static void *thread1(void *p) {
   239  	(void)p;
   240  	while (spinlock == 0)
   241  		;
   242  	pthread_kill(pthread_self(), SIGPROF);
   243  	spinlock = 0;
   244  	return NULL;
   245  }
   246  __attribute__((constructor)) void issue9456() {
   247  	pthread_t tid;
   248  	pthread_create(&tid, 0, thread1, NULL);
   249  }
   250  */
   251  import "C"
   252  
   253  import (
   254  	"runtime"
   255  	"sync/atomic"
   256  	"unsafe"
   257  )
   258  
   259  func main() {
   260  	// This test intends to test that sending SIGPROF to foreign threads
   261  	// before we make any cgo call will not abort the whole process, so
   262  	// we cannot make any cgo call here. See http://golang.org/issue/9456.
   263  	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
   264  	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
   265  		runtime.Gosched()
   266  	}
   267  	println("OK")
   268  }
   269  `