From 53ad16b79a6cf2ef4f94e282cf5fc0d50b37d2b1 Mon Sep 17 00:00:00 2001 From: Rain Date: Sat, 22 Jan 2022 21:03:38 +0800 Subject: [PATCH] add cops impl Signed-off-by: Rain --- .gitignore | 2 ++ build.sh | 3 +++ context.cpp | 28 ++++++++++++++++++++ context.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 26 ++++++++++++++++++ switch_context.S | 48 ++++++++++++++++++++++++++++++++++ 6 files changed, 175 insertions(+) create mode 100755 build.sh create mode 100644 context.cpp create mode 100644 context.h create mode 100644 main.cpp create mode 100644 switch_context.S diff --git a/.gitignore b/.gitignore index 259148f..e7790e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Prerequisites *.d +cops + # Compiled Object files *.slo *.lo diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..c2105ca --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +g++ -g -std=c++17 -I. *.cpp *.S -o cops diff --git a/context.cpp b/context.cpp new file mode 100644 index 0000000..176b694 --- /dev/null +++ b/context.cpp @@ -0,0 +1,28 @@ +#include +#include + +namespace cops{ + +static coro_t def([](){}); +coro_t* current = &def; + +void main(coro_t* coro, context from) { + coro->next_->ctx_ = from; + coro->fn_(); + coro->switch_out(); +} + +void coro_t::switch_out() { + current = next_; + context from = switch_context(next_, next_->ctx_); + next_ = static_cast(from); + next_->ctx_ = from; +} + +void coro_t::switch_in() { + next_ = current; + current = this; + ctx_ = switch_context(this, ctx_); +} + +} diff --git a/context.h b/context.h new file mode 100644 index 0000000..2084e93 --- /dev/null +++ b/context.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include + +namespace cops { +class coro_t; +} + +using context = void*; + +extern "C" +context switch_context(cops::coro_t* to, context ctx); +extern "C" +context make_context(context sp, void* entry); + +namespace cops { + +class stack_t { +public: + stack_t(size_t size = 64 * 1024) : size_(size) { + sp_ = new char[size_]; + } + ~stack_t() { + delete[] sp_; + } + + void* sp() { + return sp_ + size_ - 1; + } + +private: + char* sp_; + size_t size_; +}; + +class coro_t { +public: + using Fn = std::function; + + explicit coro_t(Fn&& fn) + : fn_(std::forward(fn)) { + } + ~coro_t() { + } + + void switch_out(); + void switch_in(); + +public: + context ctx_; + coro_t* next_; + stack_t stack_; + Fn fn_; +}; + +extern coro_t* current; +void main(coro_t* coro, context ctx); + +template +std::unique_ptr make_coro(Fn&& fn) { + auto coro = std::make_unique(std::forward(fn)); + coro->ctx_ = make_context(coro->stack_.sp(), (void*)main); + return coro; +} + +} // cops diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..4d4a10d --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +#include +#include + +int main() { + std::unique_ptr coro; + std::unique_ptr sub_coro; + coro = cops::make_coro([&sub_coro]() { + std::cout << "coro" << std::endl; + cops::current->switch_out(); + sub_coro = cops::make_coro([]() { + std::cout << "sub_coro" << std::endl; + cops::current->switch_out(); + std::cout << "sub_coro exit" << std::endl; + }); + sub_coro->switch_in(); + std::cout << "coro exit" << std::endl; + }); + std::cout << "main" << std::endl; + coro->switch_in(); + std::cout << "main" << std::endl; + coro->switch_in(); + std::cout << "main" << std::endl; + sub_coro->switch_in(); + std::cout << "exit" << std::endl; + return 0; +} diff --git a/switch_context.S b/switch_context.S new file mode 100644 index 0000000..352dba0 --- /dev/null +++ b/switch_context.S @@ -0,0 +1,48 @@ +.file "switch_context.S" +.text +.globl switch_context +.type switch_context,@function +.align 16 +switch_context: + leaq -56(%rsp), %rsp + movq %rdi, (%rsp) /* save suspended coro_t* */ + + movq %r12, 8(%rsp) + movq %r13, 16(%rsp) + movq %r14, 24(%rsp) + movq %r15, 32(%rsp) + movq %rbx, 40(%rsp) + movq %rbp, 48(%rsp) + + movq %rsp, %rax /* return suspended context */ + + movq %rsi, %rsp /* restore context */ + movq 56(%rsp), %r8 /* return point */ + + movq 8(%rsp), %r12 + movq 16(%rsp), %r13 + movq 24(%rsp), %r14 + movq 32(%rsp), %r15 + movq 40(%rsp), %rbx + movq 48(%rsp), %rbp + + leaq 64(%rsp), %rsp + + movq %rax, %rsi /* for main(coro_t*, context) 2rd argument */ + + jmp *%r8 +.size switch_context,.-switch_context +.section .note.GNU-stack,"",%progbits + +.text +.globl make_context +.type make_context,@function +.align 16 +make_context: + andq $-16, %rdi /* 16 bytes align for movdqa */ + leaq -56(%rdi), %rdi + movq %rsi, 56(%rdi) /* set entry */ + movq %rdi, %rax /* return updated context */ + retq +.size make_context,.-make_context +.section .note.GNU-stack,"",%progbits