#include "buffer.h" #include "platform.h" #include "utils.h" #include #include #include #include namespace { struct ScopedLockLocal : public ScopedLock { ScopedLockLocal(std::mutex& mutex) : guard(mutex) {} std::lock_guard guard; }; struct BufferLocal : public Buffer { explicit BufferLocal(size_t capacity) { this->data = malloc(capacity); this->capacity = capacity; } ~BufferLocal() override { free(data); data = nullptr; capacity = 0; } std::unique_ptr WaitForExclusiveAccess() override { return MakeUnique(mutex_); } std::mutex mutex_; }; struct ScopedLockPlatform : public ScopedLock { ScopedLockPlatform(PlatformMutex* mutex) : guard(CreatePlatformScopedMutexLock(mutex)) {} std::unique_ptr guard; }; struct BufferPlatform : public Buffer { explicit BufferPlatform(const std::string& name, size_t capacity) : memory_(CreatePlatformSharedMemory(name + "_mem", capacity)), mutex_(CreatePlatformMutex(name + "_mtx")) { this->data = memory_->data; this->capacity = memory_->capacity; } ~BufferPlatform() override { data = nullptr; capacity = 0; } std::unique_ptr WaitForExclusiveAccess() override { return MakeUnique(mutex_.get()); } std::unique_ptr memory_; std::unique_ptr mutex_; }; } // namespace std::unique_ptr Buffer::Create(size_t capacity) { return MakeUnique(capacity); } std::unique_ptr Buffer::CreateSharedBuffer(const std::string& name, size_t capacity) { return MakeUnique(name, capacity); } TEST_SUITE("BufferLocal"); TEST_CASE("create") { std::unique_ptr b = Buffer::Create(24); REQUIRE(b->data); REQUIRE(b->capacity == 24); b = Buffer::CreateSharedBuffer("indexertest", 24); REQUIRE(b->data); REQUIRE(b->capacity == 24); } TEST_CASE("lock") { auto buffers = {Buffer::Create(sizeof(int)), Buffer::CreateSharedBuffer("indexertest", sizeof(int))}; for (auto& b : buffers) { int* data = reinterpret_cast(b->data); *data = 0; std::unique_ptr thread; { auto lock = b->WaitForExclusiveAccess(); *data = 1; // Start a second thread, wait until it has attempted to acquire a lock. volatile bool did_read = false; thread = MakeUnique([&did_read, &b, &data]() { did_read = true; auto l = b->WaitForExclusiveAccess(); *data = 2; }); while (!did_read) std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // Verify lock acquisition is waiting. REQUIRE(*data == 1); } // Wait for thread to acquire lock, verify it writes to data. thread->join(); REQUIRE(*data == 2); } } TEST_SUITE_END();