diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2016-02-26 16:57:14 +0000 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2016-02-26 16:57:14 +0000 |
commit | 9f1a781323756a455a053f2401cbb3fbe5ecf1c4 (patch) | |
tree | e9d0dc608656241ba60b8ca8cf53eeb51825a020 /lib/tsan/go | |
parent | 6ee8c131fd532394608a6fc636c6eb69ac590a5e (diff) |
tsan: split thread into logical and physical state
Currently ThreadState holds both logical state (required for race-detection algorithm, user-visible)
and physical state (various caches, most notably malloc cache). Move physical state in a new
Process entity. Besides just being the right thing from abstraction point of view, this solves several
problems:
1. Cache everything on P level in Go. Currently we cache on a mix of goroutine and OS thread levels.
This unnecessary increases memory consumption.
2. Properly handle free operations in Go. Frees are issue by GC which don't have goroutine context.
As the result we could not do anything more than just clearing shadow. For example, we leaked
sync objects and heap block descriptors.
3. This will allow to get rid of libc malloc in Go (now we have Processor context for internal allocator cache).
This in turn will allow to get rid of dependency on libc entirely.
4. Potentially we can make Processor per-CPU in C++ mode instead of per-thread, which will
reduce resource consumption.
The distinction between Thread and Processor is currently used only by Go, C++ creates Processor per OS thread,
which is equivalent to the current scheme.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@262037 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/tsan/go')
-rw-r--r-- | lib/tsan/go/build.bat | 2 | ||||
-rwxr-xr-x | lib/tsan/go/buildgo.sh | 3 | ||||
-rw-r--r-- | lib/tsan/go/test.c | 27 | ||||
-rw-r--r-- | lib/tsan/go/tsan_go.cc | 41 |
4 files changed, 60 insertions, 13 deletions
diff --git a/lib/tsan/go/build.bat b/lib/tsan/go/build.bat index 7d393dc0e..48735bbe5 100644 --- a/lib/tsan/go/build.bat +++ b/lib/tsan/go/build.bat @@ -1,4 +1,4 @@ -type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc +type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_rtl_proc.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -Wno-maybe-uninitialized -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer -std=c++11 diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 668530c5f..5216788ee 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -14,6 +14,7 @@ SRCS=" ../rtl/tsan_rtl_mutex.cc ../rtl/tsan_rtl_report.cc ../rtl/tsan_rtl_thread.cc + ../rtl/tsan_rtl_proc.cc ../rtl/tsan_stack_trace.cc ../rtl/tsan_stat.cc ../rtl/tsan_suppressions.cc @@ -123,7 +124,7 @@ if [ "$SILENT" != "1" ]; then fi $CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS -$CC test.c $DIR/race_$SUFFIX.syso -m64 -o $DIR/test $OSLDFLAGS +$CC test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS export GORACE="exitcode=0 atexit_sleep_ms=0" if [ "$SILENT" != "1" ]; then diff --git a/lib/tsan/go/test.c b/lib/tsan/go/test.c index 94433f1b8..76116ead2 100644 --- a/lib/tsan/go/test.c +++ b/lib/tsan/go/test.c @@ -13,16 +13,21 @@ #include <stdio.h> -void __tsan_init(void **thr, void (*cb)(void*)); +void __tsan_init(void **thr, void **proc, void (*cb)(void*)); void __tsan_fini(); void __tsan_map_shadow(void *addr, unsigned long size); void __tsan_go_start(void *thr, void **chthr, void *pc); void __tsan_go_end(void *thr); +void __tsan_proc_create(void **pproc); +void __tsan_proc_destroy(void *proc); +void __tsan_proc_wire(void *proc, void *thr); +void __tsan_proc_unwire(void *proc, void *thr); void __tsan_read(void *thr, void *addr, void *pc); void __tsan_write(void *thr, void *addr, void *pc); void __tsan_func_enter(void *thr, void *pc); void __tsan_func_exit(void *thr); -void __tsan_malloc(void *p, unsigned long sz); +void __tsan_malloc(void *thr, void *pc, void *p, unsigned long sz); +void __tsan_free(void *proc, void *p, unsigned long sz); void __tsan_acquire(void *thr, void *addr); void __tsan_release(void *thr, void *addr); void __tsan_release_merge(void *thr, void *addr); @@ -36,18 +41,23 @@ void barfoo() {} int main(void) { void *thr0 = 0; + void *proc0 = 0; + __tsan_init(&thr0, &proc0, symbolize_cb); char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1)); - __tsan_malloc(buf, 10); - __tsan_init(&thr0, symbolize_cb); __tsan_map_shadow(buf, 4096); + __tsan_malloc(thr0, 0, buf, 10); + __tsan_free(proc0, buf, 10); __tsan_func_enter(thr0, (char*)&main + 1); - __tsan_malloc(buf, 10); + __tsan_malloc(thr0, 0, buf, 10); __tsan_release(thr0, buf); __tsan_release_merge(thr0, buf); void *thr1 = 0; __tsan_go_start(thr0, &thr1, (char*)&barfoo + 1); void *thr2 = 0; __tsan_go_start(thr0, &thr2, (char*)&barfoo + 1); + __tsan_func_exit(thr0); + __tsan_proc_unwire(proc0, thr0); + __tsan_proc_wire(proc0, thr1); __tsan_func_enter(thr1, (char*)&foobar + 1); __tsan_func_enter(thr1, (char*)&foobar + 1); __tsan_write(thr1, buf, (char*)&barfoo + 1); @@ -55,11 +65,16 @@ int main(void) { __tsan_func_exit(thr1); __tsan_func_exit(thr1); __tsan_go_end(thr1); + void *proc1 = 0; + __tsan_proc_create(&proc1); + __tsan_proc_wire(proc1, thr2); __tsan_func_enter(thr2, (char*)&foobar + 1); __tsan_read(thr2, buf, (char*)&barfoo + 1); + __tsan_free(proc1, buf, 10); __tsan_func_exit(thr2); __tsan_go_end(thr2); - __tsan_func_exit(thr0); + __tsan_proc_destroy(proc0); + __tsan_proc_destroy(proc1); __tsan_fini(); return 0; } diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc index ea0beb742..862f5cad4 100644 --- a/lib/tsan/go/tsan_go.cc +++ b/lib/tsan/go/tsan_go.cc @@ -81,11 +81,14 @@ static ThreadState *AllocGoroutine() { return thr; } -void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) { +void __tsan_init(ThreadState **thrp, + Processor **procp, + void (*cb)(SymbolizeContext *cb)) { symbolize_cb = cb; ThreadState *thr = AllocGoroutine(); main_thr = *thrp = thr; Initialize(thr); + *procp = thr->proc; inited = true; } @@ -140,24 +143,52 @@ void __tsan_func_exit(ThreadState *thr) { FuncExit(thr); } -void __tsan_malloc(void *p, uptr sz) { - if (!inited) - return; - MemoryResetRange(0, 0, (uptr)p, sz); +void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) { + CHECK(inited); + if (thr && thr->proc) + ctx->metamap.AllocBlock(thr, pc, p, sz); + MemoryResetRange(thr, 0, p, sz); +} + +void __tsan_free(Processor *proc, uptr p, uptr sz) { + ctx->metamap.FreeRange(proc, p, sz); } void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { ThreadState *thr = AllocGoroutine(); *pthr = thr; int goid = ThreadCreate(parent, (uptr)pc, 0, true); + Processor *proc = parent->proc; + ProcUnwire(proc, parent); + ProcWire(proc, thr); ThreadStart(thr, goid, 0); + ProcUnwire(proc, thr); + ProcWire(proc, parent); } void __tsan_go_end(ThreadState *thr) { + Processor *proc = thr->proc; ThreadFinish(thr); + ProcUnwire(proc, thr); internal_free(thr); } +void __tsan_proc_create(Processor **pproc) { + *pproc = ProcCreate(); +} + +void __tsan_proc_destroy(Processor *proc) { + ProcDestroy(proc); +} + +void __tsan_proc_wire(Processor *proc, ThreadState *thr) { + ProcWire(proc, thr); +} + +void __tsan_proc_unwire(Processor *proc, ThreadState *thr) { + ProcUnwire(proc, thr); +} + void __tsan_acquire(ThreadState *thr, void *addr) { Acquire(thr, 0, (uptr)addr); } |