summaryrefslogtreecommitdiffstats
path: root/src/test/simple_spin.cc
blob: 4afa670743e8a39183399b2fca7b517e63d62e6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <future>

#include "gtest/gtest.h"

#include "include/spinlock.h"

using ceph::spin_lock;
using ceph::spin_unlock;

static std::atomic_flag lock = ATOMIC_FLAG_INIT;
static int64_t counter = 0;

TEST(SimpleSpin, Test0)
{
  std::atomic_flag lock0 = ATOMIC_FLAG_INIT;
  spin_lock(&lock0);
  spin_unlock(&lock0);
}

static void* mythread(void *v)
{
  for (int j = 0; j < 1000000; ++j) {
    spin_lock(&lock);
    counter++;
    spin_unlock(&lock);
  }
  return NULL;
}

TEST(SimpleSpin, Test1)
{
  counter = 0;
  const auto n = 2000000U;

  int ret;
  pthread_t thread1;
  pthread_t thread2;
  ret = pthread_create(&thread1, NULL, mythread, NULL);
  ASSERT_EQ(0, ret);
  ret = pthread_create(&thread2, NULL, mythread, NULL);
  ASSERT_EQ(0, ret);
  ret = pthread_join(thread1, NULL);
  ASSERT_EQ(0, ret);
  ret = pthread_join(thread2, NULL);
  ASSERT_EQ(0, ret);
  ASSERT_EQ(n, counter);

  // Should also work with pass-by-reference:
  // (Note that we don't care about cross-threading here as-such.)
  counter = 0;
  auto f = async(std::launch::async, []() {
        for(int i = 0; n != i; ++i) {
            spin_lock(lock);
            counter++;
            spin_unlock(lock);
        }
       });
  f.wait();
  ASSERT_EQ(n, counter);
}

template <typename LockT>
int64_t check_lock_unlock(const int64_t n, int64_t& cntr, LockT& lock)
{
 auto do_lock_unlock = [&]() -> int64_t {
        int64_t i = 0;

        for(; n != i; ++i) {
           spin_lock(lock);
           cntr++;
           spin_unlock(lock);
        }

        return i;
      };

 auto fone   = async(std::launch::async, do_lock_unlock);
 auto ftwo   = async(std::launch::async, do_lock_unlock);
 auto fthree = async(std::launch::async, do_lock_unlock);

 auto one = fone.get();
 auto two = ftwo.get();
 auto three = fthree.get();

 // Google test doesn't like us using its macros out of individual tests, so:
 if(n != one || n != two || n != three)
  return 0;

 return one + two + three;
}

TEST(SimpleSpin, Test2)
{
 const auto n = 2000000U;

 // ceph::spinlock:
 {
 counter = 0;
 ceph::spinlock l;

 ASSERT_EQ(0, counter);
 auto result = check_lock_unlock(n, counter, l);
 ASSERT_NE(0, counter);
 ASSERT_EQ(counter, result);
 }
}

// ceph::spinlock should work with std::lock_guard<>:
TEST(SimpleSpin, spinlock_guard)
{
  const auto n = 2000000U;

  ceph::spinlock sl;

  counter = 0;
  auto f = async(std::launch::async, [&sl]() {
        for(int i = 0; n != i; ++i) {
            std::lock_guard<ceph::spinlock> g(sl);
            counter++;
        }
       });

  auto g = async(std::launch::async, [&sl]() {
        for(int i = 0; n != i; ++i) {
            std::lock_guard<ceph::spinlock> g(sl);
            counter++;
        }
       });

  f.wait();
  g.wait();
  ASSERT_EQ(2*n, counter);
}