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