Home | History | Annotate | Download | only in testprogcgo
      1 // Copyright 2015 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 // We only build this file with the tag "threadprof", since it starts
      6 // a thread running a busy loop at constructor time.
      7 
      8 // +build !plan9,!windows
      9 // +build threadprof
     10 
     11 package main
     12 
     13 /*
     14 #include <stdint.h>
     15 #include <signal.h>
     16 #include <pthread.h>
     17 
     18 volatile int32_t spinlock;
     19 
     20 static void *thread1(void *p) {
     21 	(void)p;
     22 	while (spinlock == 0)
     23 		;
     24 	pthread_kill(pthread_self(), SIGPROF);
     25 	spinlock = 0;
     26 	return NULL;
     27 }
     28 
     29 __attribute__((constructor)) void issue9456() {
     30 	pthread_t tid;
     31 	pthread_create(&tid, 0, thread1, NULL);
     32 }
     33 
     34 void **nullptr;
     35 
     36 void *crash(void *p) {
     37 	*nullptr = p;
     38 	return 0;
     39 }
     40 
     41 int start_crashing_thread(void) {
     42 	pthread_t tid;
     43 	return pthread_create(&tid, 0, crash, 0);
     44 }
     45 */
     46 import "C"
     47 
     48 import (
     49 	"fmt"
     50 	"os"
     51 	"os/exec"
     52 	"runtime"
     53 	"sync/atomic"
     54 	"time"
     55 	"unsafe"
     56 )
     57 
     58 func init() {
     59 	register("CgoExternalThreadSIGPROF", CgoExternalThreadSIGPROF)
     60 	register("CgoExternalThreadSignal", CgoExternalThreadSignal)
     61 }
     62 
     63 func CgoExternalThreadSIGPROF() {
     64 	// This test intends to test that sending SIGPROF to foreign threads
     65 	// before we make any cgo call will not abort the whole process, so
     66 	// we cannot make any cgo call here. See https://golang.org/issue/9456.
     67 	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
     68 	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
     69 		runtime.Gosched()
     70 	}
     71 	println("OK")
     72 }
     73 
     74 func CgoExternalThreadSignal() {
     75 	if len(os.Args) > 2 && os.Args[2] == "crash" {
     76 		i := C.start_crashing_thread()
     77 		if i != 0 {
     78 			fmt.Println("pthread_create failed:", i)
     79 			// Exit with 0 because parent expects us to crash.
     80 			return
     81 		}
     82 
     83 		// We should crash immediately, but give it plenty of
     84 		// time before failing (by exiting 0) in case we are
     85 		// running on a slow system.
     86 		time.Sleep(5 * time.Second)
     87 		return
     88 	}
     89 
     90 	out, err := exec.Command(os.Args[0], "CgoExternalThreadSignal", "crash").CombinedOutput()
     91 	if err == nil {
     92 		fmt.Println("C signal did not crash as expected")
     93 		fmt.Printf("\n%s\n", out)
     94 		os.Exit(1)
     95 	}
     96 
     97 	fmt.Println("OK")
     98 }
     99