github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/testdata/testprogcgo/needmdeadlock.go (about)

     1  // Copyright 2020 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 !plan9,!windows
     6  
     7  package main
     8  
     9  // This is for issue #42207.
    10  // During a call to needm we could get a SIGCHLD signal
    11  // which would itself call needm, causing a deadlock.
    12  
    13  /*
    14  #include <signal.h>
    15  #include <pthread.h>
    16  #include <sched.h>
    17  #include <unistd.h>
    18  
    19  extern void GoNeedM();
    20  
    21  #define SIGNALERS 10
    22  
    23  static void* needmSignalThread(void* p) {
    24  	pthread_t* pt = (pthread_t*)(p);
    25  	int i;
    26  
    27  	for (i = 0; i < 100; i++) {
    28  		if (pthread_kill(*pt, SIGCHLD) < 0) {
    29  			return NULL;
    30  		}
    31  		usleep(1);
    32  	}
    33  	return NULL;
    34  }
    35  
    36  // We don't need many calls, as the deadlock is only likely
    37  // to occur the first couple of times that needm is called.
    38  // After that there will likely be an extra M available.
    39  #define CALLS 10
    40  
    41  static void* needmCallbackThread(void* p) {
    42  	int i;
    43  
    44  	for (i = 0; i < SIGNALERS; i++) {
    45  		sched_yield(); // Help the signal threads get started.
    46  	}
    47  	for (i = 0; i < CALLS; i++) {
    48  		GoNeedM();
    49  	}
    50  	return NULL;
    51  }
    52  
    53  static void runNeedmSignalThread() {
    54  	int i;
    55  	pthread_t caller;
    56  	pthread_t s[SIGNALERS];
    57  
    58  	pthread_create(&caller, NULL, needmCallbackThread, NULL);
    59  	for (i = 0; i < SIGNALERS; i++) {
    60  		pthread_create(&s[i], NULL, needmSignalThread, &caller);
    61  	}
    62  	for (i = 0; i < SIGNALERS; i++) {
    63  		pthread_join(s[i], NULL);
    64  	}
    65  	pthread_join(caller, NULL);
    66  }
    67  */
    68  import "C"
    69  
    70  import (
    71  	"fmt"
    72  	"os"
    73  	"time"
    74  )
    75  
    76  func init() {
    77  	register("NeedmDeadlock", NeedmDeadlock)
    78  }
    79  
    80  //export GoNeedM
    81  func GoNeedM() {
    82  }
    83  
    84  func NeedmDeadlock() {
    85  	// The failure symptom is that the program hangs because of a
    86  	// deadlock in needm, so set an alarm.
    87  	go func() {
    88  		time.Sleep(5 * time.Second)
    89  		fmt.Println("Hung for 5 seconds")
    90  		os.Exit(1)
    91  	}()
    92  
    93  	C.runNeedmSignalThread()
    94  	fmt.Println("OK")
    95  }