Skip to content

Instantly share code, notes, and snippets.

@7shi
Created October 10, 2011 04:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 7shi/1274612 to your computer and use it in GitHub Desktop.
Save 7shi/1274612 to your computer and use it in GitHub Desktop.
コルーチンのコードを整理
#include "Coroutine.h"
_declspec(naked) int _fastcall mysetjmp(myjmp_buf *jbuf) {
_asm {
pop edx
mov [ecx ], edx
mov [ecx+ 4], esp
mov [ecx+ 8], ebp
mov [ecx+12], ebx
mov [ecx+16], edi
mov [ecx+20], esi
xor eax, eax
mov [ecx+24], eax
mov [ecx+28], eax
jmp edx
}
}
_declspec(naked) void _fastcall mylongjmp(myjmp_buf *jbuf, int value) {
_asm {
mov eax, edx
mov edx, ecx
mov esp, [edx+ 4]
mov edi, esp
mov esi, [edx+24]
mov ecx, [edx+28]
cld
rep movsb
mov ebp, [edx+ 8]
mov ebx, [edx+12]
mov edi, [edx+16]
mov esi, [edx+20]
jmp dword ptr [edx]
}
}
void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee) {
callee->length = last - callee->esp;
dest->resize(callee->length);
callee->stack = &(*dest)[0];
memcpy(callee->stack, (void *)callee->esp, callee->length);
}
std::stack<CoroutineBase *> coroutines;
CoroutineBase::~CoroutineBase() {}
#pragma once
#include <vector>
#include <functional>
#include <stack>
typedef struct {
unsigned long eip, esp, ebp, ebx, edi, esi;
void *stack;
int length;
} myjmp_buf;
extern int _fastcall mysetjmp(myjmp_buf *jbuf);
extern void _fastcall mylongjmp(myjmp_buf *jbuf, int value);
extern void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee);
class CoroutineBase {
public:
virtual ~CoroutineBase();
};
extern std::stack<CoroutineBase *> coroutines;
template <class T> class Coroutine : public CoroutineBase {
myjmp_buf caller, callee;
std::vector<char> stack;
std::function<void()> f;
int status;
unsigned long last;
void exec() {
f();
mylongjmp(&caller, 2);
}
public:
T value;
Coroutine() : status(0) {}
Coroutine(const decltype(f) &f) : f(f), status(0) {}
void operator=(const decltype(f) &f) { this->f = f; }
bool operator()() {
if (status == 0) _alloca(32 * 1024);
switch (mysetjmp(&caller)) {
case 1:
return true;
case 2:
coroutines.pop();
status = 3;
return false;
}
switch (status) {
case 0:
last = caller.esp;
status = 1;
coroutines.push(this);
exec();
case 2:
if (caller.esp < callee.esp)
return false;
status = 1;
coroutines.push(this);
mylongjmp(&callee, 1);
}
return false;
}
T yield(T value) {
if (coroutines.top() == this) {
coroutines.pop();
status = 2;
this->value = value;
if (mysetjmp(&callee) == 0) {
save_stack(&stack, last, &callee);
mylongjmp(&caller, 1);
}
}
return this->value;
}
};
template <class T> T yield(T value) {
auto cr = dynamic_cast<Coroutine<T> *>(coroutines.top());
return cr ? cr->yield(value) : T();
}
#include <iostream>
#include "Coroutine.h"
using namespace std;
void test() {
for (int i = 0; i <= 5; i++)
yield(i);
}
int main() {
Coroutine<int> cr = test;
while (cr())
cout << cr.value << endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment