1// Copyright 2016 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 unix
6// +build unix
7
8package main
9
10// Test that an external C thread that is calling malloc can be hit
11// with SIGCHLD signals. This used to fail when built with the race
12// detector, because in that case the signal handler would indirectly
13// call the C malloc function.
14
15/*
16#include <errno.h>
17#include <signal.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <pthread.h>
22#include <sched.h>
23#include <unistd.h>
24
25#define ALLOCERS 100
26#define SIGNALERS 10
27
28static void* signalThread(void* p) {
29	pthread_t* pt = (pthread_t*)(p);
30	int i, j;
31
32	for (i = 0; i < 100; i++) {
33		for (j = 0; j < ALLOCERS; j++) {
34			if (pthread_kill(pt[j], SIGCHLD) < 0) {
35				return NULL;
36			}
37		}
38		usleep(1);
39	}
40	return NULL;
41}
42
43#define CALLS 100
44
45static void* mallocThread(void* p) {
46	int i;
47	void *a[CALLS];
48
49	for (i = 0; i < ALLOCERS; i++) {
50		sched_yield();
51	}
52	for (i = 0; i < CALLS; i++) {
53		a[i] = malloc(i);
54	}
55	for (i = 0; i < CALLS; i++) {
56		free(a[i]);
57	}
58	return NULL;
59}
60
61void runRaceSignalThread() {
62	int i;
63	pthread_t m[ALLOCERS];
64	pthread_t s[SIGNALERS];
65
66	for (i = 0; i < ALLOCERS; i++) {
67		pthread_create(&m[i], NULL, mallocThread, NULL);
68	}
69	for (i = 0; i < SIGNALERS; i++) {
70		pthread_create(&s[i], NULL, signalThread, &m[0]);
71	}
72	for (i = 0; i < SIGNALERS; i++) {
73		pthread_join(s[i], NULL);
74	}
75	for (i = 0; i < ALLOCERS; i++) {
76		pthread_join(m[i], NULL);
77	}
78}
79*/
80import "C"
81
82import (
83	"fmt"
84)
85
86func init() {
87	register("CgoRaceSignal", CgoRaceSignal)
88}
89
90func CgoRaceSignal() {
91	C.runRaceSignalThread()
92	fmt.Println("OK")
93}
94