forked from OSchip/llvm-project
147 lines
4.0 KiB
C++
147 lines
4.0 KiB
C++
//===-- tsan_posix.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.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "tsan_interface.h"
|
|
#include "tsan_test_util.h"
|
|
#include "gtest/gtest.h"
|
|
#include <pthread.h>
|
|
|
|
struct thread_key {
|
|
pthread_key_t key;
|
|
pthread_mutex_t *mtx;
|
|
int val;
|
|
int *cnt;
|
|
thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt)
|
|
: key(key)
|
|
, mtx(mtx)
|
|
, val(val)
|
|
, cnt(cnt) {
|
|
}
|
|
};
|
|
|
|
static void thread_secific_dtor(void *v) {
|
|
thread_key *k = (thread_key *)v;
|
|
EXPECT_EQ(pthread_mutex_lock(k->mtx), 0);
|
|
(*k->cnt)++;
|
|
__tsan_write4(&k->cnt);
|
|
EXPECT_EQ(pthread_mutex_unlock(k->mtx), 0);
|
|
if (k->val == 42) {
|
|
delete k;
|
|
} else if (k->val == 43 || k->val == 44) {
|
|
k->val--;
|
|
EXPECT_EQ(pthread_setspecific(k->key, k), 0);
|
|
} else {
|
|
ASSERT_TRUE(false);
|
|
}
|
|
}
|
|
|
|
static void *dtors_thread(void *p) {
|
|
thread_key *k = (thread_key *)p;
|
|
EXPECT_EQ(pthread_setspecific(k->key, k), 0);
|
|
return 0;
|
|
}
|
|
|
|
TEST(Posix, ThreadSpecificDtors) {
|
|
int cnt = 0;
|
|
pthread_key_t key;
|
|
EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0);
|
|
pthread_mutex_t mtx;
|
|
EXPECT_EQ(pthread_mutex_init(&mtx, 0), 0);
|
|
pthread_t th[3];
|
|
thread_key *k[3];
|
|
k[0] = new thread_key(key, &mtx, 42, &cnt);
|
|
k[1] = new thread_key(key, &mtx, 43, &cnt);
|
|
k[2] = new thread_key(key, &mtx, 44, &cnt);
|
|
EXPECT_EQ(pthread_create(&th[0], 0, dtors_thread, k[0]), 0);
|
|
EXPECT_EQ(pthread_create(&th[1], 0, dtors_thread, k[1]), 0);
|
|
EXPECT_EQ(pthread_join(th[0], 0), 0);
|
|
EXPECT_EQ(pthread_create(&th[2], 0, dtors_thread, k[2]), 0);
|
|
EXPECT_EQ(pthread_join(th[1], 0), 0);
|
|
EXPECT_EQ(pthread_join(th[2], 0), 0);
|
|
EXPECT_EQ(pthread_key_delete(key), 0);
|
|
EXPECT_EQ(6, cnt);
|
|
}
|
|
|
|
static __thread int local_var;
|
|
|
|
static void *local_thread(void *p) {
|
|
__tsan_write1(&local_var);
|
|
__tsan_write1(&p);
|
|
if (p == 0)
|
|
return 0;
|
|
const int kThreads = 4;
|
|
pthread_t th[kThreads];
|
|
for (int i = 0; i < kThreads; i++)
|
|
EXPECT_EQ(pthread_create(&th[i], 0, local_thread,
|
|
(void*)((long)p - 1)), 0); // NOLINT
|
|
for (int i = 0; i < kThreads; i++)
|
|
EXPECT_EQ(pthread_join(th[i], 0), 0);
|
|
return 0;
|
|
}
|
|
|
|
TEST(Posix, ThreadLocalAccesses) {
|
|
local_thread((void*)2);
|
|
}
|
|
|
|
struct CondContext {
|
|
pthread_mutex_t m;
|
|
pthread_cond_t c;
|
|
int data;
|
|
};
|
|
|
|
static void *cond_thread(void *p) {
|
|
CondContext &ctx = *static_cast<CondContext*>(p);
|
|
|
|
EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
|
|
EXPECT_EQ(ctx.data, 0);
|
|
ctx.data = 1;
|
|
EXPECT_EQ(pthread_cond_signal(&ctx.c), 0);
|
|
EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
|
|
|
|
EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
|
|
while (ctx.data != 2)
|
|
EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
|
|
EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
|
|
|
|
EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
|
|
ctx.data = 3;
|
|
EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
|
|
EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
TEST(Posix, CondBasic) {
|
|
CondContext ctx;
|
|
EXPECT_EQ(pthread_mutex_init(&ctx.m, 0), 0);
|
|
EXPECT_EQ(pthread_cond_init(&ctx.c, 0), 0);
|
|
ctx.data = 0;
|
|
pthread_t th;
|
|
EXPECT_EQ(pthread_create(&th, 0, cond_thread, &ctx), 0);
|
|
|
|
EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
|
|
while (ctx.data != 1)
|
|
EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
|
|
ctx.data = 2;
|
|
EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
|
|
EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
|
|
|
|
EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
|
|
while (ctx.data != 3)
|
|
EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
|
|
EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
|
|
|
|
EXPECT_EQ(pthread_join(th, 0), 0);
|
|
EXPECT_EQ(pthread_cond_destroy(&ctx.c), 0);
|
|
EXPECT_EQ(pthread_mutex_destroy(&ctx.m), 0);
|
|
}
|