Implement pthread barrier.

Bug: 24341262
Change-Id: I5472549e5d7545c1c3f0bef78235f545557b9630
This commit is contained in:
Yabin Cui
2015-11-05 22:06:09 -08:00
parent 004fead6bc
commit e7c2fffa16
11 changed files with 373 additions and 5 deletions

View File

@@ -721,11 +721,11 @@ TEST(pthread, pthread_rwlock_smoke) {
ASSERT_EQ(0, pthread_rwlock_destroy(&l));
}
static void WaitUntilThreadSleep(std::atomic<pid_t>& pid) {
while (pid == 0) {
static void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
while (tid == 0) {
usleep(1000);
}
std::string filename = android::base::StringPrintf("/proc/%d/stat", pid.load());
std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
std::regex regex {R"(\s+S\s+)"};
while (true) {
@@ -1653,3 +1653,117 @@ TEST(pthread, big_enough_signal_stack_for_64bit_arch) {
kill(getpid(), SIGUSR1);
ASSERT_TRUE(signal_handler_on_altstack_done);
}
TEST(pthread, pthread_barrierattr_smoke) {
pthread_barrierattr_t attr;
ASSERT_EQ(0, pthread_barrierattr_init(&attr));
int pshared;
ASSERT_EQ(0, pthread_barrierattr_getpshared(&attr, &pshared));
ASSERT_EQ(PTHREAD_PROCESS_PRIVATE, pshared);
ASSERT_EQ(0, pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
ASSERT_EQ(0, pthread_barrierattr_getpshared(&attr, &pshared));
ASSERT_EQ(PTHREAD_PROCESS_SHARED, pshared);
ASSERT_EQ(0, pthread_barrierattr_destroy(&attr));
}
struct BarrierTestHelperArg {
std::atomic<pid_t> tid;
pthread_barrier_t* barrier;
size_t iteration_count;
};
static void BarrierTestHelper(BarrierTestHelperArg* arg) {
arg->tid = gettid();
for (size_t i = 0; i < arg->iteration_count; ++i) {
ASSERT_EQ(0, pthread_barrier_wait(arg->barrier));
}
}
TEST(pthread, pthread_barrier_smoke) {
const size_t BARRIER_ITERATION_COUNT = 10;
const size_t BARRIER_THREAD_COUNT = 10;
pthread_barrier_t barrier;
ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, BARRIER_THREAD_COUNT + 1));
std::vector<pthread_t> threads(BARRIER_THREAD_COUNT);
std::vector<BarrierTestHelperArg> args(threads.size());
for (size_t i = 0; i < threads.size(); ++i) {
args[i].tid = 0;
args[i].barrier = &barrier;
args[i].iteration_count = BARRIER_ITERATION_COUNT;
ASSERT_EQ(0, pthread_create(&threads[i], nullptr,
reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &args[i]));
}
for (size_t iteration = 0; iteration < BARRIER_ITERATION_COUNT; ++iteration) {
for (size_t i = 0; i < threads.size(); ++i) {
WaitUntilThreadSleep(args[i].tid);
}
ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));
}
for (size_t i = 0; i < threads.size(); ++i) {
ASSERT_EQ(0, pthread_join(threads[i], nullptr));
}
ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
}
TEST(pthread, pthread_barrier_destroy) {
pthread_barrier_t barrier;
ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, 2));
pthread_t thread;
BarrierTestHelperArg arg;
arg.tid = 0;
arg.barrier = &barrier;
arg.iteration_count = 1;
ASSERT_EQ(0, pthread_create(&thread, nullptr,
reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &arg));
WaitUntilThreadSleep(arg.tid);
ASSERT_EQ(EBUSY, pthread_barrier_destroy(&barrier));
ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));
// Verify if the barrier can be destroyed directly after pthread_barrier_wait().
ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
ASSERT_EQ(0, pthread_join(thread, nullptr));
#if defined(__BIONIC__)
ASSERT_EQ(EINVAL, pthread_barrier_destroy(&barrier));
#endif
}
struct BarrierOrderingTestHelperArg {
pthread_barrier_t* barrier;
size_t* array;
size_t array_length;
size_t id;
};
void BarrierOrderingTestHelper(BarrierOrderingTestHelperArg* arg) {
const size_t ITERATION_COUNT = 10000;
for (size_t i = 1; i <= ITERATION_COUNT; ++i) {
arg->array[arg->id] = i;
int ret = pthread_barrier_wait(arg->barrier);
ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
for (size_t j = 0; j < arg->array_length; ++j) {
ASSERT_EQ(i, arg->array[j]);
}
ret = pthread_barrier_wait(arg->barrier);
ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
}
}
TEST(pthread, pthread_barrier_check_ordering) {
const size_t THREAD_COUNT = 4;
pthread_barrier_t barrier;
ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, THREAD_COUNT));
size_t array[THREAD_COUNT];
std::vector<pthread_t> threads(THREAD_COUNT);
std::vector<BarrierOrderingTestHelperArg> args(THREAD_COUNT);
for (size_t i = 0; i < THREAD_COUNT; ++i) {
args[i].barrier = &barrier;
args[i].array = array;
args[i].array_length = THREAD_COUNT;
args[i].id = i;
ASSERT_EQ(0, pthread_create(&threads[i], nullptr,
reinterpret_cast<void* (*)(void*)>(BarrierOrderingTestHelper),
&args[i]));
}
for (size_t i = 0; i < THREAD_COUNT; ++i) {
ASSERT_EQ(0, pthread_join(threads[i], nullptr));
}
}