1 // Copyright 2009 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 #include "libcgo.h"
6 
7 /* Stub for creating a new thread */
8 void
x_cgo_thread_start(ThreadStart * arg)9 x_cgo_thread_start(ThreadStart *arg)
10 {
11 	ThreadStart *ts;
12 
13 	/* Make our own copy that can persist after we return. */
14 	_cgo_tsan_acquire();
15 	ts = malloc(sizeof *ts);
16 	_cgo_tsan_release();
17 	if(ts == nil) {
18 		fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
19 		abort();
20 	}
21 	*ts = *arg;
22 
23 	_cgo_sys_thread_start(ts);	/* OS-dependent half */
24 }
25 
26 #ifndef CGO_TSAN
27 void(* const _cgo_yield)() = NULL;
28 #else
29 
30 #include <string.h>
31 
32 char x_cgo_yield_strncpy_src = 0;
33 char x_cgo_yield_strncpy_dst = 0;
34 size_t x_cgo_yield_strncpy_n = 0;
35 
36 /*
37 Stub for allowing libc interceptors to execute.
38 
39 _cgo_yield is set to NULL if we do not expect libc interceptors to exist.
40 */
41 static void
x_cgo_yield()42 x_cgo_yield()
43 {
44 	/*
45 	The libc function(s) we call here must form a no-op and include at least one
46 	call that triggers TSAN to process pending asynchronous signals.
47 
48 	sleep(0) would be fine, but it's not portable C (so it would need more header
49 	guards).
50 	free(NULL) has a fast-path special case in TSAN, so it doesn't
51 	trigger signal delivery.
52 	free(malloc(0)) would work (triggering the interceptors in malloc), but
53 	it also runs a bunch of user-supplied malloc hooks.
54 
55 	So we choose strncpy(_, _, 0): it requires an extra header,
56 	but it's standard and should be very efficient.
57 
58 	GCC 7 has an unfortunate habit of optimizing out strncpy calls (see
59 	https://golang.org/issue/21196), so the arguments here need to be global
60 	variables with external linkage in order to ensure that the call traps all the
61 	way down into libc.
62 	*/
63 	strncpy(&x_cgo_yield_strncpy_dst, &x_cgo_yield_strncpy_src,
64 	        x_cgo_yield_strncpy_n);
65 }
66 
67 void(* const _cgo_yield)() = &x_cgo_yield;
68 
69 #endif  /* GO_TSAN */
70