aboutsummaryrefslogtreecommitdiff
path: root/src/base/coro
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/coro')
-rw-r--r--src/base/coro/coro.c43
-rw-r--r--src/base/coro/internal.h15
-rw-r--r--src/base/coro/rules.mk3
-rw-r--r--src/base/coro/unix_x64.s113
4 files changed, 174 insertions, 0 deletions
diff --git a/src/base/coro/coro.c b/src/base/coro/coro.c
new file mode 100644
index 0000000..2255c99
--- /dev/null
+++ b/src/base/coro/coro.c
@@ -0,0 +1,43 @@
+#include "internal.h"
+
+/* Co-routine context */
+Coro*
+coro·make(uintptr stk, uintptr (*func)(Coro*, uintptr))
+{
+ if (!func) return nil;
+ if (stk == 0) stk = 8192;
+
+ byte *block = malloc(stk);
+ Coro *co = (Coro*)&block[stk - sizeof(Coro)];
+ co->bp = block;
+ co->size = stk;
+
+ _newcoro(co, func, co);
+ return co;
+}
+
+error
+coro·free(Coro *co)
+{
+ enum
+ {
+ NIL,
+ GOOD,
+ EMPTY,
+ LOST,
+ };
+
+ if (!co) return NIL;
+ if (!co->bp) return LOST;
+ if (co->size == 0) return EMPTY;
+
+ free(co->bp);
+
+ return GOOD;
+}
+
+uintptr
+coro·yield(Coro *c, uintptr arg)
+{
+ return _coroyield(c, arg);
+}
diff --git a/src/base/coro/internal.h b/src/base/coro/internal.h
new file mode 100644
index 0000000..f57d27b
--- /dev/null
+++ b/src/base/coro/internal.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <u.h>
+#include <base.h>
+
+extern void _newcoro(Coro *co, uintptr (*func)(Coro*, uintptr), void *stk);
+extern uintptr _coroyield(Coro *co, uintptr arg);
+
+struct Coro
+{
+ void *sp;
+ void *bp;
+ uintptr size;
+ void *user;
+};
diff --git a/src/base/coro/rules.mk b/src/base/coro/rules.mk
new file mode 100644
index 0000000..c2ee89f
--- /dev/null
+++ b/src/base/coro/rules.mk
@@ -0,0 +1,3 @@
+SRCS_$(d)+=\
+ $(d)/coro/coro.c\
+ $(d)/coro/unix_x64.s\
diff --git a/src/base/coro/unix_x64.s b/src/base/coro/unix_x64.s
new file mode 100644
index 0000000..d7de2a2
--- /dev/null
+++ b/src/base/coro/unix_x64.s
@@ -0,0 +1,113 @@
+; Nicholas Noll 2019
+;
+; ===================================================================
+%use altreg
+
+ bits 64
+ default rel
+ global _newcoro
+ global _coroyield
+
+; ===================================================================
+ section .text
+; -------------------------------------------------------------------
+
+%assign L.coro -8
+%assign L.func -16
+
+coroinit:
+ mov R7, [RBP + L.coro]
+ mov R6, R0
+ call [RBP + L.func]
+
+rerun:
+ mov R7, [RBP + L.coro]
+ mov R6, R0
+ call _coroyield
+ jmp rerun
+
+; -------------------------------------------------------------------
+; # Register Mapping
+;
+; R0 R1 R2 R3 R4 R5 R6 R7 R8 ...
+; RAX RCX RDX RBX RSP RBP RSI RDI R8 ...
+;
+; # Sys V calling convention
+; func(R7, R6, R2, R1, R8, R9, Z0-7): R0
+;
+; # Stack layout of an in-flight coro
+; *coro
+; *func
+; *bp (base pointer of stack)
+; ....... STACK .........
+; Saved Clobbers
+;
+; ###
+; Stack layout of an init coro
+; Stores the func pointer to init
+; Stores the clobber registers.
+;
+; L.coro [8]
+; L.func [7]
+; coroinit [6]
+; RBP [5]
+; R3 [4]
+; R12 [3]
+; R13 [2]
+; R14 [1]
+; R15 [0]
+
+%define WORDSZ 8
+%define NSAVES 9
+
+; coro *coro·new(co *coro, fn func, bp *stack)
+_newcoro:
+ lea R0, [coroinit] ; Store address of init function
+ lea R1, [R2 - NSAVES*WORDSZ] ; Store offset address of stack
+
+ mov [R1 + 8*WORDSZ], R7 ; Store context pointer
+ mov [R1 + 7*WORDSZ], R6 ; Store function pointer
+ mov [R1 + 6*WORDSZ], R0 ; Store initializer pointer
+ mov [R1 + 5*WORDSZ], R2 ; Store stack base pointer
+
+ xor R0, R0
+
+ ; Start of mutable stack
+ ; Blank out the clobbers
+ mov [R1 + 4*WORDSZ], R0 ; R3
+ mov [R1 + 3*WORDSZ], R0 ; R12
+ mov [R1 + 2*WORDSZ], R0 ; R13
+ mov [R1 + 1*WORDSZ], R0 ; R14
+ mov [R1 + 0*WORDSZ], R0 ; R15
+
+ mov [R7], R1
+ ret
+
+; Saves register state
+%macro pushclobs 0
+ push RBP
+ push R3
+ push R12
+ push R13
+ push R14
+ push R15
+%endmacro
+
+; Restores register state
+%macro popclobs 0
+ pop R15
+ pop R14
+ pop R13
+ pop R12
+ pop R3
+ pop RBP
+%endmacro
+
+; uintptr coro.yield(co *coro, data uintptr)
+_coroyield:
+ pushclobs
+ mov R0, R6 ; Move return value into return register.
+ xchg RSP, [R7] ; Atomically swap the stack pointer with the yieldee.
+ popclobs
+
+ ret