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 8package 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 20extern void GoNeedM(); 21 22#define SIGNALERS 10 23 24static 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 42static 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 54static 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*/ 69import "C" 70 71import ( 72 "fmt" 73 "os" 74 "time" 75) 76 77func init() { 78 register("NeedmDeadlock", NeedmDeadlock) 79} 80 81//export GoNeedM 82func GoNeedM() { 83} 84 85func 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