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