Implement pthread barrier.
Bug: 24341262 Change-Id: I5472549e5d7545c1c3f0bef78235f545557b9630
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user