blob: d0cd704e18547ccb2390c8f5ade575bbf4184735 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "peridot/bin/ledger/lock/lock.h"
#include <lib/fit/function.h>
#include "gtest/gtest.h"
#include "peridot/bin/ledger/coroutine/coroutine_impl.h"
namespace lock {
namespace {
size_t Fact(size_t n) {
if (n == 0) {
return 1;
}
return Fact(n - 1) * n;
}
void UseStack() { EXPECT_EQ(120u, Fact(5)); }
TEST(Lock, OneLock) {
coroutine::CoroutineServiceImpl coroutine_service;
callback::OperationSerializer serializer;
fit::function<void(size_t)> callback;
auto callable = [&callback](fit::function<void(size_t)> called_callback) {
callback = std::move(called_callback);
};
size_t received_value = 0;
size_t other_value = 0;
coroutine_service.StartCoroutine([&serializer, callable, &received_value](
coroutine::CoroutineHandler* handler) {
std::unique_ptr<Lock> lock;
EXPECT_EQ(coroutine::ContinuationStatus::OK,
AcquireLock(handler, &serializer, &lock));
UseStack();
size_t value;
EXPECT_EQ(coroutine::ContinuationStatus::OK,
SyncCall(handler, callable, &value));
UseStack();
received_value = value;
});
EXPECT_TRUE(callback);
EXPECT_EQ(0u, received_value);
EXPECT_EQ(0u, other_value);
serializer.Serialize<>([&other_value] { other_value = 1u; },
[](fit::closure closure) { closure(); });
EXPECT_EQ(0u, other_value);
callback(1);
EXPECT_EQ(1u, received_value);
EXPECT_EQ(1u, other_value);
}
TEST(Lock, ManyLocks) {
constexpr size_t nb_routines = 10;
coroutine::CoroutineServiceImpl coroutine_service;
callback::OperationSerializer serializer;
std::queue<fit::function<void(size_t)>> callbacks;
std::vector<size_t> received_values;
for (size_t i = 0; i < nb_routines; i++) {
auto callable = [&callbacks](fit::function<void(size_t)> called_callback) {
callbacks.push(std::move(called_callback));
};
coroutine_service.StartCoroutine([&serializer, callable, &received_values](
coroutine::CoroutineHandler* handler) {
std::unique_ptr<Lock> lock;
EXPECT_EQ(coroutine::ContinuationStatus::OK,
AcquireLock(handler, &serializer, &lock));
UseStack();
size_t value;
EXPECT_EQ(coroutine::ContinuationStatus::OK,
SyncCall(handler, callable, &value));
UseStack();
received_values.push_back(value);
});
}
for (size_t i = 0; i < nb_routines; i++) {
EXPECT_EQ(1u, callbacks.size());
EXPECT_EQ(i, received_values.size());
callbacks.front()(i);
callbacks.pop();
EXPECT_EQ(i, *received_values.rbegin());
}
EXPECT_EQ(nb_routines, received_values.size());
}
TEST(Lock, Interrupted) {
callback::OperationSerializer serializer;
coroutine::CoroutineHandler* handler_ptr = nullptr;
fit::function<void()> callback;
auto callable = [&callback](fit::function<void()> called_callback) {
callback = std::move(called_callback);
};
serializer.Serialize<>([] {}, callable);
bool executed = false;
{
coroutine::CoroutineServiceImpl coroutine_service;
coroutine_service.StartCoroutine([&serializer, &executed, &handler_ptr](
coroutine::CoroutineHandler* handler) {
handler_ptr = handler;
std::unique_ptr<Lock> lock;
// We are interrupted.
EXPECT_EQ(coroutine::ContinuationStatus::INTERRUPTED,
AcquireLock(handler, &serializer, &lock));
executed = true;
return;
});
EXPECT_TRUE(callback);
EXPECT_FALSE(executed);
}
EXPECT_TRUE(executed);
callback();
callback = nullptr;
serializer.Serialize<>([] {}, callable);
EXPECT_TRUE(callback);
}
} // namespace
} // namespace lock