mirror of https://github.com/RainMark/cops.git
6 changed files with 175 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
g++ -g -std=c++17 -I. *.cpp *.S -o cops |
||||
@ -0,0 +1,28 @@ |
|||||
|
#include <context.h> |
||||
|
#include <iostream> |
||||
|
|
||||
|
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<coro_t*>(from); |
||||
|
next_->ctx_ = from; |
||||
|
} |
||||
|
|
||||
|
void coro_t::switch_in() { |
||||
|
next_ = current; |
||||
|
current = this; |
||||
|
ctx_ = switch_context(this, ctx_); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
#include <stdint.h> |
||||
|
|
||||
|
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<void(void)>; |
||||
|
|
||||
|
explicit coro_t(Fn&& fn) |
||||
|
: fn_(std::forward<Fn>(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 <class Fn> |
||||
|
std::unique_ptr<coro_t> make_coro(Fn&& fn) { |
||||
|
auto coro = std::make_unique<coro_t>(std::forward<Fn>(fn)); |
||||
|
coro->ctx_ = make_context(coro->stack_.sp(), (void*)main); |
||||
|
return coro; |
||||
|
} |
||||
|
|
||||
|
} // cops
|
||||
@ -0,0 +1,26 @@ |
|||||
|
#include <iostream> |
||||
|
#include <context.h> |
||||
|
|
||||
|
int main() { |
||||
|
std::unique_ptr<cops::coro_t> coro; |
||||
|
std::unique_ptr<cops::coro_t> 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; |
||||
|
} |
||||
@ -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 |
||||
Loading…
Reference in new issue