Index: lib/tsan/tests/rtl/CMakeLists.txt =================================================================== --- lib/tsan/tests/rtl/CMakeLists.txt +++ lib/tsan/tests/rtl/CMakeLists.txt @@ -8,7 +8,7 @@ tsan_thread.cc) if(UNIX) - list(APPEND TSAN_RTL_TEST_SOURCES tsan_test_util_linux.cc) + list(APPEND TSAN_RTL_TEST_SOURCES tsan_test_util_posix.cc) endif() set(TSAN_RTL_TEST_HEADERS Index: lib/tsan/tests/rtl/tsan_test_util_linux.cc =================================================================== --- lib/tsan/tests/rtl/tsan_test_util_linux.cc +++ lib/tsan/tests/rtl/tsan_test_util_linux.cc @@ -1,491 +0,0 @@ -//===-- tsan_test_util_linux.cc -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer (TSan), a race detector. -// -// Test utils, Linux, FreeBSD and Darwin implementation. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_atomic.h" -#include "tsan_interface.h" -#include "tsan_test_util.h" -#include "tsan_report.h" - -#include "gtest/gtest.h" - -#include -#include -#include -#include -#include -#include -#include - -using namespace __tsan; // NOLINT - -static __thread bool expect_report; -static __thread bool expect_report_reported; -static __thread ReportType expect_report_type; - -#ifdef __APPLE__ -#define __interceptor_memcpy wrap_memcpy -#define __interceptor_memset wrap_memset -#define __interceptor_pthread_create wrap_pthread_create -#define __interceptor_pthread_join wrap_pthread_join -#endif - -extern "C" void *__interceptor_memcpy(void *, const void *, uptr); -extern "C" void *__interceptor_memset(void *, int, uptr); -extern "C" int __interceptor_pthread_create(pthread_t *thread, - const pthread_attr_t *attr, - void *(*start_routine)(void *), - void *arg); -extern "C" int __interceptor_pthread_join(pthread_t thread, void **value_ptr); - -static void *BeforeInitThread(void *param) { - (void)param; - return 0; -} - -static void AtExit() { -} - -void TestMutexBeforeInit() { - // Mutexes must be usable before __tsan_init(); - pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&mtx); - pthread_mutex_unlock(&mtx); - pthread_mutex_destroy(&mtx); - pthread_t thr; - __interceptor_pthread_create(&thr, 0, BeforeInitThread, 0); - __interceptor_pthread_join(thr, 0); - atexit(AtExit); -} - -namespace __tsan { -bool OnReport(const ReportDesc *rep, bool suppressed) { - if (expect_report) { - if (rep->typ != expect_report_type) { - printf("Expected report of type %d, got type %d\n", - (int)expect_report_type, (int)rep->typ); - EXPECT_FALSE("Wrong report type"); - return false; - } - } else { - EXPECT_FALSE("Unexpected report"); - return false; - } - expect_report_reported = true; - return true; -} -} // namespace __tsan - -static void* allocate_addr(int size, int offset_from_aligned = 0) { - static uintptr_t foo; - static atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address. - const int kAlign = 16; - CHECK(offset_from_aligned < kAlign); - size = (size + 2 * kAlign) & ~(kAlign - 1); - uintptr_t addr = atomic_fetch_add(&uniq, size, memory_order_relaxed); - return (void*)(addr + offset_from_aligned); -} - -MemLoc::MemLoc(int offset_from_aligned) - : loc_(allocate_addr(16, offset_from_aligned)) { -} - -MemLoc::~MemLoc() { -} - -Mutex::Mutex(Type type) - : alive_() - , type_(type) { -} - -Mutex::~Mutex() { - CHECK(!alive_); -} - -void Mutex::Init() { - CHECK(!alive_); - alive_ = true; - if (type_ == Normal) - CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0); -#ifndef __APPLE__ - else if (type_ == Spin) - CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0); -#endif - else if (type_ == RW) - CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0); - else - CHECK(0); -} - -void Mutex::StaticInit() { - CHECK(!alive_); - CHECK(type_ == Normal); - alive_ = true; - pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER; - memcpy(mtx_, &tmp, sizeof(tmp)); -} - -void Mutex::Destroy() { - CHECK(alive_); - alive_ = false; - if (type_ == Normal) - CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0); -#ifndef __APPLE__ - else if (type_ == Spin) - CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0); -#endif - else if (type_ == RW) - CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0); -} - -void Mutex::Lock() { - CHECK(alive_); - if (type_ == Normal) - CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0); -#ifndef __APPLE__ - else if (type_ == Spin) - CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0); -#endif - else if (type_ == RW) - CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0); -} - -bool Mutex::TryLock() { - CHECK(alive_); - if (type_ == Normal) - return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0; -#ifndef __APPLE__ - else if (type_ == Spin) - return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0; -#endif - else if (type_ == RW) - return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0; - return false; -} - -void Mutex::Unlock() { - CHECK(alive_); - if (type_ == Normal) - CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0); -#ifndef __APPLE__ - else if (type_ == Spin) - CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0); -#endif - else if (type_ == RW) - CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0); -} - -void Mutex::ReadLock() { - CHECK(alive_); - CHECK(type_ == RW); - CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0); -} - -bool Mutex::TryReadLock() { - CHECK(alive_); - CHECK(type_ == RW); - return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0; -} - -void Mutex::ReadUnlock() { - CHECK(alive_); - CHECK(type_ == RW); - CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0); -} - -struct Event { - enum Type { - SHUTDOWN, - READ, - WRITE, - VPTR_UPDATE, - CALL, - RETURN, - MUTEX_CREATE, - MUTEX_DESTROY, - MUTEX_LOCK, - MUTEX_TRYLOCK, - MUTEX_UNLOCK, - MUTEX_READLOCK, - MUTEX_TRYREADLOCK, - MUTEX_READUNLOCK, - MEMCPY, - MEMSET - }; - Type type; - void *ptr; - uptr arg; - uptr arg2; - bool res; - bool expect_report; - ReportType report_type; - - Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0) - : type(type) - , ptr(const_cast(ptr)) - , arg(arg) - , arg2(arg2) - , res() - , expect_report() - , report_type() { - } - - void ExpectReport(ReportType type) { - expect_report = true; - report_type = type; - } -}; - -struct ScopedThread::Impl { - pthread_t thread; - bool main; - bool detached; - atomic_uintptr_t event; // Event* - - static void *ScopedThreadCallback(void *arg); - void send(Event *ev); - void HandleEvent(Event *ev); -}; - -void ScopedThread::Impl::HandleEvent(Event *ev) { - CHECK_EQ(expect_report, false); - expect_report = ev->expect_report; - expect_report_reported = false; - expect_report_type = ev->report_type; - switch (ev->type) { - case Event::READ: - case Event::WRITE: { - void (*tsan_mop)(void *addr) = 0; - if (ev->type == Event::READ) { - switch (ev->arg /*size*/) { - case 1: tsan_mop = __tsan_read1; break; - case 2: tsan_mop = __tsan_read2; break; - case 4: tsan_mop = __tsan_read4; break; - case 8: tsan_mop = __tsan_read8; break; - case 16: tsan_mop = __tsan_read16; break; - } - } else { - switch (ev->arg /*size*/) { - case 1: tsan_mop = __tsan_write1; break; - case 2: tsan_mop = __tsan_write2; break; - case 4: tsan_mop = __tsan_write4; break; - case 8: tsan_mop = __tsan_write8; break; - case 16: tsan_mop = __tsan_write16; break; - } - } - CHECK_NE(tsan_mop, 0); -#if defined(__FreeBSD__) || defined(__APPLE__) - const int ErrCode = ESOCKTNOSUPPORT; -#else - const int ErrCode = ECHRNG; -#endif - errno = ErrCode; - tsan_mop(ev->ptr); - CHECK_EQ(ErrCode, errno); // In no case must errno be changed. - break; - } - case Event::VPTR_UPDATE: - __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg); - break; - case Event::CALL: - __tsan_func_entry((void*)((uptr)ev->ptr)); - break; - case Event::RETURN: - __tsan_func_exit(); - break; - case Event::MUTEX_CREATE: - static_cast(ev->ptr)->Init(); - break; - case Event::MUTEX_DESTROY: - static_cast(ev->ptr)->Destroy(); - break; - case Event::MUTEX_LOCK: - static_cast(ev->ptr)->Lock(); - break; - case Event::MUTEX_TRYLOCK: - ev->res = static_cast(ev->ptr)->TryLock(); - break; - case Event::MUTEX_UNLOCK: - static_cast(ev->ptr)->Unlock(); - break; - case Event::MUTEX_READLOCK: - static_cast(ev->ptr)->ReadLock(); - break; - case Event::MUTEX_TRYREADLOCK: - ev->res = static_cast(ev->ptr)->TryReadLock(); - break; - case Event::MUTEX_READUNLOCK: - static_cast(ev->ptr)->ReadUnlock(); - break; - case Event::MEMCPY: - __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2); - break; - case Event::MEMSET: - __interceptor_memset(ev->ptr, ev->arg, ev->arg2); - break; - default: CHECK(0); - } - if (expect_report && !expect_report_reported) { - printf("Missed expected report of type %d\n", (int)ev->report_type); - EXPECT_FALSE("Missed expected race"); - } - expect_report = false; -} - -void *ScopedThread::Impl::ScopedThreadCallback(void *arg) { - __tsan_func_entry(__builtin_return_address(0)); - Impl *impl = (Impl*)arg; - for (;;) { - Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire); - if (ev == 0) { - sched_yield(); - continue; - } - if (ev->type == Event::SHUTDOWN) { - atomic_store(&impl->event, 0, memory_order_release); - break; - } - impl->HandleEvent(ev); - atomic_store(&impl->event, 0, memory_order_release); - } - __tsan_func_exit(); - return 0; -} - -void ScopedThread::Impl::send(Event *e) { - if (main) { - HandleEvent(e); - } else { - CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0); - atomic_store(&event, (uintptr_t)e, memory_order_release); - while (atomic_load(&event, memory_order_acquire) != 0) - sched_yield(); - } -} - -ScopedThread::ScopedThread(bool detached, bool main) { - impl_ = new Impl; - impl_->main = main; - impl_->detached = detached; - atomic_store(&impl_->event, 0, memory_order_relaxed); - if (!main) { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, detached); - pthread_attr_setstacksize(&attr, 64*1024); - __interceptor_pthread_create(&impl_->thread, &attr, - ScopedThread::Impl::ScopedThreadCallback, impl_); - } -} - -ScopedThread::~ScopedThread() { - if (!impl_->main) { - Event event(Event::SHUTDOWN); - impl_->send(&event); - if (!impl_->detached) - __interceptor_pthread_join(impl_->thread, 0); - } - delete impl_; -} - -void ScopedThread::Detach() { - CHECK(!impl_->main); - CHECK(!impl_->detached); - impl_->detached = true; - pthread_detach(impl_->thread); -} - -void ScopedThread::Access(void *addr, bool is_write, - int size, bool expect_race) { - Event event(is_write ? Event::WRITE : Event::READ, addr, size); - if (expect_race) - event.ExpectReport(ReportTypeRace); - impl_->send(&event); -} - -void ScopedThread::VptrUpdate(const MemLoc &vptr, - const MemLoc &new_val, - bool expect_race) { - Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc()); - if (expect_race) - event.ExpectReport(ReportTypeRace); - impl_->send(&event); -} - -void ScopedThread::Call(void(*pc)()) { - Event event(Event::CALL, (void*)((uintptr_t)pc)); - impl_->send(&event); -} - -void ScopedThread::Return() { - Event event(Event::RETURN); - impl_->send(&event); -} - -void ScopedThread::Create(const Mutex &m) { - Event event(Event::MUTEX_CREATE, &m); - impl_->send(&event); -} - -void ScopedThread::Destroy(const Mutex &m) { - Event event(Event::MUTEX_DESTROY, &m); - impl_->send(&event); -} - -void ScopedThread::Lock(const Mutex &m) { - Event event(Event::MUTEX_LOCK, &m); - impl_->send(&event); -} - -bool ScopedThread::TryLock(const Mutex &m) { - Event event(Event::MUTEX_TRYLOCK, &m); - impl_->send(&event); - return event.res; -} - -void ScopedThread::Unlock(const Mutex &m) { - Event event(Event::MUTEX_UNLOCK, &m); - impl_->send(&event); -} - -void ScopedThread::ReadLock(const Mutex &m) { - Event event(Event::MUTEX_READLOCK, &m); - impl_->send(&event); -} - -bool ScopedThread::TryReadLock(const Mutex &m) { - Event event(Event::MUTEX_TRYREADLOCK, &m); - impl_->send(&event); - return event.res; -} - -void ScopedThread::ReadUnlock(const Mutex &m) { - Event event(Event::MUTEX_READUNLOCK, &m); - impl_->send(&event); -} - -void ScopedThread::Memcpy(void *dst, const void *src, int size, - bool expect_race) { - Event event(Event::MEMCPY, dst, (uptr)src, size); - if (expect_race) - event.ExpectReport(ReportTypeRace); - impl_->send(&event); -} - -void ScopedThread::Memset(void *dst, int val, int size, - bool expect_race) { - Event event(Event::MEMSET, dst, val, size); - if (expect_race) - event.ExpectReport(ReportTypeRace); - impl_->send(&event); -} Index: lib/tsan/tests/rtl/tsan_test_util_posix.cc =================================================================== --- lib/tsan/tests/rtl/tsan_test_util_posix.cc +++ lib/tsan/tests/rtl/tsan_test_util_posix.cc @@ -1,4 +1,4 @@ -//===-- tsan_test_util_linux.cc -------------------------------------------===// +//===-- tsan_test_util_posix.cc -------------------------------------------===// // // The LLVM Compiler Infrastructure //