base_tests.cpp 2.06 KB
Newer Older
1
#include <catch.hpp>
2

3 4
#include "pls/internal/base/spin_lock.h"
#include "pls/internal/base/system_details.h"
5 6 7
#include "pls/internal/base/stack_allocator.h"

#include "test_helpers.h"
8

9
#include <mutex>
10
#include <atomic>
11
#include <thread>
12 13 14

using namespace pls::internal::base;

15 16
int base_tests_shared_counter;

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
TEST_CASE("mmap stack allocator", "[internal/base/stack_allocator.h") {
  mmap_stack_allocator stack_allocator;

  char *stack = stack_allocator.allocate_stack(4096);

  SECTION("stack passes in valid range") {
    stack[0] = 'a';
    stack[4096 - 1] = 'a';

    REQUIRE(true);
  }

  SECTION("guard page sigsev on overflow") {
    REQUIRE(CHECK_ABORT([&]() { stack[-10] = 'a'; }));
  }

  stack_allocator.free_stack(4096, stack);

  SECTION("stack unmaps after free") {
    REQUIRE(CHECK_ABORT([&]() { stack[0] = 'a'; }));
  }
}

40
TEST_CASE("spinlock protects concurrent counter", "[internal/data_structures/spinlock.h]") {
41
  constexpr int num_iterations = 10000;
42
  base_tests_shared_counter = 0;
43 44
  std::atomic<int> barrier{2};

45 46 47
  spin_lock lock{};

  SECTION("lock can be used by itself") {
48
    std::thread t1{[&]() {
49 50 51
      barrier--;
      while (barrier != 0);

52 53 54 55 56
      for (int i = 0; i < num_iterations; i++) {
        lock.lock();
        base_tests_shared_counter++;
        lock.unlock();
      }
57
    }};
58
    std::thread t2{[&]() {
59 60 61
      barrier--;
      while(barrier != 0);

62 63 64 65 66
      for (int i = 0; i < num_iterations; i++) {
        lock.lock();
        base_tests_shared_counter--;
        lock.unlock();
      }
67
    }};
68 69 70 71 72 73 74 75

    t1.join();
    t2.join();

    REQUIRE(base_tests_shared_counter == 0);
  }

  SECTION("lock can be used with std::lock_guard") {
76
    std::thread t1{[&]() {
77 78 79 80
      for (int i = 0; i < num_iterations; i++) {
        std::lock_guard<spin_lock> my_lock{lock};
        base_tests_shared_counter++;
      }
81
    }};
82
    std::thread t2{[&]() {
83 84 85 86
      for (int i = 0; i < num_iterations; i++) {
        std::lock_guard<spin_lock> my_lock{lock};
        base_tests_shared_counter--;
      }
87
    }};
88 89 90 91 92 93

    t1.join();
    t2.join();

    REQUIRE(base_tests_shared_counter == 0);
  }
94
}