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 14 class EnvPosixTest { 15 private: 16 port::Mutex mu_; 17 std::string events_; 18 19 public: 20 Env* env_; 21 EnvPosixTest() : env_(Env::Default()) { } 22 }; 23 24 static void SetBool(void* ptr) { 25 reinterpret_cast<port::AtomicPointer*>(ptr)->NoBarrier_Store(ptr); 26 } 27 28 TEST(EnvPosixTest, RunImmediately) { 29 port::AtomicPointer called (NULL); 30 env_->Schedule(&SetBool, &called); 31 Env::Default()->SleepForMicroseconds(kDelayMicros); 32 ASSERT_TRUE(called.NoBarrier_Load() != NULL); 33 } 34 35 TEST(EnvPosixTest, RunMany) { 36 port::AtomicPointer last_id (NULL); 37 38 struct CB { 39 port::AtomicPointer* last_id_ptr; // Pointer to shared slot 40 uintptr_t id; // Order# for the execution of this callback 41 42 CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } 43 44 static void Run(void* v) { 45 CB* cb = reinterpret_cast<CB*>(v); 46 void* cur = cb->last_id_ptr->NoBarrier_Load(); 47 ASSERT_EQ(cb->id-1, reinterpret_cast<uintptr_t>(cur)); 48 cb->last_id_ptr->Release_Store(reinterpret_cast<void*>(cb->id)); 49 } 50 }; 51 52 // Schedule in different order than start time 53 CB cb1(&last_id, 1); 54 CB cb2(&last_id, 2); 55 CB cb3(&last_id, 3); 56 CB cb4(&last_id, 4); 57 env_->Schedule(&CB::Run, &cb1); 58 env_->Schedule(&CB::Run, &cb2); 59 env_->Schedule(&CB::Run, &cb3); 60 env_->Schedule(&CB::Run, &cb4); 61 62 Env::Default()->SleepForMicroseconds(kDelayMicros); 63 void* cur = last_id.Acquire_Load(); 64 ASSERT_EQ(4, reinterpret_cast<uintptr_t>(cur)); 65 } 66 67 struct State { 68 port::Mutex mu; 69 int val; 70 int num_running; 71 }; 72 73 static void ThreadBody(void* arg) { 74 State* s = reinterpret_cast<State*>(arg); 75 s->mu.Lock(); 76 s->val += 1; 77 s->num_running -= 1; 78 s->mu.Unlock(); 79 } 80 81 TEST(EnvPosixTest, StartThread) { 82 State state; 83 state.val = 0; 84 state.num_running = 3; 85 for (int i = 0; i < 3; i++) { 86 env_->StartThread(&ThreadBody, &state); 87 } 88 while (true) { 89 state.mu.Lock(); 90 int num = state.num_running; 91 state.mu.Unlock(); 92 if (num == 0) { 93 break; 94 } 95 Env::Default()->SleepForMicroseconds(kDelayMicros); 96 } 97 ASSERT_EQ(state.val, 3); 98 } 99 100 } // namespace leveldb 101 102 int main(int argc, char** argv) { 103 return leveldb::test::RunAllTests(); 104 } 105