From 6654e3e0a1fa1deff4acf7d5ea68cd078df7e2fa Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 25 May 2017 12:20:58 -0700 Subject: [PATCH] cmd/cgo, runtime/cgo: add docs for TSAN interaction Change-Id: I3b3ae4ecad0894781a3019326c7262cb9790ad4d Reviewed-on: https://go-review.googlesource.com/44250 Reviewed-by: Bryan Mills Reviewed-by: Dmitry Vyukov --- src/cmd/cgo/out.go | 21 +++++++++++++++++++++ src/runtime/cgo/libcgo.h | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 274bb1fb1af..9ab6bd8f977 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -1323,6 +1323,27 @@ const noTsanProlog = ` ` // This must match the TSAN code in runtime/cgo/libcgo.h. +// This is used when the code is built with the C/C++ Thread SANitizer, +// which is not the same as the Go race detector. +// __tsan_acquire tells TSAN that we are acquiring a lock on a variable, +// in this case _cgo_sync. __tsan_release releases the lock. +// (There is no actual lock, we are just telling TSAN that there is.) +// +// When we call from Go to C we call _cgo_tsan_acquire. +// When the C function returns we call _cgo_tsan_release. +// Similarly, when C calls back into Go we call _cgo_tsan_release +// and then call _cgo_tsan_acquire when we return to C. +// These calls tell TSAN that there is a serialization point at the C call. +// +// This is necessary because TSAN, which is a C/C++ tool, can not see +// the synchronization in the Go code. Without these calls, when +// multiple goroutines call into C code, TSAN does not understand +// that the calls are properly synchronized on the Go side. +// +// To be clear, if the calls are not properly synchronized on the Go side, +// we will be hiding races. But when using TSAN on mixed Go C/C++ code +// it is more important to avoid false positives, which reduce confidence +// in the tool, than to avoid false negatives. const yesTsanProlog = ` #line 1 "cgo-tsan-prolog" #define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread)) diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h index 01f9e721745..2b8b4e25a29 100644 --- a/src/runtime/cgo/libcgo.h +++ b/src/runtime/cgo/libcgo.h @@ -111,6 +111,11 @@ extern void (*(_cgo_get_context_function(void)))(struct context_arg*); #ifdef CGO_TSAN // These must match the definitions in yesTsanProlog in cmd/cgo/out.go. +// In general we should call _cgo_tsan_acquire when we enter C code, +// and call _cgo_tsan_release when we return to Go code. +// This is only necessary when calling code that might be instrumented +// by TSAN, which mostly means system library calls that TSAN intercepts. +// See the comment in cmd/cgo/out.go for more details. long long _cgo_sync __attribute__ ((common));