code / tomo-coroutines

Lines715 C545 Assembly92 Tomo47 Markdown31
(213 lines)
1 // A coroutine library
2 // Copyright 2018 Sen Han <00hnes@gmail.com>
3 // Modifications copyright 2025 Bruce Hill <bruce@bruce-hill.com>
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 #pragma once
19 #include <limits.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/mman.h>
26 #include <time.h>
27 #include <unistd.h>
29 #ifdef ACO_USE_VALGRIND
30 #include <valgrind/valgrind.h>
31 #endif
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
37 #define ACO_VERSION_MAJOR 2
38 #define ACO_VERSION_MINOR 0
39 #define ACO_VERSION_PATCH 0
41 #ifdef __i386__
42 #define ACO_REG_IDX_RETADDR 0
43 #define ACO_REG_IDX_SP 1
44 #define ACO_REG_IDX_BP 2
45 #define ACO_REG_IDX_ARG1 0
46 #define ACO_REG_IDX_FPU 6
47 #elif __x86_64__
48 #define ACO_REG_IDX_RETADDR 4
49 #define ACO_REG_IDX_SP 5
50 #define ACO_REG_IDX_BP 7
51 #define ACO_REG_IDX_EDI 8
52 #define ACO_REG_IDX_FPU 8
53 #else
54 #error "platform not supported yet"
55 #endif
57 typedef struct {
58 void *ptr;
59 size_t sz;
60 size_t valid_sz;
61 // max copy size in bytes
62 size_t max_cpsz;
63 // copy from shared stack to this saved stack
64 size_t ct_save;
65 // copy from this saved stack to shared stack
66 size_t ct_restore;
67 } aco_saved_stack_t;
69 struct aco_s;
70 typedef struct aco_s aco_t;
72 typedef struct {
73 void *ptr;
74 size_t sz;
75 void *align_highptr;
76 void *align_retptr;
77 size_t align_validsz;
78 size_t align_limit;
79 aco_t *owner;
81 bool guard_page_enabled;
82 void *real_ptr;
83 size_t real_sz;
85 #ifdef ACO_USE_VALGRIND
86 unsigned long valgrind_stk_id;
87 #endif
88 } aco_shared_stack_t;
90 typedef void (*aco_cofuncp_t)(void *);
92 struct aco_s {
93 // cpu registers' state
94 #ifdef __i386__
95 #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
96 void *reg[6];
97 #else
98 void *reg[8];
99 #endif
100 #elif __x86_64__
101 #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
102 void *reg[8];
103 #else
104 void *reg[9];
105 #endif
106 #else
107 #error "platform not supported yet"
108 #endif
109 aco_t *main_co;
110 void *arg;
111 bool is_finished;
113 aco_cofuncp_t fp;
115 aco_saved_stack_t saved_stack;
116 aco_shared_stack_t *shared_stack;
119 #define aco_likely(x) (__builtin_expect(!!(x), 1))
121 #define aco_unlikely(x) (__builtin_expect(!!(x), 0))
123 #define aco_assert(EX) ((aco_likely(EX)) ? ((void)0) : (abort()))
125 #define aco_assertptr(ptr) ((aco_likely((ptr) != NULL)) ? ((void)0) : (abort()))
127 #if defined(aco_attr_no_asan)
128 #error "aco_attr_no_asan already defined"
129 #endif
130 #if defined(ACO_USE_ASAN)
131 #if defined(__has_feature)
132 #if __has_feature(__address_sanitizer__)
133 #define aco_attr_no_asan __attribute__((__no_sanitize_address__))
134 #endif
135 #endif
136 #if defined(__SANITIZE_ADDRESS__) && !defined(aco_attr_no_asan)
137 #define aco_attr_no_asan __attribute__((__no_sanitize_address__))
138 #endif
139 #endif
140 #ifndef aco_attr_no_asan
141 #define aco_attr_no_asan
142 #endif
144 void aco_runtime_test(void);
146 void aco_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *));
148 void aco_thread_init(aco_cofuncp_t last_word_co_fp);
150 void aco_yield_asm(aco_t *from_co, aco_t *to_co) __asm__("aco_yield_asm"); // asm
152 void aco_save_fpucw_mxcsr(void *p) __asm__("aco_save_fpucw_mxcsr"); // asm
154 void aco_funcp_protector_asm(void) __asm__("aco_funcp_protector_asm"); // asm
156 void aco_funcp_protector(void);
158 aco_shared_stack_t *aco_shared_stack_new(size_t sz);
160 aco_shared_stack_t *aco_shared_stack_new2(size_t sz, bool guard_page_enabled);
162 void aco_shared_stack_destroy(aco_shared_stack_t *sstk);
164 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);
166 // aco's Global Thread Local Storage variable `co`
167 #ifdef __TINYC__
168 #error "TinyCC doesn't support thread-local storage!"
169 #else
170 extern __thread aco_t *aco_gtls_co;
171 #endif
173 aco_attr_no_asan void aco_resume(aco_t *resume_co);
175 // void aco_yield1(aco_t* yield_co);
176 #define aco_yield1(yield_co) \
177 do { \
178 aco_assertptr((yield_co)); \
179 aco_assertptr((yield_co)->main_co); \
180 aco_yield_asm((yield_co), (yield_co)->main_co); \
181 } while (0)
183 #define aco_yield() aco_yield1(aco_gtls_co)
185 #define aco_get_arg() (aco_gtls_co->arg)
187 #define aco_get_co() \
188 ({ \
189 (void)0; \
190 aco_gtls_co; \
193 void aco_destroy(aco_t *co);
195 #define aco_is_main_co(co) ({ ((co)->main_co) == NULL; })
197 #define aco_exit1(co) \
198 do { \
199 (co)->is_finished = true; \
200 aco_assert((co)->shared_stack->owner == (co)); \
201 (co)->shared_stack->owner = NULL; \
202 (co)->shared_stack->align_validsz = 0; \
203 aco_yield1((co)); \
204 aco_assert(0); \
205 } while (0)
207 #define aco_exit() aco_exit1(aco_gtls_co)
209 void aco_exit_fn(void *);
211 #ifdef __cplusplus
213 #endif