Home | History | Annotate | Download | only in util
      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