#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <iostream>
#include <queue>
#include <vector>
extern "C" void swap_context(void *, void *) asm("swap_context");
asm(R"(
swap_context:
mov 0x00(%rsp), %rdx
lea 0x08(%rsp), %rcx
mov %r12, 0x00(%rdi)
mov %r13, 0x08(%rdi)
mov %r14, 0x10(%rdi)
mov %r15, 0x18(%rdi)
mov %rdx, 0x20(%rdi)
mov %rcx, 0x28(%rdi)
mov %rbx, 0x30(%rdi)
mov %rbp, 0x38(%rdi)
mov 0x00(%rsi), %r12
mov 0x08(%rsi), %r13
mov 0x10(%rsi), %r14
mov 0x18(%rsi), %r15
mov 0x20(%rsi), %rax
mov 0x28(%rsi), %rcx
mov 0x30(%rsi), %rbx
mov 0x38(%rsi), %rbp
mov %rcx, %rsp
jmpq *%rax
)");
struct Context {
void *reg[8];
std::vector<char> mem;
Context(void (*func)() = nullptr) : mem(4096) {
reg[4] = (void *)func;
reg[5] = (char *)((uintptr_t)(&mem.back()) & ~15ull) - sizeof(void *);
}
} ma;
Context *current = nullptr;
void resume_coroutine(Context *coroutine) {
current = coroutine;
swap_context(&ma, current);
}
uint64_t GetMs() {
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_nsec / 1000000 + ts.tv_sec * 1000ull;
}
struct Task {
uint64_t expire;
Context *coroutine;
bool operator<(const Task &other) const { return expire > other.expire; }
};
std::priority_queue<Task> tasks;
void coroutine_sleep(int ms) {
uint64_t expire = GetMs() + ms;
tasks.push(Task{.expire = expire, .coroutine = current});
swap_context(current, &ma);
}
void event_loop(int timeout_in_seconds) {
uint64_t start = GetMs();
while (true) {
usleep(1000);
while (!tasks.empty()) {
if (GetMs() > tasks.top().expire) {
Task task = tasks.top();
tasks.pop();
resume_coroutine(task.coroutine);
} else {
break;
}
}
if ((GetMs() - start) > timeout_in_seconds * 1000) {
break;
}
}
}
void func1() {
while (true) {
std::cout << "Coroutine 1 print per 500ms" << std::endl;
coroutine_sleep(500);
}
}
void func2() {
while (true) {
std::cout << "Coroutine 2 print per 1000ms" << std::endl;
coroutine_sleep(1000);
}
}
int main() {
Context co1(func1);
resume_coroutine(&co1);
Context co2(func2);
resume_coroutine(&co2);
event_loop(5);
return 0;
}