From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- src/base/coro/coro.c | 43 ++++++++++++++++++ src/base/coro/internal.h | 15 +++++++ src/base/coro/rules.mk | 3 ++ src/base/coro/unix_x64.s | 113 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 src/base/coro/coro.c create mode 100644 src/base/coro/internal.h create mode 100644 src/base/coro/rules.mk create mode 100644 src/base/coro/unix_x64.s (limited to 'src/base/coro') 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 +#include + +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 -- cgit v1.2.1