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 #ifndef CGO_TSAN
8 void(* const _cgo_yield)() = NULL;
9 #else
10
11 #include <string.h>
12
13 char x_cgo_yield_strncpy_src = 0;
14 char x_cgo_yield_strncpy_dst = 0;
15 size_t x_cgo_yield_strncpy_n = 0;
16
17 /*
18 Stub for allowing libc interceptors to execute.
19
20 _cgo_yield is set to NULL if we do not expect libc interceptors to exist.
21 */
22 static void
23 x_cgo_yield()
24 {
25 /*
26 The libc function(s) we call here must form a no-op and include at least one
27 call that triggers TSAN to process pending asynchronous signals.
28
29 sleep(0) would be fine, but it's not portable C (so it would need more header
30 guards).
31 free(NULL) has a fast-path special case in TSAN, so it doesn't
32 trigger signal delivery.
33 free(malloc(0)) would work (triggering the interceptors in malloc), but
34 it also runs a bunch of user-supplied malloc hooks.
35
36 So we choose strncpy(_, _, 0): it requires an extra header,
37 but it's standard and should be very efficient.
38
39 GCC 7 has an unfortunate habit of optimizing out strncpy calls (see
40 https://golang.org/issue/21196), so the arguments here need to be global
41 variables with external linkage in order to ensure that the call traps all the
42 way down into libc.
43 */
44 strncpy(&x_cgo_yield_strncpy_dst, &x_cgo_yield_strncpy_src,
45 x_cgo_yield_strncpy_n);
46 }
47
48 void(* const _cgo_yield)() = &x_cgo_yield;
49
50 #endif /* GO_TSAN */
51
View as plain text