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