Source file src/runtime/testdata/testprogcgo/needmdeadlock.go

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

View as plain text