Skip to content

Instantly share code, notes, and snippets.

@cutthroat
Created October 11, 2012 15:57
Show Gist options
  • Save cutthroat/3873382 to your computer and use it in GitHub Desktop.
Save cutthroat/3873382 to your computer and use it in GitHub Desktop.
Simple C coroutines on AMD64/SysV
#pragma once
/* Each coroutine is represented by a pointer to its stack bottom. */
typedef void *co_coro;
/* The coroutine procedure takes the calling coroutine as its first argument. */
typedef void (*co_proc)(co_coro back);
/* Switch to new coroutine. The stack top must be 16 byte aligned.*/
void *
co_boot(void *stack_top, co_proc proc);
/* Switch to coro. In coro return self. */
void *
co_back(co_coro coro);
/* Switch to coro. In coro return data. */
void *
co_jump(co_coro coro, void *data);
# context %rbp %rbx %r12 %r13 %r14 %r15
# argument order %rdi %rsi %rdx %rcx %r8 %r9
.macro save_ctx
push %rbp
push %rbx
push %r12
push %r13
push %r14
push %r15
.endm
.macro load_ctx
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
.endm
.text
.global co_boot
co_boot:
save_ctx
# switch
xchg %rsp, %rdi
# enter
call *%rsi
# if we have no other choice
mov $0, %rdi
call exit
.global co_back
co_back:
save_ctx
# switch
mov %rsp, %rax
mov %rdi, %rsp
load_ctx
ret
.global co_jump
co_jump:
save_ctx
# switch
mov %rsi, %rax
mov %rdi, %rsp
load_ctx
ret
# vim: ft=asm
#!/bin/bash -e
gcc -m64 -mabi=sysv -Wall -o ping_pong ping_pong.c amd64_sysv_asm.s
#include <stdlib.h>
#include <unistd.h>
#include "amd64_sysv.h"
static unsigned long ping_stack[128];
static unsigned long pong_stack[128];
static unsigned long rounds = -1;
static void *
stack_top(void *bot, size_t len)
{
return bot + len;
}
static void
ping_proc(co_coro boot)
{
co_coro pong;
write(1, "ping init\n", 10);
pong = co_back(boot);
while (rounds-- > 0) {
write(1, "ping\n", 5);
pong = co_back(pong);
}
}
static void
pong_proc(co_coro boot)
{
co_coro ping;
write(1, "pong init\n", 10);
ping = co_back(boot);
while (rounds-- > 0) {
write(1, "pong\n", 5);
ping = co_back(ping);
}
}
int
main()
{
co_coro ping, pong;
ping = co_boot(stack_top(ping_stack, sizeof ping_stack), ping_proc);
pong = co_boot(stack_top(pong_stack, sizeof pong_stack), pong_proc);
co_jump(ping, pong);
exit(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment