brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.8 KiB · d482dcc Raw
197 lines · cpp
1//===-- Tests for pthread_mutex_t -----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "hdr/stdint_proxy.h" // uintptr_t10#include "src/pthread/pthread_create.h"11#include "src/pthread/pthread_join.h"12#include "src/pthread/pthread_mutex_destroy.h"13#include "src/pthread/pthread_mutex_init.h"14#include "src/pthread/pthread_mutex_lock.h"15#include "src/pthread/pthread_mutex_unlock.h"16#include "test/IntegrationTest/test.h"17 18#include <pthread.h>19 20constexpr int START = 0;21constexpr int MAX = 10000;22 23pthread_mutex_t mutex;24static int shared_int = START;25 26void *counter([[maybe_unused]] void *arg) {27  int last_count = START;28  while (true) {29    LIBC_NAMESPACE::pthread_mutex_lock(&mutex);30    if (shared_int == last_count + 1) {31      shared_int++;32      last_count = shared_int;33    }34    LIBC_NAMESPACE::pthread_mutex_unlock(&mutex);35    if (last_count >= MAX)36      break;37  }38  return nullptr;39}40 41void relay_counter() {42  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex, nullptr), 0);43 44  // The idea of this test is that two competing threads will update45  // a counter only if the other thread has updated it.46  pthread_t thread;47  LIBC_NAMESPACE::pthread_create(&thread, nullptr, counter, nullptr);48 49  int last_count = START;50  while (true) {51    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex), 0);52    if (shared_int == START) {53      ++shared_int;54      last_count = shared_int;55    } else if (shared_int != last_count) {56      ASSERT_EQ(shared_int, last_count + 1);57      ++shared_int;58      last_count = shared_int;59    }60    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex), 0);61    if (last_count > MAX)62      break;63  }64 65  void *retval = reinterpret_cast<void *>(123);66  LIBC_NAMESPACE::pthread_join(thread, &retval);67  ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));68 69  LIBC_NAMESPACE::pthread_mutex_destroy(&mutex);70}71 72pthread_mutex_t start_lock, step_lock;73bool started, step;74 75void *stepper([[maybe_unused]] void *arg) {76  LIBC_NAMESPACE::pthread_mutex_lock(&start_lock);77  started = true;78  LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock);79 80  LIBC_NAMESPACE::pthread_mutex_lock(&step_lock);81  step = true;82  LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock);83  return nullptr;84}85 86void wait_and_step() {87  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&start_lock, nullptr), 0);88  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&step_lock, nullptr), 0);89 90  // In this test, we start a new thread but block it before it can make a91  // step. Once we ensure that the thread is blocked, we unblock it.92  // After unblocking, we then verify that the thread was indeed unblocked.93  step = false;94  started = false;95  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);96 97  pthread_t thread;98  LIBC_NAMESPACE::pthread_create(&thread, nullptr, stepper, nullptr);99 100  while (true) {101    // Make sure the thread actually started.102    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&start_lock), 0);103    bool s = started;104    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&start_lock), 0);105    if (s)106      break;107  }108 109  // Since |step_lock| is still locked, |step| should be false.110  ASSERT_FALSE(step);111 112  // Unlock the step lock and wait until the step is made.113  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);114 115  while (true) {116    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&step_lock), 0);117    bool current_step_value = step;118    ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&step_lock), 0);119    if (current_step_value)120      break;121  }122 123  void *retval = reinterpret_cast<void *>(123);124  LIBC_NAMESPACE::pthread_join(thread, &retval);125  ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));126 127  LIBC_NAMESPACE::pthread_mutex_destroy(&start_lock);128  LIBC_NAMESPACE::pthread_mutex_destroy(&step_lock);129}130 131static constexpr int THREAD_COUNT = 10;132static pthread_mutex_t multiple_waiter_lock;133static pthread_mutex_t counter_lock;134static int wait_count = 0;135 136void *waiter_func(void *) {137  LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);138  ++wait_count;139  LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);140 141  // Block on the waiter lock until the main142  // thread unblocks.143  LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);144  LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);145 146  LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);147  --wait_count;148  LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);149 150  return nullptr;151}152 153void multiple_waiters() {154  LIBC_NAMESPACE::pthread_mutex_init(&multiple_waiter_lock, nullptr);155  LIBC_NAMESPACE::pthread_mutex_init(&counter_lock, nullptr);156 157  LIBC_NAMESPACE::pthread_mutex_lock(&multiple_waiter_lock);158  pthread_t waiters[THREAD_COUNT];159  for (int i = 0; i < THREAD_COUNT; ++i) {160    LIBC_NAMESPACE::pthread_create(waiters + i, nullptr, waiter_func, nullptr);161  }162 163  // Spin until the counter is incremented to the desired164  // value.165  while (true) {166    LIBC_NAMESPACE::pthread_mutex_lock(&counter_lock);167    if (wait_count == THREAD_COUNT) {168      LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);169      break;170    }171    LIBC_NAMESPACE::pthread_mutex_unlock(&counter_lock);172  }173 174  LIBC_NAMESPACE::pthread_mutex_unlock(&multiple_waiter_lock);175 176  void *retval;177  for (int i = 0; i < THREAD_COUNT; ++i) {178    LIBC_NAMESPACE::pthread_join(waiters[i], &retval);179  }180 181  ASSERT_EQ(wait_count, 0);182 183  LIBC_NAMESPACE::pthread_mutex_destroy(&multiple_waiter_lock);184  LIBC_NAMESPACE::pthread_mutex_destroy(&counter_lock);185}186 187// Test the initializer188[[maybe_unused]]189static pthread_mutex_t test_initializer = PTHREAD_MUTEX_INITIALIZER;190 191TEST_MAIN() {192  relay_counter();193  wait_and_step();194  multiple_waiters();195  return 0;196}197