feat/support_fiber #2
@ -204,7 +204,7 @@ if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS))
|
||||
list(APPEND TILE_SRCS "tile/base/net/detail/android/ifaddrs.c")
|
||||
endif()
|
||||
|
||||
add_library(tile OBJECT ${TILE_SRCS} ${ASM_SRCS})
|
||||
add_library(tile OBJECT ${TILE_SRCS})
|
||||
set_target_properties(tile PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${tile_VERSION_MAJRO}")
|
||||
# target_sources(tile PRIVATE ${TILE_SRCS})
|
||||
|
7
third_party/context/CMakeLists.txt
vendored
7
third_party/context/CMakeLists.txt
vendored
@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.5...3.16)
|
||||
project(
|
||||
nova_context
|
||||
VERSION 0.1.0
|
||||
LANGUAGES C)
|
||||
LANGUAGES C ASM)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
@ -197,6 +197,7 @@ set(ASM_SRC
|
||||
|
||||
unset(_asm_suffix)
|
||||
|
||||
set_source_files_properties(${ASM_SRC} PROPERTIES LINKER_LANGUAGE C)
|
||||
# POWERPC_32/SYSV Special case: https://github.com/boostorg/context/issues/120
|
||||
if((NOVA_CONTEXT_ARCHITECTURE STREQUAL ppc32) AND (NOVA_CONTEXT_ABI STREQUAL
|
||||
sysv))
|
||||
@ -210,8 +211,8 @@ if(NOVA_CONTEXT_ASSEMBLER STREQUAL masm AND NOVA_CONTEXT_ARCHITECTURE STREQUAL
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
set_source_files_properties(${ASM_SRC} PROPERTIES COMPILE_OPTIONS
|
||||
"-x assembler-with-cpp")
|
||||
# set_source_files_properties(${ASM_SRC} PROPERTIES COMPILE_OPTIONS
|
||||
# "-x assembler-with-cpp")
|
||||
endif()
|
||||
|
||||
# Boost specific definitions
|
||||
|
@ -57,6 +57,13 @@ auto format_as(const T &val)
|
||||
return val.ToString();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto format_as(T *ptr)
|
||||
-> tile::enable_if_t<!std::is_void<tile::remove_cvref_t<T>>::value,
|
||||
void *> {
|
||||
return reinterpret_cast<void *>(ptr);
|
||||
}
|
||||
|
||||
#define TILE_INSTANCE_CHRONO_FORMAT_AS(type, suffix) \
|
||||
inline std::string format_as(const type &val) { \
|
||||
return tile::detail::format_as_impl(val, suffix); \
|
||||
@ -80,4 +87,17 @@ TILE_INSTANCE_CHRONO_FORMAT_AS(std::chrono::years, "y")
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, std::nullptr_t) {
|
||||
return os << "nullptr";
|
||||
}
|
||||
|
||||
// template <typename T,
|
||||
// typename = tile::enable_if_t<
|
||||
// !tile::detail::is_streamable<std::ostream, T *>::value &&
|
||||
// !std::is_same<tile::remove_cvref_t<T *>,
|
||||
// std::nullptr_t>::value>>
|
||||
// std::ostream &operator<<(std::ostream &os, T *ptr) {
|
||||
// return os << fmt::format("{}", fmt::ptr(ptr));
|
||||
// }
|
||||
|
||||
#endif // TILE_BASE_INTERNAL_FORMAT_H
|
||||
|
@ -16,32 +16,38 @@ namespace detail {
|
||||
static thread_local Fiber *tls_current_fiber = nullptr;
|
||||
static thread_local Fiber *tls_master_fiber = nullptr;
|
||||
|
||||
constexpr auto kStackSize = 8192;
|
||||
constexpr auto kAlignSize = 16;
|
||||
constexpr std::size_t kStackSize = 8192;
|
||||
constexpr std::size_t kAlignSize = 16;
|
||||
|
||||
void RunProc(void *arg) {
|
||||
auto proc = static_cast<std::function<void()> *>(arg);
|
||||
if (proc) {
|
||||
(*proc)();
|
||||
void FiberEntry(fcontext_transfer_t t) {
|
||||
// TILE_LOG_INFO("FiberEntry creater {}, proc {}", t.fctx, t.data);
|
||||
std::function<void()> *fn = static_cast<std::function<void()> *>(t.data);
|
||||
TILE_CHECK_NE(t.data, nullptr);
|
||||
TILE_CHECK_NE(t.fctx, nullptr);
|
||||
try {
|
||||
t = jump_fcontext(t.fctx, nullptr);
|
||||
(*fn)();
|
||||
} catch (const std::exception &e) {
|
||||
// TILE_LOG_ERROR("Exception caught in fiber: {}", e.what());
|
||||
}
|
||||
Fiber::MasterFiber()->Resume();
|
||||
TILE_CHECK_NE(t.fctx, nullptr);
|
||||
// TILE_LOG_INFO("FiberEntry End. Resume to {}", t.fctx);
|
||||
jump_fcontext(t.fctx, nullptr);
|
||||
}
|
||||
|
||||
void RunProc1(fcontext_transfer_t ft) {
|
||||
auto t = jump_fcontext(ft.fctx, nullptr);
|
||||
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_NE(fctx, nullptr);
|
||||
|
||||
auto proc = static_cast<std::function<void()> *>(ft.data);
|
||||
TILE_LOG_INFO("proc: {}", fmt::ptr(proc));
|
||||
if (proc) {
|
||||
(*proc)();
|
||||
}
|
||||
Fiber::MasterFiber()->Resume();
|
||||
return jump_fcontext(fctx, fn).fctx;
|
||||
}
|
||||
|
||||
struct alignas(hardware_destructive_interference_size) Fiber::FiberContext {
|
||||
fcontext_t fctx;
|
||||
// tile_ucontext_t uctx;
|
||||
std::aligned_storage<kStackSize, kAlignSize>::type stack;
|
||||
std::function<void()> proc;
|
||||
};
|
||||
|
||||
Fiber *Fiber::Current() noexcept { return tls_current_fiber; }
|
||||
@ -56,12 +62,13 @@ std::unique_ptr<Fiber> Fiber::Create(std::function<void()> proc) noexcept {
|
||||
}
|
||||
|
||||
Fiber::Fiber(std::function<void()> proc)
|
||||
: ctx_(object_pool::Get<FiberContext>().Leak()), proc_(std::move(proc)) {
|
||||
: ctx_(object_pool::Get<FiberContext>().Leak()) {
|
||||
|
||||
// memset(&ctx_->uctx, 0, sizeof(tile_ucontext_t));
|
||||
// memset(&ctx_->stack, 0, kStackSize);
|
||||
if (proc_) {
|
||||
make_fcontext(&ctx_->stack, kStackSize, RunProc1);
|
||||
ctx_->proc = std::move(proc);
|
||||
if (ctx_->proc) {
|
||||
ctx_->fctx = CreateFiber(&ctx_->stack, kStackSize, &ctx_->proc);
|
||||
} else {
|
||||
ctx_->fctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,12 +82,14 @@ void Fiber::Resume() {
|
||||
auto caller = Current();
|
||||
TILE_CHECK_NE(caller, this, "Can't `Resume()` self");
|
||||
SetCurrent(this);
|
||||
// tile_ucontext_swap(&caller->ctx_->uctx, &ctx_->uctx);
|
||||
TILE_LOG_INFO("proc: {}", fmt::ptr(&proc_));
|
||||
jump_fcontext(ctx_->fctx, nullptr);
|
||||
// TILE_LOG_INFO("Resume before proc: {}", fmt::ptr(&proc_));
|
||||
ctx_->fctx = jump_fcontext(ctx_->fctx, nullptr).fctx;
|
||||
// TILE_LOG_INFO("Resume after proc: {}", fmt::ptr(&proc_));
|
||||
SetCurrent(caller);
|
||||
}
|
||||
|
||||
void Fiber::Yield() {}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace fiber
|
||||
|
||||
|
@ -43,21 +43,20 @@ public:
|
||||
Fiber(Fiber &&other) noexcept = default;
|
||||
Fiber &operator=(Fiber &&other) noexcept = default;
|
||||
|
||||
// for `Scheduler`
|
||||
void Resume();
|
||||
void Yield();
|
||||
|
||||
private:
|
||||
TILE_FRIEND_TEST(Fiber, Base);
|
||||
friend void RunProc(void *);
|
||||
friend void RunProc1(struct fcontext_transfer);
|
||||
friend Scheduler;
|
||||
struct FiberContext;
|
||||
friend class ::tile::PoolTraits<FiberContext>;
|
||||
|
||||
Fiber(std::function<void()> proc = nullptr);
|
||||
|
||||
void Resume();
|
||||
|
||||
private:
|
||||
std::unique_ptr<FiberContext> ctx_;
|
||||
std::function<void()> proc_;
|
||||
FiberState state_{Ready};
|
||||
};
|
||||
|
||||
|
@ -13,27 +13,19 @@ TEST(Fiber, Base) {
|
||||
|
||||
// 0 -> master fiber
|
||||
// [1, 9] -> worker fibers
|
||||
std::vector<std::unique_ptr<Fiber>> fibers;
|
||||
|
||||
fibers.emplace_back(Fiber::Create());
|
||||
Fiber::SetMasterFiber(fibers[0].get());
|
||||
Fiber::SetCurrent(fibers[0].get());
|
||||
auto master_fiber = Fiber::Create();
|
||||
Fiber::SetMasterFiber(master_fiber.get());
|
||||
Fiber::SetCurrent(master_fiber.get());
|
||||
|
||||
for (int i = 1; i != 10; ++i) {
|
||||
fibers.emplace_back(Fiber::Create([&, i] {
|
||||
while (cnt < kMaxCnt) {
|
||||
ASSERT_EQ(Fiber::Current(), fibers[i].get());
|
||||
std::unique_ptr<Fiber> worker_fiber = Fiber::Create([&] {
|
||||
ASSERT_EQ(Fiber::Current(), worker_fiber.get());
|
||||
++cnt;
|
||||
Fiber::MasterFiber()->Resume();
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
while (cnt < kMaxCnt) {
|
||||
int old = cnt;
|
||||
auto next_fiber = fibers[Random(1, 9)].get();
|
||||
|
||||
next_fiber->Resume();
|
||||
worker_fiber->Resume();
|
||||
++resume_cnt;
|
||||
ASSERT_EQ(old + 1, cnt);
|
||||
ASSERT_EQ(Fiber::Current(), Fiber::MasterFiber());
|
||||
|
Loading…
x
Reference in New Issue
Block a user