Compare commits

...

2 Commits

Author SHA1 Message Date
tqcq
76595be62a feat update
Some checks failed
ci/pr/linux-aarch64-gcc/1 Pipeline failed
ci/pr/linux-aarch64-gcc/2 Pipeline failed
ci/pr/linux-x64-gcc/1 Pipeline failed
ci/pr/linux-x64-gcc/2 Pipeline failed
ci/pull_request_closed/linux-aarch64-gcc/1 Pipeline failed
ci/pull_request_closed/linux-aarch64-gcc/2 Pipeline failed
ci/pull_request_closed/linux-x64-gcc/1 Pipeline failed
ci/pull_request_closed/linux-x64-gcc/2 Pipeline failed
ci/push/linux-aarch64-gcc/1 Pipeline failed
ci/push/linux-x64-gcc/1 Pipeline failed
ci/push/linux-aarch64-gcc/2 Pipeline failed
ci/push/linux-x64-gcc/2 Pipeline failed
2024-08-13 23:24:09 +08:00
tqcq
923eba7037 feat update cmake 2024-08-13 23:09:49 +08:00
23 changed files with 62 additions and 801 deletions

View File

@ -9,7 +9,7 @@ if (NOT tile_VERSION_BUILD)
endif() endif()
project( project(
tile tile
VERSION ${tile_VERSION_MAJOR}.${tile_VERSION_MINOR}.${tile_VERSION_PATCH}.${tile_VERSION_BUILD} VERSION "${tile_VERSION_MAJOR}.${tile_VERSION_MINOR}.${tile_VERSION_PATCH}"
LANGUAGES C CXX) LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
@ -24,9 +24,6 @@ option(TILE_WITH_OPENSSL "Build with openssl" OFF)
option(TILE_BUILD_SHARED "Build shared library" ON) option(TILE_BUILD_SHARED "Build shared library" ON)
option(TILE_BUILD_STATIC "Build static library" ON) option(TILE_BUILD_STATIC "Build static library" ON)
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "time")
# set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "time")
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(TILE_BUILD_TESTS ON) set(TILE_BUILD_TESTS ON)
set(TILE_BUILD_BENCHMARKS ON) set(TILE_BUILD_BENCHMARKS ON)
@ -210,9 +207,9 @@ set(TILE_SRCS
"tile/rpc/protocol/http/buffer_io.cc" "tile/rpc/protocol/http/buffer_io.cc"
"tile/rpc/protocol/message.cc" "tile/rpc/protocol/message.cc"
# "tile/rpc/server.cc" # "tile/rpc/server.cc"
"tile/util/config.cc" "tile/base/config/config.cc"
"tile/util/ini_file_config.cc" "tile/base/config/ini_file_config.cc"
"tile/util/layered_config.cc" "tile/base/config/layered_config.cc"
) )
if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS)) if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS))
@ -295,82 +292,30 @@ if(TILE_BUILD_TESTS)
add_test(NAME ${test_name} COMMAND ${test_name}) add_test(NAME ${test_name} COMMAND ${test_name})
endmacro() endmacro()
tile_add_test(io_util_rate_limiter_test "tile/io/util/rate_limiter_test.cc") function(add_test_group prefix group_name)
tile_add_test(base_exposed_var_test "tile/base/exposed_var_test.cc") file(GLOB_RECURSE TEST_FILES "${prefix}/**/*_test.cc")
tile_add_test(base_byte_order_test "tile/base/byte_order_test.cc") foreach(SRC_FILE ${TEST_FILES})
# tile_add_test(fiber_detail_scheduler_test "tile/fiber/detail/scheduler_test.cc") if(IS_DIRECTORY ${SRC_FILE})
tile_add_test(base_internal_meta_test "tile/base/internal/meta_test.cc") continue()
# tile_add_test(net_internal_http_engine_test endif()
# "tile/net/internal/http_engine_test.cc") # convert to relative path message(STATUS "${prefix} -> ${TEST_FILE}")
tile_add_test(net_internal_http_task_test file(RELATIVE_PATH TEST_NAME "${prefix}" "${SRC_FILE}")
"tile/net/internal/http_task_test.cc") string(REPLACE "/" "_" TEST_NAME "${TEST_NAME}")
tile_add_test(net_http_http_client_test "tile/net/http/http_client_test.cc") # if group_name is not empty, add suffix _
tile_add_test(net_http_http_request_test "tile/net/http/http_reqeust_test.cc") if (NOT group_name STREQUAL "")
tile_add_test(net_http_http_response_test set(TEST_NAME "${group_name}_${TEST_NAME}")
"tile/net/http/http_response_test.cc") endif()
tile_add_test(base_compression_util_test "tile/base/compression/util_test.cc")
tile_add_test(rpc_protocol_http_buffer_io_test
"tile/rpc/protocol/http/buffer_io_test.cc")
tile_add_test(base_compression_test "tile/base/compression_test.cc") tile_add_test(${TEST_NAME} ${SRC_FILE})
tile_add_test(base_casting_test "tile/base/casting_test.cc") endforeach()
tile_add_test(base_future_future_test "tile/base/future/future_test.cc") endfunction(add_test_group)
tile_add_test(base_future_boxed_test "tile/base/future/boxed_test.cc")
tile_add_test(base_option_option_service_test
"tile/base/option/option_service_test.cc")
tile_add_test(base_ref_ptr_test "tile/base/ref_ptr_test.cc")
tile_add_test(base_object_pool_disabled_test
"tile/base/object_pool/disabled_test.cc")
tile_add_test(base_object_pool_types_test
"tile/base/object_pool/types_test.cc")
tile_add_test(base_string_test "tile/base/string_test.cc")
tile_add_test(base_deferred_test "tile/base/deferred_test.cc")
tile_add_test(base_internal_singly_linked_list_test
"tile/base/internal/singly_linked_list_test.cc")
tile_add_test(base_internal_move_on_copy_test
"tile/base/internal/move_on_copy_test.cc")
tile_add_test(base_internal_thread_pool_test
"tile/base/internal/thread_pool_test.cc")
tile_add_test(base_internal_format_test "tile/base/internal/format_test.cc")
tile_add_test(base_internal_background_task_host_test
"tile/base/internal/background_task_host_test.cc")
tile_add_test(base_down_cast_test "tile/base/down_cast_test.cc")
tile_add_test(base_encoding_hex_test "tile/base/encoding/hex_test.cc")
tile_add_test(base_encoding_percent_test "tile/base/encoding/percent_test.cc")
tile_add_test(base_encoding_base64_test "tile/base/encoding/base64_test.cc")
tile_add_test(base_internal_case_insensitive_hash_map_test
"tile/base/internal/case_insensitive_hash_map_test.cc")
tile_add_test(net_http_http_headers_test "tile/net/http/http_headers_test.cc")
tile_add_test(base_demangle_test "tile/base/demangle_test.cc")
tile_add_test(base_option_json_parser_test
"tile/base/option/json_parser_test.cc")
tile_add_test(base_option_key_test "tile/base/option/key_test.cc")
tile_add_test(base_dependency_registry_test
"tile/base/dependency_registry_test.cc")
tile_add_test(base_maybe_owning_test "tile/base/maybe_owning_test.cc")
tile_add_test(base_status_test "tile/base/status_test.cc")
tile_add_test(base_net_endpoint_test "tile/base/net/endpoint_test.cc")
tile_add_test(base_handle_test "tile/base/handle_test.cc")
tile_add_test(base_thread_scoped_lock_test
"tile/base/thread/scoped_lock_test.cc")
tile_add_test(base_thread_spinlock_test "tile/base/thread/spinlock_test.cc")
tile_add_test(base_thread_unique_lock_test
"tile/base/thread/unique_lock_test.cc")
tile_add_test(base_thread_cond_var_test "tile/base/thread/cond_var_test.cc")
tile_add_test(base_thread_latch_test "tile/base/thread/latch_test.cc")
# tile_add_test(fiber_ucontext_test "tile/fiber/ucontext_test.cc")
tile_add_test(init_on_init_test "tile/init/on_init_test.cc") add_test_group(${CMAKE_CURRENT_SOURCE_DIR}/tile/base base)
tile_add_test(base_buffer_test "tile/base/buffer_test.cc") add_test_group(${CMAKE_CURRENT_SOURCE_DIR}/tile/init init)
tile_add_test(base_object_pool_thread_local_test add_test_group(${CMAKE_CURRENT_SOURCE_DIR}/tile/io io)
"tile/base/object_pool/thread_local_test.cc") add_test_group(${CMAKE_CURRENT_SOURCE_DIR}/tile/net net)
tile_add_test(base_internal_logging_test "tile/base/internal/logging_test.cc") add_test_group(${CMAKE_CURRENT_SOURCE_DIR}/tile/rpc rpc)
tile_add_test(base_chrono_test "tile/base/chrono_test.cc")
tile_add_test(init_override_flag_test "tile/init/override_flag_test.cc")
tile_add_custom_test("custom_http_client_test" "tests/http_client_test.cc") tile_add_custom_test("custom_http_client_test" "tests/http_client_test.cc")
# tile_add_test(base_internal_time_keeper_test
# "tile/base/internal/time_keeper_test.cc")
tile_add_test(tile_util_ini_file_config_test "tile/util/ini_file_config_test.cc")
endif(TILE_BUILD_TESTS) endif(TILE_BUILD_TESTS)
if(TILE_BUILD_BENCHMARKS) if(TILE_BUILD_BENCHMARKS)

View File

@ -1,4 +1,4 @@
#include "tile/util/config.h" #include "tile/base/config/config.h"
#include "tile/base/thread/unique_lock.h" #include "tile/base/thread/unique_lock.h"
namespace tile { namespace tile {

View File

@ -1,8 +1,7 @@
#ifndef TILE_UTIL_CONFIG_H #ifndef TILE_BASE_CONFIG_CONFIG_H
#define TILE_UTIL_CONFIG_H #define TILE_BASE_CONFIG_CONFIG_H
#pragma once #pragma once
#include "tile/base/optional.h" #include "tile/base/optional.h"
#include "tile/base/ref_ptr.h" #include "tile/base/ref_ptr.h"
#include "tile/base/slice.h" #include "tile/base/slice.h"
@ -125,4 +124,4 @@ private:
} // namespace util } // namespace util
} // namespace tile } // namespace tile
#endif // TILE_UTIL_CONFIG_H #endif // TILE_BASE_CONFIG_CONFIG_H

View File

@ -0,0 +1,19 @@
#ifndef TILE_BASE_CONFIG_CONFIGURABLE_H
#define TILE_BASE_CONFIG_CONFIGURABLE_H
#pragma once
#include "tile/base/string.h"
namespace tile {
namespace util {
class Configurable {
Configurable();
virtual ~Configurable() = default;
virtual void SetProperty(const Slice &name, const Slice &value) = 0;
virtual std::string GetProperty(const Slice &name) const = 0;
};
} // namespace util
} // namespace tile
#endif // TILE_BASE_CONFIG_CONFIGURABLE_H

View File

@ -1,4 +1,4 @@
#include "tile/util/ini_file_config.h" #include "tile/base/config/ini_file_config.h"
#include "tile/base/thread/scoped_lock.h" #include "tile/base/thread/scoped_lock.h"
namespace tile { namespace tile {

View File

@ -1,9 +1,9 @@
#ifndef TILE_UTIL_INI_FILE_CONFIG_H #ifndef TILE_BASE_CONFIG_INI_FILE_CONFIG_H
#define TILE_UTIL_INI_FILE_CONFIG_H #define TILE_BASE_CONFIG_INI_FILE_CONFIG_H
#pragma once #pragma once
#include "tile/util/config.h" #include "tile/base/config/config.h"
#include <map> #include <map>
namespace tile { namespace tile {
@ -37,4 +37,4 @@ private:
} // namespace util } // namespace util
} // namespace tile } // namespace tile
#endif // TILE_UTIL_INI_FILE_CONFIG_H #endif // TILE_BASE_CONFIG_INI_FILE_CONFIG_H

View File

@ -1,4 +1,4 @@
#include "tile/util/ini_file_config.h" #include "tile/base/config/ini_file_config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
const char *kIniFileConfig = R"( const char *kIniFileConfig = R"(

View File

@ -1,4 +1,4 @@
#include "tile/util/layered_config.h" #include "tile/base/config/layered_config.h"
namespace tile { namespace tile {
namespace util { namespace util {

View File

@ -1,9 +1,9 @@
#ifndef TILE_UTIL_LAYERD_CONFIG_H #ifndef TILE_BASE_CONFIG_LAYERED_CONFIG_H
#define TILE_UTIL_LAYERD_CONFIG_H #define TILE_BASE_CONFIG_LAYERED_CONFIG_H
#pragma once #pragma once
#include "tile/util/config.h" #include "tile/base/config/config.h"
#include <list> #include <list>
namespace tile { namespace tile {
@ -54,4 +54,4 @@ private:
} // namespace util } // namespace util
} // namespace tile } // namespace tile
#endif // TILE_UTIL_LAYERD_CONFIG_H #endif // TILE_BASE_CONFIG_LAYERED_CONFIG_H

View File

@ -1,178 +0,0 @@
#include "tile/fiber/detail/fiber.h"
#include "tile/base/align.h"
#include "tile/base/internal/index_alloc.h"
#include "tile/base/internal/move_on_copy.h"
#include "tile/base/logging.h"
#include "tile/base/make_unique.h"
#include "tile/base/object_pool.h"
#include "tile/base/string.h"
#include "nova/context/fcontext.h"
namespace tile {
namespace fiber {
namespace detail {
std::string ToString(const FiberState &state) noexcept {
switch (state) {
case FiberState::Runnable:
return "Runnable";
case FiberState::Running:
return "Running";
case FiberState::Waiting:
return "Waiting";
case FiberState::Terminated:
return "Terminated";
default:
TILE_UNEXPECTED("");
return "Unknown";
}
}
std::ostream &operator<<(std::ostream &os, const FiberState &state) noexcept {
return os << ToString(state);
}
static thread_local Fiber *tls_current_fiber = nullptr;
static thread_local Fiber *tls_master_fiber = nullptr;
constexpr std::size_t kStackSize = 128 * 1024; // 128k
constexpr std::size_t kAlignSize = 16;
struct alignas(hardware_destructive_interference_size) Fiber::FiberContext {
std::aligned_storage<kStackSize, kAlignSize>::type stack;
std::function<void()> proc;
};
void FiberEntry(fcontext_transfer_t t) {
std::function<void()> *fn = static_cast<std::function<void()> *>(t.data);
TILE_CHECK(t.data != nullptr);
TILE_CHECK(t.fctx != nullptr);
Fiber *self = nullptr;
try {
// From Resume()
t = jump_fcontext(t.fctx, nullptr);
Fiber *caller = reinterpret_cast<Fiber *>(t.data);
self = GetCurrentFiber();
if (caller) {
caller->ctx_ = t.fctx;
} else {
TILE_CHECK_EQ(self, GetMasterFiber());
}
(*fn)();
} catch (const std::exception &e) {
TILE_LOG_ERROR("Exception caught in fiber: {}", e.what());
}
self->state_ = FiberState::Terminated;
if (GetMasterFiber() == self) {
// master fiber end
jump_fcontext(t.fctx, GetMasterFiber());
} else {
TILE_CHECK(GetMasterFiber() != nullptr);
TILE_CHECK_NE(GetMasterFiber()->state(), FiberState::Terminated);
GetMasterFiber()->Resume();
}
}
fcontext_transfer_t FiberOnTop(fcontext_transfer_t t) {}
fcontext_t CreateFiber(void *stack, std::size_t stack_size,
std::function<void()> *fn) {
void *stack_top = static_cast<char *>(stack) + stack_size;
const fcontext_t fctx = make_fcontext(stack_top, stack_size, FiberEntry);
TILE_CHECK(fctx != nullptr);
return jump_fcontext(fctx, fn).fctx;
}
Fiber *GetCurrentFiber() noexcept { return tls_current_fiber; }
void SetUpCurrentFiber(Fiber *fiber) noexcept { tls_current_fiber = fiber; }
Fiber *GetMasterFiber() noexcept { return tls_master_fiber; }
void SetUpMasterFiber(Fiber *fiber) noexcept { tls_master_fiber = fiber; }
std::unique_ptr<Fiber> Fiber::Create(std::function<void()> proc) noexcept {
return std::unique_ptr<Fiber>(new Fiber(std::move(proc)));
}
Fiber::Fiber(std::function<void()> proc)
: id_(internal::IndexAlloc::For<Fiber>()->Next()),
data_(object_pool::Get<FiberContext>().Leak()) {
TILE_CHECK(proc);
data_->proc = std::move(proc);
ctx_ = CreateFiber(&data_->stack, kStackSize, &data_->proc);
}
Fiber::~Fiber() {
if (data_) {
object_pool::Put<FiberContext>(data_.release());
}
internal::IndexAlloc::For<Fiber>()->Free(id_);
}
void Fiber::Resume() {
auto caller = GetCurrentFiber();
TILE_CHECK_NE(caller, this, "Calling `Resume()`, on self is undefined.");
SetUpCurrentFiber(this);
auto t = jump_fcontext(internal::Exchange(ctx_, nullptr), caller);
if (auto from = reinterpret_cast<Fiber *>(t.data)) {
from->ctx_ = t.fctx;
}
SetUpCurrentFiber(caller);
}
void Fiber::ResumeOn(std::function<void()> &&cb) noexcept {
auto caller = GetCurrentFiber();
TILE_CHECK_NE(caller, this, "Calling `ResumeOn()`, on self is undefined.");
SetUpCurrentFiber(this);
auto t = ontop_fcontext(ctx_, this, FiberOnTop);
caller = reinterpret_cast<Fiber *>(t.data);
SetUpCurrentFiber(caller);
}
std::string ToString(const Fiber &fiber) noexcept { return ToString(&fiber); }
std::string ToString(const std::unique_ptr<Fiber> &fiber) noexcept {
return ToString(fiber.get());
}
std::string ToString(Fiber const *const fiber) noexcept {
if (TILE_UNLIKELY(fiber == nullptr)) {
return "Fiber(nullptr)";
}
return Format("Fiber({})[{}]", fiber->id(), fmt::ptr(fiber));
}
} // namespace detail
} // namespace fiber
template <> struct PoolTraits<tile::fiber::detail::Fiber::FiberContext> {
static constexpr auto kType = PoolType::MemoryNodeShared;
static constexpr std::size_t kLowWaterMark = 128;
static constexpr std::size_t kHighWaterMark =
std::numeric_limits<std::size_t>::max();
static constexpr std::chrono::seconds kMaxIdle = std::chrono::seconds(10);
static constexpr std::size_t kMinimumThreadCacheSize = 64;
static constexpr std::size_t kTransferBatchSize = 16;
};
constexpr PoolType PoolTraits<fiber::detail::Fiber::FiberContext>::kType;
constexpr std::size_t
PoolTraits<fiber::detail::Fiber::FiberContext>::kLowWaterMark;
constexpr std::size_t
PoolTraits<fiber::detail::Fiber::FiberContext>::kHighWaterMark;
constexpr std::chrono::seconds
PoolTraits<fiber::detail::Fiber::FiberContext>::kMaxIdle;
constexpr std::size_t
PoolTraits<fiber::detail::Fiber::FiberContext>::kMinimumThreadCacheSize;
constexpr std::size_t
PoolTraits<fiber::detail::Fiber::FiberContext>::kTransferBatchSize;
} // namespace tile

View File

@ -1,93 +0,0 @@
#ifndef TILE_FIBER_DETAIL_FIBER_H
#define TILE_FIBER_DETAIL_FIBER_H
#pragma once
#include "tile/base/align.h"
#include "tile/base/internal/test_prod.h"
#include "tile/base/object_pool.h"
#include "tile/base/ref_ptr.h"
#include <memory>
struct tile_ucontext_t;
// struct fcontext_transfer;
typedef struct fcontext_transfer fcontext_transfer_t;
namespace tile {
namespace fiber {
namespace detail {
class Scheduler;
enum class FiberState {
Runnable,
Running,
Waiting,
Terminated,
};
std::string ToString(const FiberState &state) noexcept;
std::ostream &operator<<(std::ostream &os, const FiberState &state) noexcept;
class Scheduler;
class alignas(hardware_destructive_interference_size) Fiber {
public:
using Id = std::uint64_t;
static std::unique_ptr<Fiber>
Create(std::function<void()> proc = nullptr) noexcept;
~Fiber();
Fiber(const Fiber &) = delete;
Fiber &operator=(const Fiber &) = delete;
Fiber(Fiber &&other) noexcept = default;
Fiber &operator=(Fiber &&other) noexcept = default;
void Resume();
void ResumeOn(std::function<void()> &&cb) noexcept;
void Yield();
Id id() const noexcept { return id_; }
FiberState state() const noexcept { return state_; }
Scheduler *scheduler() const { return scheduler_; }
private:
TILE_FRIEND_TEST(Fiber, Base);
friend Scheduler;
struct FiberContext;
friend class ::tile::PoolTraits<FiberContext>;
friend void FiberEntry(fcontext_transfer_t);
friend fcontext_transfer_t FiberOnTop(fcontext_transfer_t);
Fiber(std::function<void()> proc = nullptr);
private:
Id id_;
std::unique_ptr<FiberContext> data_;
FiberState state_{FiberState::Runnable};
void *ctx_{nullptr};
// for scheduler
Scheduler *scheduler_{nullptr};
};
Fiber *GetCurrentFiber() noexcept;
Fiber *GetMasterFiber() noexcept;
void SetUpCurrentFiber(Fiber *fiber) noexcept;
void SetUpMasterFiber(Fiber *fiber) noexcept;
inline bool IsFiberContext() noexcept { return GetCurrentFiber() != nullptr; }
std::string ToString(Fiber const *const fiber) noexcept;
std::string ToString(const std::unique_ptr<Fiber> &fiber) noexcept;
std::string ToString(const Fiber &fiber) noexcept;
} // namespace detail
} // namespace fiber
} // namespace tile
#endif // TILE_FIBER_DETAIL_FIBER_H

View File

@ -1,64 +0,0 @@
#include "tile/base/chrono.h"
#include "tile/base/random.h"
#include "tile/fiber/detail/fiber.h"
#include "benchmark/benchmark.h"
namespace tile {
namespace fiber {
namespace detail {
void Benchmark_FiberSwitch(benchmark::State &state) {
constexpr int kFiberCount = 2 * 10000;
std::unique_ptr<Fiber> master;
std::unique_ptr<Fiber> worker[kFiberCount];
int cnt = 0;
master = Fiber::Create([&]() {
while (state.KeepRunning()) {
++cnt;
auto &w1 = worker[Random(kFiberCount - 1)];
auto &w2 = worker[Random(kFiberCount - 1)];
auto start = ReadSteadyClock();
w1->Resume();
w2->Resume();
w1->Resume();
w2->Resume();
w1->Resume();
w2->Resume();
w1->Resume();
w2->Resume();
auto end = ReadSteadyClock();
auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(
end - start) /
8;
state.SetIterationTime(duration.count());
}
cnt = -1;
for (int i = 0; i != kFiberCount; ++i) {
worker[i]->Resume();
}
});
for (int i = 0; i != kFiberCount; ++i) {
worker[i] = Fiber::Create([&, i]() {
while (cnt != -1) {
master->Resume();
master->Resume();
master->Resume();
master->Resume();
}
});
}
SetUpMasterFiber(master.get());
SetUpCurrentFiber(nullptr);
master->Resume();
}
BENCHMARK(Benchmark_FiberSwitch)->UseManualTime();
} // namespace detail
} // namespace fiber
} // namespace tile

View File

@ -1,44 +0,0 @@
#include "tile/fiber/detail/scheduler.h"
namespace tile {
namespace fiber {
namespace detail {
static thread_local Scheduler *current_scheduler = nullptr;
void Scheduler::SwitchTo(Fiber *self, Fiber *to) {
TILE_CHECK_EQ(self, GetCurrentFiber());
TILE_CHECK(to->state_ == FiberState::Terminated,
"Fiber `to` is not in Runnable.");
TILE_CHECK_NE(self, to, "Switch to yourself result in U.B.");
to->Resume();
TILE_CHECK_EQ(self, GetCurrentFiber());
}
void Scheduler::Yield(Fiber *self) {
auto master = GetMasterFiber();
TILE_CHECK(self, "self fiber is nullptr.");
TILE_CHECK(master, "Master fiber is not set.");
master->state_ = FiberState::Runnable;
self->state_ = FiberState::Running;
SwitchTo(self, master);
}
void Scheduler::Halt(Fiber *self) {
TILE_CHECK_EQ(self, GetCurrentFiber(), "Fiber is not current fiber.");
TILE_CHECK(self->state() == FiberState::Running, "Fiber is not running.");
auto master = GetMasterFiber();
self->state_ = FiberState::Waiting;
master->Resume();
TILE_CHECK_EQ(self, GetCurrentFiber());
}
} // namespace detail
} // namespace fiber
} // namespace tile

View File

@ -1,24 +0,0 @@
#ifndef TILE_FIBER_DETAIL_SCHEDULER_H
#define TILE_FIBER_DETAIL_SCHEDULER_H
#pragma once
#include "tile/fiber/detail/fiber.h"
namespace tile {
namespace fiber {
namespace detail {
class Scheduler {
public:
static Scheduler *Current() noexcept;
void SwitchTo(Fiber *self, Fiber *to);
void Yield(Fiber *self);
void Halt(Fiber *self);
};
} // namespace detail
} // namespace fiber
} // namespace tile
#endif // TILE_FIBER_DETAIL_SCHEDULER_H

View File

@ -1,55 +0,0 @@
#include "tile/fiber/detail/scheduler.h"
#include "tile/base/deferred.h"
#include "tile/base/random.h"
#include "gtest/gtest.h"
namespace tile {
namespace fiber {
namespace detail {
TEST(Fiber, Resume) {
constexpr int kFiberCount = 1000;
constexpr int kSwitchCount = 1000 * 1000;
std::unique_ptr<Fiber> master;
std::unique_ptr<Fiber> worker[kFiberCount];
int cnt = 0;
auto end_check = tile::Deferred([&]() { ASSERT_EQ(cnt, kSwitchCount); });
master = Fiber::Create([&]() {
while (cnt < kSwitchCount) {
ASSERT_EQ(GetCurrentFiber(), master.get());
worker[Random(kFiberCount - 1)]->Resume();
ASSERT_EQ(GetCurrentFiber(), master.get());
}
for (int i = 0; i != kFiberCount; ++i) {
worker[i]->Resume();
}
});
for (int i = 0; i != kFiberCount; ++i) {
worker[i] = Fiber::Create([&, i]() {
while (cnt < kSwitchCount) {
++cnt;
ASSERT_EQ(GetCurrentFiber(), worker[i].get());
master->Resume();
ASSERT_EQ(GetCurrentFiber(), worker[i].get());
}
});
}
SetUpMasterFiber(master.get());
SetUpCurrentFiber(nullptr);
master->Resume();
ASSERT_EQ(cnt, kSwitchCount);
for (int i = 0; i != kFiberCount; ++i) {
ASSERT_EQ(worker[i]->state(), FiberState::Terminated);
}
}
} // namespace detail
} // namespace fiber
} // namespace tile

View File

@ -1,42 +0,0 @@
#include "tile/fiber/detail/waitable.h"
#include "tile/base/thread/scoped_lock.h"
namespace tile {
namespace fiber {
namespace detail {
WaitList::WaitList() {}
WaitList::~WaitList() {}
bool WaitList::AddWaiter(WaitListNode *node) {
ScopedLock _(lock_);
TILE_CHECK(node->waiter);
waiters_.push_back(node);
return true;
}
Fiber *WaitList::WakeOne() {
ScopedLock _(lock_);
while (true) {
if (waiters_.empty()) {
return nullptr;
}
WaitListNode *waiter = waiters_.front();
waiters_.pop_front();
if (!waiter) {
return nullptr;
}
if (waiter->satisfied.exchange(true, std::memory_order_relaxed)) {
continue;
;
}
return waiter->waiter;
}
}
} // namespace detail
} // namespace fiber
} // namespace tile

View File

@ -1,48 +0,0 @@
#ifndef TILE_FIBER_DETAIL_WAITABLE_H
#define TILE_FIBER_DETAIL_WAITABLE_H
#pragma once
#include "tile/base/internal/singly_linked_list.h"
#include "tile/base/thread/spinlock.h"
#include <list>
namespace tile {
namespace fiber {
namespace detail {
class Fiber;
class Scheduler;
struct WaitListNode {
Fiber *waiter = nullptr;
tile::internal::SinglyLinkedListEntry chain;
std::atomic<bool> satisfied{false};
};
class WaitList {
public:
WaitList();
~WaitList();
bool AddWaiter(WaitListNode *node);
// Remove the waiter from the list.
// return true if the waiter is removed, otherwise return nullptr.
Fiber *WakeOne();
WaitList(const WaitList &) = delete;
WaitList &operator=(const WaitList &) = delete;
private:
Spinlock lock_;
std::list<WaitListNode *> waiters_;
// tile::internal::SinglyLinkedList<WaitListNode, &WaitListNode::chain>
// waiters_;
};
} // namespace detail
} // namespace fiber
} // namespace tile
#endif // TILE_FIBER_DETAIL_WAITABLE_H

View File

@ -1,49 +0,0 @@
#include "tile/fiber/mutex.h"
// #include "tile/base/thread/scoped_lock.h"
#include "tile/base/thread/unique_lock.h"
#include "tile/fiber/detail/os_fiber.h"
namespace tile {
namespace fiber {
void Mutex::Lock() {
TILE_DCHECK(detail::IsFiberEnv());
if (TILE_LIKELY(TryLock())) {
return;
}
LockSlow();
}
bool Mutex::TryLock() {
TILE_DCHECK(detail::IsFiberEnv());
std::uint32_t expected = 0;
return count_.compare_exchange_strong(expected, 1, std::memory_order_acquire);
}
void Mutex::Unlock() {
TILE_CHECK(detail::IsFiberEnv());
auto was = count_.fetch_sub(1, std::memory_order_release);
if (was == 1) {
// lock success.
} else {
TILE_CHECK_GT(was, 1);
UniqueLock<Spinlock> splk(slow_path_lock_);
splk.Unlock();
}
}
void Mutex::LockSlow() {
TILE_DCHECK(detail::IsFiberEnv());
if (TryLock()) {
// lock success.
return;
}
UniqueLock<Spinlock> splk(slow_path_lock_);
if (count_.fetch_add(1, std::memory_order_acquire) == 0) {
// lock success.
return;
}
auto current = detail::OSFiber::Current();
}
} // namespace fiber
} // namespace tile

View File

@ -1,24 +0,0 @@
#include "tile/fiber/this_fiber.h"
namespace tile {
namespace this_fiber {
void Yield() {
auto self = fiber::detail::GetCurrentFiber();
TILE_CHECK(self, "Yield() should be called in a fiber.");
self->scheduler()->Yield(self);
}
void SleepUntil(std::chrono::steady_clock::time_point expires_at) {}
void SleepFor(std::chrono::nanoseconds expires_in) {
SleepUntil(ReadSteadyClock() + expires_in);
}
Fiber::Id GetId() {
auto self = fiber::detail::GetCurrentFiber();
TILE_CHECK(self, "GetId() should be called in a fiber.");
return self->id();
}
} // namespace this_fiber
} // namespace tile

View File

@ -1,29 +0,0 @@
#include "tile/fiber/detail/fiber.h"
#include "tile/fiber/detail/scheduler.h"
#include "tile/base/chrono.h"
namespace tile {
namespace this_fiber {
using Fiber = fiber::detail::Fiber;
void Yield();
void SleepUntil(std::chrono::steady_clock::time_point expires_at);
void SleepFor(std::chrono::nanoseconds expires_in);
template <typename Clock, typename Duration>
void SleepFor(std::chrono::time_point<Clock, Duration> expires_at) {
SleepUntil(ReadSteadyClock() + (expires_at - Clock::now()));
}
template <typename Rep, typename Period>
void SleepFor(std::chrono::duration<Rep, Period> expires_in) {
return SleepFor(static_cast<std::chrono::nanoseconds>(expires_in));
}
Fiber::Id GetId();
} // namespace this_fiber
} // namespace tile

View File

@ -1,54 +0,0 @@
#define _XOPEN_SOURCE 600
extern "C" {
#include <ucontext.h>
}
#include "tile/base/logging.h"
#include "gtest/gtest.h"
static int call_id = 0;
char stack1[8192];
char stack2[8192];
static void f1() {
EXPECT_EQ(call_id, 0);
call_id = 1;
}
static void f2() {
EXPECT_EQ(call_id, 1);
call_id = 2;
}
// 0 -> main fiber
// 1 -> f1
// 2 -> f2
static ucontext_t ctx[3];
void SetCtx1() {}
void SetCtx2() {}
TEST(Ucontext, Ucontext) {
memset(&ctx, 0, sizeof(ctx));
getcontext(&ctx[0]);
for (int i = 0; i != 1000; ++i) {
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = stack1;
ctx[1].uc_stack.ss_size = sizeof(stack1);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], f1, 0);
getcontext(&ctx[2]);
ctx[2].uc_stack.ss_sp = stack2;
ctx[2].uc_stack.ss_size = sizeof(stack2);
ctx[2].uc_link = &ctx[0];
makecontext(&ctx[2], f2, 0);
call_id = 0;
swapcontext(&ctx[0], &ctx[1]);
EXPECT_EQ(call_id, 1);
swapcontext(&ctx[0], &ctx[2]);
EXPECT_EQ(call_id, 2);
}
}

View File

@ -75,6 +75,7 @@ public:
void SetUp() override { site_url_ = "http://example.com/"; } void SetUp() override { site_url_ = "http://example.com/"; }
std::string site_url_; std::string site_url_;
}; };
TEST_F(HttpEngineTest, Basic) { TEST_F(HttpEngineTest, Basic) {
HttpTask t; HttpTask t;
t.SetMethod(HttpMethod::Get); t.SetMethod(HttpMethod::Get);

View File

@ -9,6 +9,7 @@
#include "tile/base/casting.h" #include "tile/base/casting.h"
#include "tile/base/chrono.h" #include "tile/base/chrono.h"
#include "tile/base/compression.h" #include "tile/base/compression.h"
#include "tile/base/config/ini_file_config.h"
#include "tile/base/data.h" #include "tile/base/data.h"
#include "tile/base/deferred.h" #include "tile/base/deferred.h"
#include "tile/base/demangle.h" #include "tile/base/demangle.h"