15de29a4bSNico Weber //===-- tsan_test_util_posix.cpp ------------------------------------------===//
25de29a4bSNico Weber //
35de29a4bSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45de29a4bSNico Weber // See https://llvm.org/LICENSE.txt for license information.
55de29a4bSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65de29a4bSNico Weber //
75de29a4bSNico Weber //===----------------------------------------------------------------------===//
85de29a4bSNico Weber //
95de29a4bSNico Weber // This file is a part of ThreadSanitizer (TSan), a race detector.
105de29a4bSNico Weber //
115de29a4bSNico Weber // Test utils, Linux, FreeBSD, NetBSD and Darwin implementation.
125de29a4bSNico Weber //===----------------------------------------------------------------------===//
135de29a4bSNico Weber
145de29a4bSNico Weber #include "sanitizer_common/sanitizer_atomic.h"
155de29a4bSNico Weber #include "tsan_interface.h"
165de29a4bSNico Weber #include "tsan_posix_util.h"
17*a61c8e1eSYuanfang Chen #include "tsan_rtl.h"
185de29a4bSNico Weber #include "tsan_test_util.h"
195de29a4bSNico Weber #include "tsan_report.h"
205de29a4bSNico Weber
215de29a4bSNico Weber #include <assert.h>
225de29a4bSNico Weber #include <pthread.h>
235de29a4bSNico Weber #include <stdio.h>
245de29a4bSNico Weber #include <stdint.h>
255de29a4bSNico Weber #include <string.h>
265de29a4bSNico Weber #include <unistd.h>
275de29a4bSNico Weber #include <errno.h>
285de29a4bSNico Weber
297358a110SJoachim Protze #define CALLERPC (__builtin_return_address(0))
307358a110SJoachim Protze
315de29a4bSNico Weber static __thread bool expect_report;
325de29a4bSNico Weber static __thread bool expect_report_reported;
33*a61c8e1eSYuanfang Chen static __thread __tsan::ReportType expect_report_type;
34*a61c8e1eSYuanfang Chen
TearDown()35*a61c8e1eSYuanfang Chen void ThreadSanitizer::TearDown() {
36*a61c8e1eSYuanfang Chen __tsan::ctx->racy_stacks.Reset();
37*a61c8e1eSYuanfang Chen }
385de29a4bSNico Weber
BeforeInitThread(void * param)395de29a4bSNico Weber static void *BeforeInitThread(void *param) {
405de29a4bSNico Weber (void)param;
415de29a4bSNico Weber return 0;
425de29a4bSNico Weber }
435de29a4bSNico Weber
AtExit()445de29a4bSNico Weber static void AtExit() {
455de29a4bSNico Weber }
465de29a4bSNico Weber
TestMutexBeforeInit()475de29a4bSNico Weber void TestMutexBeforeInit() {
485de29a4bSNico Weber // Mutexes must be usable before __tsan_init();
495de29a4bSNico Weber pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
505de29a4bSNico Weber __interceptor_pthread_mutex_lock(&mtx);
515de29a4bSNico Weber __interceptor_pthread_mutex_unlock(&mtx);
525de29a4bSNico Weber __interceptor_pthread_mutex_destroy(&mtx);
535de29a4bSNico Weber pthread_t thr;
545de29a4bSNico Weber __interceptor_pthread_create(&thr, 0, BeforeInitThread, 0);
555de29a4bSNico Weber __interceptor_pthread_join(thr, 0);
565de29a4bSNico Weber atexit(AtExit);
575de29a4bSNico Weber }
585de29a4bSNico Weber
595de29a4bSNico Weber namespace __tsan {
OnReport(const ReportDesc * rep,bool suppressed)605de29a4bSNico Weber bool OnReport(const ReportDesc *rep, bool suppressed) {
615de29a4bSNico Weber if (expect_report) {
625de29a4bSNico Weber if (rep->typ != expect_report_type) {
635de29a4bSNico Weber printf("Expected report of type %d, got type %d\n",
645de29a4bSNico Weber (int)expect_report_type, (int)rep->typ);
655de29a4bSNico Weber EXPECT_TRUE(false) << "Wrong report type";
665de29a4bSNico Weber return false;
675de29a4bSNico Weber }
685de29a4bSNico Weber } else {
695de29a4bSNico Weber EXPECT_TRUE(false) << "Unexpected report";
705de29a4bSNico Weber return false;
715de29a4bSNico Weber }
725de29a4bSNico Weber expect_report_reported = true;
735de29a4bSNico Weber return true;
745de29a4bSNico Weber }
755de29a4bSNico Weber } // namespace __tsan
765de29a4bSNico Weber
allocate_addr(int size,int offset_from_aligned=0)775de29a4bSNico Weber static void* allocate_addr(int size, int offset_from_aligned = 0) {
785de29a4bSNico Weber static uintptr_t foo;
79*a61c8e1eSYuanfang Chen static __tsan::atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address.
805de29a4bSNico Weber const int kAlign = 16;
815de29a4bSNico Weber CHECK(offset_from_aligned < kAlign);
825de29a4bSNico Weber size = (size + 2 * kAlign) & ~(kAlign - 1);
83*a61c8e1eSYuanfang Chen uintptr_t addr = atomic_fetch_add(&uniq, size, __tsan::memory_order_relaxed);
845de29a4bSNico Weber return (void*)(addr + offset_from_aligned);
855de29a4bSNico Weber }
865de29a4bSNico Weber
MemLoc(int offset_from_aligned)875de29a4bSNico Weber MemLoc::MemLoc(int offset_from_aligned)
885de29a4bSNico Weber : loc_(allocate_addr(16, offset_from_aligned)) {
895de29a4bSNico Weber }
905de29a4bSNico Weber
~MemLoc()915de29a4bSNico Weber MemLoc::~MemLoc() {
925de29a4bSNico Weber }
935de29a4bSNico Weber
UserMutex(Type type)94cfed8d0fSDmitry Vyukov UserMutex::UserMutex(Type type) : alive_(), type_(type) {}
955de29a4bSNico Weber
~UserMutex()96cfed8d0fSDmitry Vyukov UserMutex::~UserMutex() { CHECK(!alive_); }
975de29a4bSNico Weber
Init()98cfed8d0fSDmitry Vyukov void UserMutex::Init() {
995de29a4bSNico Weber CHECK(!alive_);
1005de29a4bSNico Weber alive_ = true;
1015de29a4bSNico Weber if (type_ == Normal)
1025de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
1035de29a4bSNico Weber #ifndef __APPLE__
1045de29a4bSNico Weber else if (type_ == Spin)
1055de29a4bSNico Weber CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
1065de29a4bSNico Weber #endif
1075de29a4bSNico Weber else if (type_ == RW)
1085de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
1095de29a4bSNico Weber else
1105de29a4bSNico Weber CHECK(0);
1115de29a4bSNico Weber }
1125de29a4bSNico Weber
StaticInit()113cfed8d0fSDmitry Vyukov void UserMutex::StaticInit() {
1145de29a4bSNico Weber CHECK(!alive_);
1155de29a4bSNico Weber CHECK(type_ == Normal);
1165de29a4bSNico Weber alive_ = true;
1175de29a4bSNico Weber pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
1185de29a4bSNico Weber memcpy(mtx_, &tmp, sizeof(tmp));
1195de29a4bSNico Weber }
1205de29a4bSNico Weber
Destroy()121cfed8d0fSDmitry Vyukov void UserMutex::Destroy() {
1225de29a4bSNico Weber CHECK(alive_);
1235de29a4bSNico Weber alive_ = false;
1245de29a4bSNico Weber if (type_ == Normal)
1255de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
1265de29a4bSNico Weber #ifndef __APPLE__
1275de29a4bSNico Weber else if (type_ == Spin)
1285de29a4bSNico Weber CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
1295de29a4bSNico Weber #endif
1305de29a4bSNico Weber else if (type_ == RW)
1315de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
1325de29a4bSNico Weber }
1335de29a4bSNico Weber
Lock()134cfed8d0fSDmitry Vyukov void UserMutex::Lock() {
1355de29a4bSNico Weber CHECK(alive_);
1365de29a4bSNico Weber if (type_ == Normal)
1375de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
1385de29a4bSNico Weber #ifndef __APPLE__
1395de29a4bSNico Weber else if (type_ == Spin)
1405de29a4bSNico Weber CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
1415de29a4bSNico Weber #endif
1425de29a4bSNico Weber else if (type_ == RW)
1435de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
1445de29a4bSNico Weber }
1455de29a4bSNico Weber
TryLock()146cfed8d0fSDmitry Vyukov bool UserMutex::TryLock() {
1475de29a4bSNico Weber CHECK(alive_);
1485de29a4bSNico Weber if (type_ == Normal)
1495de29a4bSNico Weber return __interceptor_pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
1505de29a4bSNico Weber #ifndef __APPLE__
1515de29a4bSNico Weber else if (type_ == Spin)
1525de29a4bSNico Weber return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
1535de29a4bSNico Weber #endif
1545de29a4bSNico Weber else if (type_ == RW)
1555de29a4bSNico Weber return __interceptor_pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
1565de29a4bSNico Weber return false;
1575de29a4bSNico Weber }
1585de29a4bSNico Weber
Unlock()159cfed8d0fSDmitry Vyukov void UserMutex::Unlock() {
1605de29a4bSNico Weber CHECK(alive_);
1615de29a4bSNico Weber if (type_ == Normal)
1625de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
1635de29a4bSNico Weber #ifndef __APPLE__
1645de29a4bSNico Weber else if (type_ == Spin)
1655de29a4bSNico Weber CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
1665de29a4bSNico Weber #endif
1675de29a4bSNico Weber else if (type_ == RW)
1685de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
1695de29a4bSNico Weber }
1705de29a4bSNico Weber
ReadLock()171cfed8d0fSDmitry Vyukov void UserMutex::ReadLock() {
1725de29a4bSNico Weber CHECK(alive_);
1735de29a4bSNico Weber CHECK(type_ == RW);
1745de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
1755de29a4bSNico Weber }
1765de29a4bSNico Weber
TryReadLock()177cfed8d0fSDmitry Vyukov bool UserMutex::TryReadLock() {
1785de29a4bSNico Weber CHECK(alive_);
1795de29a4bSNico Weber CHECK(type_ == RW);
1805de29a4bSNico Weber return __interceptor_pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0;
1815de29a4bSNico Weber }
1825de29a4bSNico Weber
ReadUnlock()183cfed8d0fSDmitry Vyukov void UserMutex::ReadUnlock() {
1845de29a4bSNico Weber CHECK(alive_);
1855de29a4bSNico Weber CHECK(type_ == RW);
1865de29a4bSNico Weber CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
1875de29a4bSNico Weber }
1885de29a4bSNico Weber
1895de29a4bSNico Weber struct Event {
1905de29a4bSNico Weber enum Type {
1915de29a4bSNico Weber SHUTDOWN,
1925de29a4bSNico Weber READ,
1935de29a4bSNico Weber WRITE,
1945de29a4bSNico Weber VPTR_UPDATE,
1955de29a4bSNico Weber CALL,
1965de29a4bSNico Weber RETURN,
1975de29a4bSNico Weber MUTEX_CREATE,
1985de29a4bSNico Weber MUTEX_DESTROY,
1995de29a4bSNico Weber MUTEX_LOCK,
2005de29a4bSNico Weber MUTEX_TRYLOCK,
2015de29a4bSNico Weber MUTEX_UNLOCK,
2025de29a4bSNico Weber MUTEX_READLOCK,
2035de29a4bSNico Weber MUTEX_TRYREADLOCK,
2045de29a4bSNico Weber MUTEX_READUNLOCK,
2055de29a4bSNico Weber MEMCPY,
2065de29a4bSNico Weber MEMSET
2075de29a4bSNico Weber };
2085de29a4bSNico Weber Type type;
2095de29a4bSNico Weber void *ptr;
2105de29a4bSNico Weber uptr arg;
2115de29a4bSNico Weber uptr arg2;
2125de29a4bSNico Weber bool res;
2135de29a4bSNico Weber bool expect_report;
214*a61c8e1eSYuanfang Chen __tsan::ReportType report_type;
2155de29a4bSNico Weber
EventEvent21648eb4a27SVitaly Buka explicit Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
21748eb4a27SVitaly Buka : type(type),
21848eb4a27SVitaly Buka ptr(const_cast<void *>(ptr)),
21948eb4a27SVitaly Buka arg(arg),
22048eb4a27SVitaly Buka arg2(arg2),
22148eb4a27SVitaly Buka res(),
22248eb4a27SVitaly Buka expect_report(),
22348eb4a27SVitaly Buka report_type() {}
2245de29a4bSNico Weber
ExpectReportEvent225*a61c8e1eSYuanfang Chen void ExpectReport(__tsan::ReportType type) {
2265de29a4bSNico Weber expect_report = true;
2275de29a4bSNico Weber report_type = type;
2285de29a4bSNico Weber }
2295de29a4bSNico Weber };
2305de29a4bSNico Weber
2315de29a4bSNico Weber struct ScopedThread::Impl {
2325de29a4bSNico Weber pthread_t thread;
2335de29a4bSNico Weber bool main;
2345de29a4bSNico Weber bool detached;
235*a61c8e1eSYuanfang Chen __tsan::atomic_uintptr_t event; // Event*
2365de29a4bSNico Weber
2375de29a4bSNico Weber static void *ScopedThreadCallback(void *arg);
2385de29a4bSNico Weber void send(Event *ev);
2395de29a4bSNico Weber void HandleEvent(Event *ev);
2405de29a4bSNico Weber };
2415de29a4bSNico Weber
HandleEvent(Event * ev)2425de29a4bSNico Weber void ScopedThread::Impl::HandleEvent(Event *ev) {
2435de29a4bSNico Weber CHECK_EQ(expect_report, false);
2445de29a4bSNico Weber expect_report = ev->expect_report;
2455de29a4bSNico Weber expect_report_reported = false;
2465de29a4bSNico Weber expect_report_type = ev->report_type;
2475de29a4bSNico Weber switch (ev->type) {
2485de29a4bSNico Weber case Event::READ:
2495de29a4bSNico Weber case Event::WRITE: {
2507358a110SJoachim Protze void (*tsan_mop)(void *addr, void *pc) = 0;
2515de29a4bSNico Weber if (ev->type == Event::READ) {
2525de29a4bSNico Weber switch (ev->arg /*size*/) {
2537358a110SJoachim Protze case 1:
2547358a110SJoachim Protze tsan_mop = __tsan_read1_pc;
2557358a110SJoachim Protze break;
2567358a110SJoachim Protze case 2:
2577358a110SJoachim Protze tsan_mop = __tsan_read2_pc;
2587358a110SJoachim Protze break;
2597358a110SJoachim Protze case 4:
2607358a110SJoachim Protze tsan_mop = __tsan_read4_pc;
2617358a110SJoachim Protze break;
2627358a110SJoachim Protze case 8:
2637358a110SJoachim Protze tsan_mop = __tsan_read8_pc;
2647358a110SJoachim Protze break;
2657358a110SJoachim Protze case 16:
2667358a110SJoachim Protze tsan_mop = __tsan_read16_pc;
2677358a110SJoachim Protze break;
2685de29a4bSNico Weber }
2695de29a4bSNico Weber } else {
2705de29a4bSNico Weber switch (ev->arg /*size*/) {
2717358a110SJoachim Protze case 1:
2727358a110SJoachim Protze tsan_mop = __tsan_write1_pc;
2737358a110SJoachim Protze break;
2747358a110SJoachim Protze case 2:
2757358a110SJoachim Protze tsan_mop = __tsan_write2_pc;
2767358a110SJoachim Protze break;
2777358a110SJoachim Protze case 4:
2787358a110SJoachim Protze tsan_mop = __tsan_write4_pc;
2797358a110SJoachim Protze break;
2807358a110SJoachim Protze case 8:
2817358a110SJoachim Protze tsan_mop = __tsan_write8_pc;
2827358a110SJoachim Protze break;
2837358a110SJoachim Protze case 16:
2847358a110SJoachim Protze tsan_mop = __tsan_write16_pc;
2857358a110SJoachim Protze break;
2865de29a4bSNico Weber }
2875de29a4bSNico Weber }
2885de29a4bSNico Weber CHECK_NE(tsan_mop, 0);
2895de29a4bSNico Weber #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
2905de29a4bSNico Weber const int ErrCode = ESOCKTNOSUPPORT;
2915de29a4bSNico Weber #else
2925de29a4bSNico Weber const int ErrCode = ECHRNG;
2935de29a4bSNico Weber #endif
2945de29a4bSNico Weber errno = ErrCode;
2957358a110SJoachim Protze tsan_mop(ev->ptr, (void *)ev->arg2);
2965de29a4bSNico Weber CHECK_EQ(ErrCode, errno); // In no case must errno be changed.
2975de29a4bSNico Weber break;
2985de29a4bSNico Weber }
2995de29a4bSNico Weber case Event::VPTR_UPDATE:
3005de29a4bSNico Weber __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
3015de29a4bSNico Weber break;
3025de29a4bSNico Weber case Event::CALL:
3035de29a4bSNico Weber __tsan_func_entry((void*)((uptr)ev->ptr));
3045de29a4bSNico Weber break;
3055de29a4bSNico Weber case Event::RETURN:
3065de29a4bSNico Weber __tsan_func_exit();
3075de29a4bSNico Weber break;
3085de29a4bSNico Weber case Event::MUTEX_CREATE:
309cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->Init();
3105de29a4bSNico Weber break;
3115de29a4bSNico Weber case Event::MUTEX_DESTROY:
312cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->Destroy();
3135de29a4bSNico Weber break;
3145de29a4bSNico Weber case Event::MUTEX_LOCK:
315cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->Lock();
3165de29a4bSNico Weber break;
3175de29a4bSNico Weber case Event::MUTEX_TRYLOCK:
318cfed8d0fSDmitry Vyukov ev->res = static_cast<UserMutex *>(ev->ptr)->TryLock();
3195de29a4bSNico Weber break;
3205de29a4bSNico Weber case Event::MUTEX_UNLOCK:
321cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->Unlock();
3225de29a4bSNico Weber break;
3235de29a4bSNico Weber case Event::MUTEX_READLOCK:
324cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->ReadLock();
3255de29a4bSNico Weber break;
3265de29a4bSNico Weber case Event::MUTEX_TRYREADLOCK:
327cfed8d0fSDmitry Vyukov ev->res = static_cast<UserMutex *>(ev->ptr)->TryReadLock();
3285de29a4bSNico Weber break;
3295de29a4bSNico Weber case Event::MUTEX_READUNLOCK:
330cfed8d0fSDmitry Vyukov static_cast<UserMutex *>(ev->ptr)->ReadUnlock();
3315de29a4bSNico Weber break;
3325de29a4bSNico Weber case Event::MEMCPY:
3335de29a4bSNico Weber __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
3345de29a4bSNico Weber break;
3355de29a4bSNico Weber case Event::MEMSET:
3365de29a4bSNico Weber __interceptor_memset(ev->ptr, ev->arg, ev->arg2);
3375de29a4bSNico Weber break;
3385de29a4bSNico Weber default: CHECK(0);
3395de29a4bSNico Weber }
3405de29a4bSNico Weber if (expect_report && !expect_report_reported) {
3415de29a4bSNico Weber printf("Missed expected report of type %d\n", (int)ev->report_type);
3425de29a4bSNico Weber EXPECT_TRUE(false) << "Missed expected race";
3435de29a4bSNico Weber }
3445de29a4bSNico Weber expect_report = false;
3455de29a4bSNico Weber }
3465de29a4bSNico Weber
ScopedThreadCallback(void * arg)3475de29a4bSNico Weber void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
3487358a110SJoachim Protze __tsan_func_entry(CALLERPC);
3495de29a4bSNico Weber Impl *impl = (Impl*)arg;
3505de29a4bSNico Weber for (;;) {
351*a61c8e1eSYuanfang Chen Event *ev =
352*a61c8e1eSYuanfang Chen (Event *)atomic_load(&impl->event, __tsan::memory_order_acquire);
3535de29a4bSNico Weber if (ev == 0) {
3545de29a4bSNico Weber sched_yield();
3555de29a4bSNico Weber continue;
3565de29a4bSNico Weber }
3575de29a4bSNico Weber if (ev->type == Event::SHUTDOWN) {
358*a61c8e1eSYuanfang Chen atomic_store(&impl->event, 0, __tsan::memory_order_release);
3595de29a4bSNico Weber break;
3605de29a4bSNico Weber }
3615de29a4bSNico Weber impl->HandleEvent(ev);
362*a61c8e1eSYuanfang Chen atomic_store(&impl->event, 0, __tsan::memory_order_release);
3635de29a4bSNico Weber }
3645de29a4bSNico Weber __tsan_func_exit();
3655de29a4bSNico Weber return 0;
3665de29a4bSNico Weber }
3675de29a4bSNico Weber
send(Event * e)3685de29a4bSNico Weber void ScopedThread::Impl::send(Event *e) {
3695de29a4bSNico Weber if (main) {
3705de29a4bSNico Weber HandleEvent(e);
3715de29a4bSNico Weber } else {
372*a61c8e1eSYuanfang Chen CHECK_EQ(atomic_load(&event, __tsan::memory_order_relaxed), 0);
373*a61c8e1eSYuanfang Chen atomic_store(&event, (uintptr_t)e, __tsan::memory_order_release);
374*a61c8e1eSYuanfang Chen while (atomic_load(&event, __tsan::memory_order_acquire) != 0)
3755de29a4bSNico Weber sched_yield();
3765de29a4bSNico Weber }
3775de29a4bSNico Weber }
3785de29a4bSNico Weber
ScopedThread(bool detached,bool main)3795de29a4bSNico Weber ScopedThread::ScopedThread(bool detached, bool main) {
3805de29a4bSNico Weber impl_ = new Impl;
3815de29a4bSNico Weber impl_->main = main;
3825de29a4bSNico Weber impl_->detached = detached;
383*a61c8e1eSYuanfang Chen atomic_store(&impl_->event, 0, __tsan::memory_order_relaxed);
3845de29a4bSNico Weber if (!main) {
3855de29a4bSNico Weber pthread_attr_t attr;
3865de29a4bSNico Weber pthread_attr_init(&attr);
3875de29a4bSNico Weber pthread_attr_setdetachstate(
3885de29a4bSNico Weber &attr, detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
3895de29a4bSNico Weber pthread_attr_setstacksize(&attr, 64*1024);
3905de29a4bSNico Weber __interceptor_pthread_create(&impl_->thread, &attr,
3915de29a4bSNico Weber ScopedThread::Impl::ScopedThreadCallback, impl_);
3925de29a4bSNico Weber }
3935de29a4bSNico Weber }
3945de29a4bSNico Weber
~ScopedThread()3955de29a4bSNico Weber ScopedThread::~ScopedThread() {
3965de29a4bSNico Weber if (!impl_->main) {
3975de29a4bSNico Weber Event event(Event::SHUTDOWN);
3985de29a4bSNico Weber impl_->send(&event);
3995de29a4bSNico Weber if (!impl_->detached)
4005de29a4bSNico Weber __interceptor_pthread_join(impl_->thread, 0);
4015de29a4bSNico Weber }
4025de29a4bSNico Weber delete impl_;
4035de29a4bSNico Weber }
4045de29a4bSNico Weber
Detach()4055de29a4bSNico Weber void ScopedThread::Detach() {
4065de29a4bSNico Weber CHECK(!impl_->main);
4075de29a4bSNico Weber CHECK(!impl_->detached);
4085de29a4bSNico Weber impl_->detached = true;
4095de29a4bSNico Weber __interceptor_pthread_detach(impl_->thread);
4105de29a4bSNico Weber }
4115de29a4bSNico Weber
Access(void * addr,bool is_write,int size,bool expect_race)4125de29a4bSNico Weber void ScopedThread::Access(void *addr, bool is_write,
4135de29a4bSNico Weber int size, bool expect_race) {
4147358a110SJoachim Protze Event event(is_write ? Event::WRITE : Event::READ, addr, size,
4157358a110SJoachim Protze (uptr)CALLERPC);
4165de29a4bSNico Weber if (expect_race)
417*a61c8e1eSYuanfang Chen event.ExpectReport(__tsan::ReportTypeRace);
4185de29a4bSNico Weber impl_->send(&event);
4195de29a4bSNico Weber }
4205de29a4bSNico Weber
VptrUpdate(const MemLoc & vptr,const MemLoc & new_val,bool expect_race)4215de29a4bSNico Weber void ScopedThread::VptrUpdate(const MemLoc &vptr,
4225de29a4bSNico Weber const MemLoc &new_val,
4235de29a4bSNico Weber bool expect_race) {
4245de29a4bSNico Weber Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
4255de29a4bSNico Weber if (expect_race)
426*a61c8e1eSYuanfang Chen event.ExpectReport(__tsan::ReportTypeRace);
4275de29a4bSNico Weber impl_->send(&event);
4285de29a4bSNico Weber }
4295de29a4bSNico Weber
Call(void (* pc)())4305de29a4bSNico Weber void ScopedThread::Call(void(*pc)()) {
4315de29a4bSNico Weber Event event(Event::CALL, (void*)((uintptr_t)pc));
4325de29a4bSNico Weber impl_->send(&event);
4335de29a4bSNico Weber }
4345de29a4bSNico Weber
Return()4355de29a4bSNico Weber void ScopedThread::Return() {
4365de29a4bSNico Weber Event event(Event::RETURN);
4375de29a4bSNico Weber impl_->send(&event);
4385de29a4bSNico Weber }
4395de29a4bSNico Weber
Create(const UserMutex & m)440cfed8d0fSDmitry Vyukov void ScopedThread::Create(const UserMutex &m) {
4415de29a4bSNico Weber Event event(Event::MUTEX_CREATE, &m);
4425de29a4bSNico Weber impl_->send(&event);
4435de29a4bSNico Weber }
4445de29a4bSNico Weber
Destroy(const UserMutex & m)445cfed8d0fSDmitry Vyukov void ScopedThread::Destroy(const UserMutex &m) {
4465de29a4bSNico Weber Event event(Event::MUTEX_DESTROY, &m);
4475de29a4bSNico Weber impl_->send(&event);
4485de29a4bSNico Weber }
4495de29a4bSNico Weber
Lock(const UserMutex & m)450cfed8d0fSDmitry Vyukov void ScopedThread::Lock(const UserMutex &m) {
4515de29a4bSNico Weber Event event(Event::MUTEX_LOCK, &m);
4525de29a4bSNico Weber impl_->send(&event);
4535de29a4bSNico Weber }
4545de29a4bSNico Weber
TryLock(const UserMutex & m)455cfed8d0fSDmitry Vyukov bool ScopedThread::TryLock(const UserMutex &m) {
4565de29a4bSNico Weber Event event(Event::MUTEX_TRYLOCK, &m);
4575de29a4bSNico Weber impl_->send(&event);
4585de29a4bSNico Weber return event.res;
4595de29a4bSNico Weber }
4605de29a4bSNico Weber
Unlock(const UserMutex & m)461cfed8d0fSDmitry Vyukov void ScopedThread::Unlock(const UserMutex &m) {
4625de29a4bSNico Weber Event event(Event::MUTEX_UNLOCK, &m);
4635de29a4bSNico Weber impl_->send(&event);
4645de29a4bSNico Weber }
4655de29a4bSNico Weber
ReadLock(const UserMutex & m)466cfed8d0fSDmitry Vyukov void ScopedThread::ReadLock(const UserMutex &m) {
4675de29a4bSNico Weber Event event(Event::MUTEX_READLOCK, &m);
4685de29a4bSNico Weber impl_->send(&event);
4695de29a4bSNico Weber }
4705de29a4bSNico Weber
TryReadLock(const UserMutex & m)471cfed8d0fSDmitry Vyukov bool ScopedThread::TryReadLock(const UserMutex &m) {
4725de29a4bSNico Weber Event event(Event::MUTEX_TRYREADLOCK, &m);
4735de29a4bSNico Weber impl_->send(&event);
4745de29a4bSNico Weber return event.res;
4755de29a4bSNico Weber }
4765de29a4bSNico Weber
ReadUnlock(const UserMutex & m)477cfed8d0fSDmitry Vyukov void ScopedThread::ReadUnlock(const UserMutex &m) {
4785de29a4bSNico Weber Event event(Event::MUTEX_READUNLOCK, &m);
4795de29a4bSNico Weber impl_->send(&event);
4805de29a4bSNico Weber }
4815de29a4bSNico Weber
Memcpy(void * dst,const void * src,int size,bool expect_race)4825de29a4bSNico Weber void ScopedThread::Memcpy(void *dst, const void *src, int size,
4835de29a4bSNico Weber bool expect_race) {
4845de29a4bSNico Weber Event event(Event::MEMCPY, dst, (uptr)src, size);
4855de29a4bSNico Weber if (expect_race)
486*a61c8e1eSYuanfang Chen event.ExpectReport(__tsan::ReportTypeRace);
4875de29a4bSNico Weber impl_->send(&event);
4885de29a4bSNico Weber }
4895de29a4bSNico Weber
Memset(void * dst,int val,int size,bool expect_race)4905de29a4bSNico Weber void ScopedThread::Memset(void *dst, int val, int size,
4915de29a4bSNico Weber bool expect_race) {
4925de29a4bSNico Weber Event event(Event::MEMSET, dst, val, size);
4935de29a4bSNico Weber if (expect_race)
494*a61c8e1eSYuanfang Chen event.ExpectReport(__tsan::ReportTypeRace);
4955de29a4bSNico Weber impl_->send(&event);
4965de29a4bSNico Weber }
497