协程初步实现
This commit is contained in:
parent
222b364df0
commit
2cf361f0d5
@ -11,21 +11,24 @@ include_directories(includes/log)
|
|||||||
|
|
||||||
aux_source_directory(${CMAKE_SOURCE_DIR}/src/coroutine SRC_LIST)
|
aux_source_directory(${CMAKE_SOURCE_DIR}/src/coroutine SRC_LIST)
|
||||||
|
|
||||||
# set(ASM_FILES ${CMAKE_SOURCE_DIR}/src/swap.S)
|
set(ASM_FILES ${CMAKE_SOURCE_DIR}/src/coroutine/coctx_swap.S)
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
|
||||||
set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
|
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib)
|
||||||
|
|
||||||
|
find_library(TINYRPC_LIB tinyrpc ${CMAKE_SOURCE_DIR}/lib)
|
||||||
|
|
||||||
add_library(tinyrpc
|
add_library(tinyrpc
|
||||||
${SRC_LIST}
|
${SRC_LIST}
|
||||||
# ${ASM_FILES}
|
${ASM_FILES}
|
||||||
|
|
||||||
)
|
)
|
||||||
aux_source_directory(${CMAKE_SOURCE_DIR}/test/logtest TEST_SRC_LIST)
|
|
||||||
|
aux_source_directory(${CMAKE_SOURCE_DIR}/test/coroutine TEST_SRC_LIST)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
add_executable(test_tinyrpc
|
add_executable(test_tinyrpc
|
||||||
${TEST_SRC_LIST}
|
${TEST_SRC_LIST}
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(test_tinyrpc ${TINYRPC_LIB})
|
@ -1,14 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace tinyrpc {
|
namespace tinyrpc {
|
||||||
enum class reg : unsigned int { // https://wiki.osdev.org/System_V_ABI
|
namespace reg {
|
||||||
|
enum { // https://wiki.osdev.org/System_V_ABI
|
||||||
kRBP = 6, // 栈底指针
|
kRBP = 6, // 栈底指针
|
||||||
kRDI = 7, // rdi,调用函数时的第一个参数
|
kRDI = 7, // rdi,调用函数时的第一个参数
|
||||||
kRSI = 8, // rsi, 调用函数时的第二个参数 这两个是 根据调用约定确定的
|
kRSI = 8, // rsi, 调用函数时的第二个参数 这两个是 根据调用约定确定的
|
||||||
kRETAddr = 9, // 下一个要执行的命令地址,它将被分配给 rip
|
kRETAddr = 9, // 下一个要执行的命令地址,它将被分配给 rip
|
||||||
kRSP = 13, // 堆栈顶部指针
|
kRSP = 13, // 堆栈顶部指针
|
||||||
/*
|
|
||||||
|
|
||||||
|
/*
|
||||||
High memory
|
High memory
|
||||||
-----------------
|
-----------------
|
||||||
| 调用者的 rbp | <- 被调用函数栈帧的起点
|
| 调用者的 rbp | <- 被调用函数栈帧的起点
|
||||||
@ -19,7 +20,11 @@ namespace tinyrpc {
|
|||||||
-----------------
|
-----------------
|
||||||
Low memory
|
Low memory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct coctx { // Coroutine Context
|
struct coctx { // Coroutine Context
|
||||||
void* regs[14]{}; // 初始化为 0
|
void* regs[14]{}; // 初始化为 0
|
||||||
|
@ -5,21 +5,31 @@ namespace tinyrpc {
|
|||||||
|
|
||||||
|
|
||||||
class Coroutine {
|
class Coroutine {
|
||||||
|
friend void coFunction(Coroutine* co);
|
||||||
private:
|
private:
|
||||||
Coroutine();
|
Coroutine();
|
||||||
public:
|
public:
|
||||||
Coroutine(std::size_t stack_size, void* stack_sp);
|
Coroutine(std::size_t stack_size, char* stack_sp);
|
||||||
Coroutine(std::size_t stack_size, void* stack_sp, std::function<void()> cb);
|
Coroutine(std::size_t stack_size, char* stack_sp, std::function<void()> cb);
|
||||||
|
|
||||||
int getCorID() const {return m_cor_id;}
|
int getCorID() const {return m_cor_id;}
|
||||||
|
|
||||||
|
void operator()() const {
|
||||||
|
m_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// coctx* getContext() {return &m_ctx;}
|
||||||
|
|
||||||
|
static void yeild();
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
~Coroutine();
|
||||||
private:
|
private:
|
||||||
coctx m_ctx {}; // 这个协程的上下文信息
|
coctx m_ctx {}; // 这个协程的上下文信息
|
||||||
int m_cor_id {0}; // 这个协程的 id
|
int m_cor_id {0}; // 这个协程的 id
|
||||||
char* m_stack_sp {nullptr}; // 这个协程的栈空间指针
|
char* m_stack_sp {nullptr}; // 这个协程的栈空间指针
|
||||||
std::size_t m_stack_size {0};
|
std::size_t m_stack_size {0};
|
||||||
bool m_is_in_cofunc {true}; // 调用 CoFunction 时为真,CoFunction 完成时为假。
|
bool m_is_in_cofunc {true}; // 调用 CoFunction 时为真,CoFunction 完成时为假。
|
||||||
std::function<void()> m_callback {};
|
std::function<void()> m_callback {}; // 这个协程的回调
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -8,11 +8,13 @@ struct logger {
|
|||||||
logger() = default;
|
logger() = default;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::ostream& operator <<(T msg) {
|
std::ostream& operator << (T&& msg) {
|
||||||
return std::cout << __FILE__ << ":" << __LINE__ << " " << msg;
|
return std::cout << msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
~logger() {
|
~logger() {
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define logger() (logger() << __FILE__ << ":" << __LINE__ << " ")
|
78
src/coroutine/coroutine.cc
Normal file
78
src/coroutine/coroutine.cc
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "coroutine.hpp"
|
||||||
|
#include "coctx.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace tinyrpc {
|
||||||
|
static thread_local Coroutine* t_main_coroutine = nullptr; // thread_local: 每个线程有一个主协程
|
||||||
|
static thread_local Coroutine* t_curr_coroutine = nullptr;
|
||||||
|
static std::atomic_int t_coroutine_count {0};
|
||||||
|
|
||||||
|
void coFunction(Coroutine* co) {
|
||||||
|
if (co != nullptr) {
|
||||||
|
co->m_is_in_cofunc = true;
|
||||||
|
(*co)();
|
||||||
|
co->m_is_in_cofunc = false;
|
||||||
|
}
|
||||||
|
Coroutine::yeild();
|
||||||
|
}
|
||||||
|
|
||||||
|
Coroutine::Coroutine() { // 构造主协程
|
||||||
|
m_cor_id = t_coroutine_count++;
|
||||||
|
// t_main_coroutine = this;
|
||||||
|
t_main_coroutine = t_curr_coroutine = this;
|
||||||
|
|
||||||
|
logger() << "main coroutine has built";
|
||||||
|
}
|
||||||
|
|
||||||
|
Coroutine::Coroutine(std::size_t stack_size, char* stack_sp, std::function<void()> cb) :
|
||||||
|
m_stack_sp(stack_sp),
|
||||||
|
m_stack_size(stack_size),
|
||||||
|
m_callback(cb)
|
||||||
|
|
||||||
|
{ // 构造协程
|
||||||
|
m_cor_id = t_coroutine_count++;
|
||||||
|
|
||||||
|
if (t_main_coroutine == nullptr) {
|
||||||
|
t_main_coroutine = new Coroutine();
|
||||||
|
}
|
||||||
|
|
||||||
|
char* top = stack_sp + stack_size;
|
||||||
|
top = reinterpret_cast<char*>((reinterpret_cast<unsigned long long >(top) & (~0xfull))); // 8字节对齐
|
||||||
|
|
||||||
|
m_ctx.regs[reg::kRBP] = top;
|
||||||
|
m_ctx.regs[reg::kRSP] = top;
|
||||||
|
m_ctx.regs[reg::kRDI] = this;
|
||||||
|
m_ctx.regs[reg::kRETAddr] = reinterpret_cast<char*>(&coFunction);
|
||||||
|
m_ctx.regs[reg::kRDI] = reinterpret_cast<char*>(this);
|
||||||
|
logger() << "user coroutine has built";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coroutine::yeild() {
|
||||||
|
|
||||||
|
if (t_curr_coroutine == t_main_coroutine) {
|
||||||
|
logger() << "current coroutine is main coroutine !";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Coroutine* cur = t_curr_coroutine;
|
||||||
|
t_curr_coroutine = t_main_coroutine;
|
||||||
|
coctx_swap(&(cur->m_ctx), &(t_main_coroutine->m_ctx));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coroutine::resume() {
|
||||||
|
if (t_curr_coroutine != t_main_coroutine) {
|
||||||
|
logger() << "swap error, current coroutine must be main coroutine !";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t_curr_coroutine = this;
|
||||||
|
coctx_swap(&(t_main_coroutine->m_ctx), &(this->m_ctx));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Coroutine::~Coroutine() {
|
||||||
|
free(m_stack_sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
test/coroutine/main.cc
Normal file
44
test/coroutine/main.cc
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "coroutine.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace tinyrpc;
|
||||||
|
|
||||||
|
Coroutine* co1;
|
||||||
|
Coroutine* co2;
|
||||||
|
|
||||||
|
void coro1() {
|
||||||
|
|
||||||
|
cout << "this is coro1 begin" << endl;
|
||||||
|
|
||||||
|
Coroutine::yeild();
|
||||||
|
|
||||||
|
cout << "this is coro1 end" << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void coro2() {
|
||||||
|
|
||||||
|
cout << "this is coro2 begin" << endl;
|
||||||
|
|
||||||
|
Coroutine::yeild();
|
||||||
|
|
||||||
|
cout << "this is coro2 end" << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int stk_size = 4 * 1024 * 1024;
|
||||||
|
char* stk1 = static_cast<char*>(malloc(stk_size));
|
||||||
|
char* stk2 = static_cast<char*>(malloc(stk_size));
|
||||||
|
co1 = new Coroutine(stk_size, stk1, coro1);
|
||||||
|
co2 = new Coroutine(stk_size, stk2, coro2);
|
||||||
|
co1->resume();
|
||||||
|
co2->resume();
|
||||||
|
co1->resume();
|
||||||
|
co2->resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user