aboutsummaryrefslogtreecommitdiff
path: root/examples/coroutines/aco.h
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-05-02 22:50:18 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-05-02 22:50:18 -0400
commite476799ab7d0e26256ac9be25888e963dc0928a0 (patch)
tree75ad3ade720e57d74c984a19bfdb1ff05aeee75a /examples/coroutines/aco.h
parentaa6992613087f227df8f823e8ee41761c386840e (diff)
Move coroutines into examples folder due to compatibility issues on some
platforms/compilers
Diffstat (limited to 'examples/coroutines/aco.h')
-rw-r--r--examples/coroutines/aco.h214
1 files changed, 214 insertions, 0 deletions
diff --git a/examples/coroutines/aco.h b/examples/coroutines/aco.h
new file mode 100644
index 00000000..80d5542b
--- /dev/null
+++ b/examples/coroutines/aco.h
@@ -0,0 +1,214 @@
+// Copyright 2018 Sen Han <00hnes@gmail.com>
+// Modifications copyright 2025 Bruce Hill <bruce@bruce-hill.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef ACO_USE_VALGRIND
+ #include <valgrind/valgrind.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ACO_VERSION_MAJOR 2
+#define ACO_VERSION_MINOR 0
+#define ACO_VERSION_PATCH 0
+
+#ifdef __i386__
+ #define ACO_REG_IDX_RETADDR 0
+ #define ACO_REG_IDX_SP 1
+ #define ACO_REG_IDX_BP 2
+ #define ACO_REG_IDX_ARG1 0
+ #define ACO_REG_IDX_FPU 6
+#elif __x86_64__
+ #define ACO_REG_IDX_RETADDR 4
+ #define ACO_REG_IDX_SP 5
+ #define ACO_REG_IDX_BP 7
+ #define ACO_REG_IDX_EDI 8
+ #define ACO_REG_IDX_FPU 8
+#else
+ #error "platform not supported yet"
+#endif
+
+typedef struct {
+ void* ptr;
+ size_t sz;
+ size_t valid_sz;
+ // max copy size in bytes
+ size_t max_cpsz;
+ // copy from shared stack to this saved stack
+ size_t ct_save;
+ // copy from this saved stack to shared stack
+ size_t ct_restore;
+} aco_saved_stack_t;
+
+struct aco_s;
+typedef struct aco_s aco_t;
+
+typedef struct {
+ void* ptr;
+ size_t sz;
+ void* align_highptr;
+ void* align_retptr;
+ size_t align_validsz;
+ size_t align_limit;
+ aco_t* owner;
+
+ bool guard_page_enabled;
+ void* real_ptr;
+ size_t real_sz;
+
+#ifdef ACO_USE_VALGRIND
+ unsigned long valgrind_stk_id;
+#endif
+} aco_shared_stack_t;
+
+typedef void (*aco_cofuncp_t)(void*);
+
+struct aco_s {
+ // cpu registers' state
+#ifdef __i386__
+ #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ void* reg[6];
+ #else
+ void* reg[8];
+ #endif
+#elif __x86_64__
+ #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ void* reg[8];
+ #else
+ void* reg[9];
+ #endif
+#else
+ #error "platform not supported yet"
+#endif
+ aco_t* main_co;
+ void* arg;
+ bool is_finished;
+
+ aco_cofuncp_t fp;
+
+ aco_saved_stack_t saved_stack;
+ aco_shared_stack_t* shared_stack;
+};
+
+#define aco_likely(x) (__builtin_expect(!!(x), 1))
+
+#define aco_unlikely(x) (__builtin_expect(!!(x), 0))
+
+#define aco_assert(EX) ((aco_likely(EX))?((void)0):(abort()))
+
+#define aco_assertptr(ptr) ((aco_likely((ptr) != NULL))?((void)0):(abort()))
+
+#if defined(aco_attr_no_asan)
+ #error "aco_attr_no_asan already defined"
+#endif
+#if defined(ACO_USE_ASAN)
+ #if defined(__has_feature)
+ #if __has_feature(__address_sanitizer__)
+ #define aco_attr_no_asan \
+ __attribute__((__no_sanitize_address__))
+ #endif
+ #endif
+ #if defined(__SANITIZE_ADDRESS__) && !defined(aco_attr_no_asan)
+ #define aco_attr_no_asan \
+ __attribute__((__no_sanitize_address__))
+ #endif
+#endif
+#ifndef aco_attr_no_asan
+ #define aco_attr_no_asan
+#endif
+
+void aco_runtime_test(void);
+
+void aco_set_allocator(void* (*alloc)(size_t), void (*dealloc)(void*));
+
+void aco_thread_init(aco_cofuncp_t last_word_co_fp);
+
+void aco_yield_asm(aco_t* from_co, aco_t* to_co) __asm__("aco_yield_asm"); // asm
+
+void aco_save_fpucw_mxcsr(void* p) __asm__("aco_save_fpucw_mxcsr"); // asm
+
+void aco_funcp_protector_asm(void) __asm__("aco_funcp_protector_asm"); // asm
+
+void aco_funcp_protector(void);
+
+aco_shared_stack_t* aco_shared_stack_new(size_t sz);
+
+aco_shared_stack_t* aco_shared_stack_new2(size_t sz, bool guard_page_enabled);
+
+void aco_shared_stack_destroy(aco_shared_stack_t* sstk);
+
+aco_t* aco_create(
+ aco_t* main_co,
+ aco_shared_stack_t* shared_stack,
+ size_t saved_stack_sz,
+ aco_cofuncp_t fp, void* arg
+);
+
+// aco's Global Thread Local Storage variable `co`
+#ifdef __TINYC__
+ #error "TinyCC doesn't support thread-local storage!"
+#else
+extern __thread aco_t* aco_gtls_co;
+#endif
+
+aco_attr_no_asan
+void aco_resume(aco_t* resume_co);
+
+//void aco_yield1(aco_t* yield_co);
+#define aco_yield1(yield_co) do { \
+ aco_assertptr((yield_co)); \
+ aco_assertptr((yield_co)->main_co); \
+ aco_yield_asm((yield_co), (yield_co)->main_co); \
+} while (0)
+
+#define aco_yield() aco_yield1(aco_gtls_co)
+
+#define aco_get_arg() (aco_gtls_co->arg)
+
+#define aco_get_co() ({(void)0; aco_gtls_co;})
+
+void aco_destroy(aco_t* co);
+
+#define aco_is_main_co(co) ({((co)->main_co) == NULL;})
+
+#define aco_exit1(co) do { \
+ (co)->is_finished = true; \
+ aco_assert((co)->shared_stack->owner == (co)); \
+ (co)->shared_stack->owner = NULL; \
+ (co)->shared_stack->align_validsz = 0; \
+ aco_yield1((co)); \
+ aco_assert(0); \
+} while (0)
+
+#define aco_exit() aco_exit1(aco_gtls_co)
+
+void aco_exit_fn(void*);
+
+#ifdef __cplusplus
+}
+#endif