mirror of
https://github.com/google/leveldb.git
synced 2025-02-10 07:30:09 +08:00
Fix tsan problem in env_test.
PiperOrigin-RevId: 268265314
This commit is contained in:
parent
21304d41f7
commit
60db170a43
102
util/env_test.cc
102
util/env_test.cc
@ -5,7 +5,6 @@
|
|||||||
#include "leveldb/env.h"
|
#include "leveldb/env.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include "port/port.h"
|
#include "port/port.h"
|
||||||
#include "port/thread_annotations.h"
|
#include "port/thread_annotations.h"
|
||||||
@ -24,16 +23,6 @@ class EnvTest {
|
|||||||
Env* env_;
|
Env* env_;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
static void SetAtomicBool(void* atomic_bool_ptr) {
|
|
||||||
std::atomic<bool>* atomic_bool =
|
|
||||||
reinterpret_cast<std::atomic<bool>*>(atomic_bool_ptr);
|
|
||||||
atomic_bool->store(true, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(EnvTest, ReadWrite) {
|
TEST(EnvTest, ReadWrite) {
|
||||||
Random rnd(test::RandomSeed());
|
Random rnd(test::RandomSeed());
|
||||||
|
|
||||||
@ -82,45 +71,73 @@ TEST(EnvTest, ReadWrite) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(EnvTest, RunImmediately) {
|
TEST(EnvTest, RunImmediately) {
|
||||||
std::atomic<bool> called(false);
|
struct RunState {
|
||||||
env_->Schedule(&SetAtomicBool, &called);
|
port::Mutex mu;
|
||||||
env_->SleepForMicroseconds(kDelayMicros);
|
port::CondVar cvar{&mu};
|
||||||
ASSERT_TRUE(called.load(std::memory_order_relaxed));
|
bool called = false;
|
||||||
}
|
|
||||||
|
|
||||||
TEST(EnvTest, RunMany) {
|
|
||||||
std::atomic<int> last_id(0);
|
|
||||||
|
|
||||||
struct Callback {
|
|
||||||
std::atomic<int>* const last_id_ptr_; // Pointer to shared state.
|
|
||||||
const int id_; // Order# for the execution of this callback.
|
|
||||||
|
|
||||||
Callback(std::atomic<int>* last_id_ptr, int id)
|
|
||||||
: last_id_ptr_(last_id_ptr), id_(id) {}
|
|
||||||
|
|
||||||
static void Run(void* arg) {
|
static void Run(void* arg) {
|
||||||
Callback* callback = reinterpret_cast<Callback*>(arg);
|
RunState* state = reinterpret_cast<RunState*>(arg);
|
||||||
int current_id = callback->last_id_ptr_->load(std::memory_order_relaxed);
|
MutexLock l(&state->mu);
|
||||||
ASSERT_EQ(callback->id_ - 1, current_id);
|
ASSERT_EQ(state->called, false);
|
||||||
callback->last_id_ptr_->store(callback->id_, std::memory_order_relaxed);
|
state->called = true;
|
||||||
|
state->cvar.Signal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Callback callback1(&last_id, 1);
|
RunState state;
|
||||||
Callback callback2(&last_id, 2);
|
env_->Schedule(&RunState::Run, &state);
|
||||||
Callback callback3(&last_id, 3);
|
|
||||||
Callback callback4(&last_id, 4);
|
MutexLock l(&state.mu);
|
||||||
|
while (!state.called) {
|
||||||
|
state.cvar.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EnvTest, RunMany) {
|
||||||
|
struct RunState {
|
||||||
|
port::Mutex mu;
|
||||||
|
port::CondVar cvar{&mu};
|
||||||
|
int last_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Callback {
|
||||||
|
RunState* state_; // Pointer to shared state.
|
||||||
|
const int id_; // Order# for the execution of this callback.
|
||||||
|
|
||||||
|
Callback(RunState* s, int id) : state_(s), id_(id) {}
|
||||||
|
|
||||||
|
static void Run(void* arg) {
|
||||||
|
Callback* callback = reinterpret_cast<Callback*>(arg);
|
||||||
|
RunState* state = callback->state_;
|
||||||
|
|
||||||
|
MutexLock l(&state->mu);
|
||||||
|
ASSERT_EQ(state->last_id, callback->id_ - 1);
|
||||||
|
state->last_id = callback->id_;
|
||||||
|
state->cvar.Signal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RunState state;
|
||||||
|
Callback callback1(&state, 1);
|
||||||
|
Callback callback2(&state, 2);
|
||||||
|
Callback callback3(&state, 3);
|
||||||
|
Callback callback4(&state, 4);
|
||||||
env_->Schedule(&Callback::Run, &callback1);
|
env_->Schedule(&Callback::Run, &callback1);
|
||||||
env_->Schedule(&Callback::Run, &callback2);
|
env_->Schedule(&Callback::Run, &callback2);
|
||||||
env_->Schedule(&Callback::Run, &callback3);
|
env_->Schedule(&Callback::Run, &callback3);
|
||||||
env_->Schedule(&Callback::Run, &callback4);
|
env_->Schedule(&Callback::Run, &callback4);
|
||||||
|
|
||||||
env_->SleepForMicroseconds(kDelayMicros);
|
MutexLock l(&state.mu);
|
||||||
ASSERT_EQ(4, last_id.load(std::memory_order_relaxed));
|
while (state.last_id != 4) {
|
||||||
|
state.cvar.Wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
port::Mutex mu;
|
port::Mutex mu;
|
||||||
|
port::CondVar cvar{&mu};
|
||||||
|
|
||||||
int val GUARDED_BY(mu);
|
int val GUARDED_BY(mu);
|
||||||
int num_running GUARDED_BY(mu);
|
int num_running GUARDED_BY(mu);
|
||||||
|
|
||||||
@ -132,6 +149,7 @@ static void ThreadBody(void* arg) {
|
|||||||
s->mu.Lock();
|
s->mu.Lock();
|
||||||
s->val += 1;
|
s->val += 1;
|
||||||
s->num_running -= 1;
|
s->num_running -= 1;
|
||||||
|
s->cvar.Signal();
|
||||||
s->mu.Unlock();
|
s->mu.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,17 +158,11 @@ TEST(EnvTest, StartThread) {
|
|||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
env_->StartThread(&ThreadBody, &state);
|
env_->StartThread(&ThreadBody, &state);
|
||||||
}
|
}
|
||||||
while (true) {
|
|
||||||
state.mu.Lock();
|
|
||||||
int num = state.num_running;
|
|
||||||
state.mu.Unlock();
|
|
||||||
if (num == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
env_->SleepForMicroseconds(kDelayMicros);
|
|
||||||
}
|
|
||||||
|
|
||||||
MutexLock l(&state.mu);
|
MutexLock l(&state.mu);
|
||||||
|
while (state.num_running != 0) {
|
||||||
|
state.cvar.Wait();
|
||||||
|
}
|
||||||
ASSERT_EQ(state.val, 3);
|
ASSERT_EQ(state.val, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user