1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
4
5 #include "leveldb/env.h"
6
7 #include "port/port.h"
8 #include "util/testharness.h"
9
10 namespace leveldb {
11
12 static const int kDelayMicros = 100000;
13 static const int kReadOnlyFileLimit = 4;
14 static const int kMMapLimit = 4;
15
16 class EnvTest {
17 private:
18 port::Mutex mu_;
19 std::string events_;
20
21 public:
22 Env* env_;
EnvTest()23 EnvTest() : env_(Env::Default()) { }
24 };
25
SetBool(void * ptr)26 static void SetBool(void* ptr) {
27 reinterpret_cast<port::AtomicPointer*>(ptr)->NoBarrier_Store(ptr);
28 }
29
TEST(EnvTest,RunImmediately)30 TEST(EnvTest, RunImmediately) {
31 port::AtomicPointer called (NULL);
32 env_->Schedule(&SetBool, &called);
33 env_->SleepForMicroseconds(kDelayMicros);
34 ASSERT_TRUE(called.NoBarrier_Load() != NULL);
35 }
36
TEST(EnvTest,RunMany)37 TEST(EnvTest, RunMany) {
38 port::AtomicPointer last_id (NULL);
39
40 struct CB {
41 port::AtomicPointer* last_id_ptr; // Pointer to shared slot
42 uintptr_t id; // Order# for the execution of this callback
43
44 CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { }
45
46 static void Run(void* v) {
47 CB* cb = reinterpret_cast<CB*>(v);
48 void* cur = cb->last_id_ptr->NoBarrier_Load();
49 ASSERT_EQ(cb->id-1, reinterpret_cast<uintptr_t>(cur));
50 cb->last_id_ptr->Release_Store(reinterpret_cast<void*>(cb->id));
51 }
52 };
53
54 // Schedule in different order than start time
55 CB cb1(&last_id, 1);
56 CB cb2(&last_id, 2);
57 CB cb3(&last_id, 3);
58 CB cb4(&last_id, 4);
59 env_->Schedule(&CB::Run, &cb1);
60 env_->Schedule(&CB::Run, &cb2);
61 env_->Schedule(&CB::Run, &cb3);
62 env_->Schedule(&CB::Run, &cb4);
63
64 env_->SleepForMicroseconds(kDelayMicros);
65 void* cur = last_id.Acquire_Load();
66 ASSERT_EQ(4, reinterpret_cast<uintptr_t>(cur));
67 }
68
69 struct State {
70 port::Mutex mu;
71 int val;
72 int num_running;
73 };
74
ThreadBody(void * arg)75 static void ThreadBody(void* arg) {
76 State* s = reinterpret_cast<State*>(arg);
77 s->mu.Lock();
78 s->val += 1;
79 s->num_running -= 1;
80 s->mu.Unlock();
81 }
82
TEST(EnvTest,StartThread)83 TEST(EnvTest, StartThread) {
84 State state;
85 state.val = 0;
86 state.num_running = 3;
87 for (int i = 0; i < 3; i++) {
88 env_->StartThread(&ThreadBody, &state);
89 }
90 while (true) {
91 state.mu.Lock();
92 int num = state.num_running;
93 state.mu.Unlock();
94 if (num == 0) {
95 break;
96 }
97 env_->SleepForMicroseconds(kDelayMicros);
98 }
99 ASSERT_EQ(state.val, 3);
100 }
101
102 } // namespace leveldb
103
main(int argc,char ** argv)104 int main(int argc, char** argv) {
105 return leveldb::test::RunAllTests();
106 }
107