aboutsummaryrefslogtreecommitdiff
path: root/lib
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 /lib
parentaa6992613087f227df8f823e8ee41761c386840e (diff)
Move coroutines into examples folder due to compatibility issues on some
platforms/compilers
Diffstat (limited to 'lib')
-rw-r--r--lib/coroutines/ACO_LICENSE202
-rw-r--r--lib/coroutines/README.md24
-rw-r--r--lib/coroutines/aco.c492
-rw-r--r--lib/coroutines/aco.h214
-rw-r--r--lib/coroutines/acoyield.S208
-rw-r--r--lib/coroutines/coroutines.tm67
6 files changed, 0 insertions, 1207 deletions
diff --git a/lib/coroutines/ACO_LICENSE b/lib/coroutines/ACO_LICENSE
deleted file mode 100644
index ef4f82f0..00000000
--- a/lib/coroutines/ACO_LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [2018] [Sen Han <00hnes@gmail.com>]
- Copyright [2024] [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.
diff --git a/lib/coroutines/README.md b/lib/coroutines/README.md
deleted file mode 100644
index eef923e0..00000000
--- a/lib/coroutines/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Tomo Coroutine Library
-
-This is a coroutine library built on top of a modified version of
-[libaco](https://libaco.org).
-
-## Example Usage
-
-```tomo
-use coroutines
-
-func main()
- co := Coroutine(func()
- say("I'm in the coroutine!")
- yield()
- say("I'm back in the coroutine!")
- )
- >> co
- say("I'm in the main func")
- >> co.resume()
- say("I'm back in the main func")
- >> co.resume()
- say("I'm back in the main func again")
- >> co.resume()
-```
diff --git a/lib/coroutines/aco.c b/lib/coroutines/aco.c
deleted file mode 100644
index 3226468b..00000000
--- a/lib/coroutines/aco.c
+++ /dev/null
@@ -1,492 +0,0 @@
-// 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.
-
-#define _GNU_SOURCE
-
-#include "aco.h"
-#include <stdio.h>
-#include <stdint.h>
-
-#ifndef public
-#define public __attribute__ ((visibility ("default")))
-#endif
-
-#define aco_size_t_safe_add_assert(a,b) aco_assert((a)+(b) >= (a))
-
-static void aco_default_protector_last_word(void*);
-
-void* (*aco_alloc_fn)(size_t) = malloc;
-void (*aco_dealloc_fn)(void*) = free;
-
-#define aco_alloc(size) ({ \
- void *_ptr = aco_alloc_fn(size); \
- if (aco_unlikely((_ptr) == NULL)) { \
- fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__); \
- abort(); \
- } \
- _ptr; \
-})
-
-// aco's Global Thread Local Storage variable `co`
-public __thread aco_t* aco_gtls_co;
-static __thread aco_cofuncp_t aco_gtls_last_word_fp = aco_default_protector_last_word;
-
-#ifdef __i386__
- static __thread void* aco_gtls_fpucw_mxcsr[2];
-#elif __x86_64__
- static __thread void* aco_gtls_fpucw_mxcsr[1];
-#else
- #error "platform not supporteded yet"
-#endif
-
-public void aco_runtime_test(void) {
-#ifdef __i386__
- _Static_assert(sizeof(void*) == 4, "require 'sizeof(void*) == 4'");
-#elif __x86_64__
- _Static_assert(sizeof(void*) == 8, "require 'sizeof(void*) == 8'");
- _Static_assert(sizeof(__uint128_t) == 16, "require 'sizeof(__uint128_t) == 16'");
-#else
- #error "platform not supporteded yet"
-#endif
- _Static_assert(sizeof(int) >= 4, "require 'sizeof(int) >= 4'");
- aco_assert(sizeof(int) >= 4);
- _Static_assert(sizeof(int) <= sizeof(size_t),
- "require 'sizeof(int) <= sizeof(size_t)'");
- aco_assert(sizeof(int) <= sizeof(size_t));
-}
-
-#ifdef __x86_64__
-static inline void aco_fast_memcpy(void *dst, const void *src, size_t sz) {
- if (((uintptr_t)src & 0x0f) != 0
- || ((uintptr_t)dst & 0x0f) != 0
- || (sz & 0x0f) != 0x08
- || (sz >> 4) > 8) {
- memcpy(dst, src, sz);
- return;
- }
-
- __uint128_t xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7;
- switch (sz >> 4) {
- case 0:
- break;
- case 1:
- xmm0 = *((__uint128_t*)src + 0);
- *((__uint128_t*)dst + 0) = xmm0;
- break;
- case 2:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- break;
- case 3:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- break;
- case 4:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- break;
- case 5:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- break;
- case 6:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- break;
- case 7:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- xmm6 = *((__uint128_t*)src + 6);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- *((__uint128_t*)dst + 6) = xmm6;
- break;
- case 8:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- xmm6 = *((__uint128_t*)src + 6);
- xmm7 = *((__uint128_t*)src + 7);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- *((__uint128_t*)dst + 6) = xmm6;
- *((__uint128_t*)dst + 7) = xmm7;
- break;
- }
- *((uint64_t*)((uintptr_t)dst + sz - 8)) = *((uint64_t*)((uintptr_t)src + sz - 8));
-}
-#endif
-
-void aco_default_protector_last_word(void*) {
- aco_t* co = aco_get_co();
- // do some log about the offending `co`
- fprintf(stderr,"error: aco_default_protector_last_word triggered\n");
- fprintf(stderr, "error: co:%p should call `aco_exit()` instead of direct "
- "`return` in co_fp:%p to finish its execution\n", co, (void*)co->fp);
- aco_assert(0);
-}
-
-public void aco_set_allocator(void* (*alloc)(size_t), void (*dealloc)(void*))
-{
- aco_alloc_fn = alloc;
- aco_dealloc_fn = dealloc;
-}
-
-public void aco_thread_init(aco_cofuncp_t last_word_co_fp) {
- aco_save_fpucw_mxcsr(aco_gtls_fpucw_mxcsr);
-
- if ((void*)last_word_co_fp != NULL)
- aco_gtls_last_word_fp = last_word_co_fp;
-}
-
-// This function `aco_funcp_protector` should never be
-// called. If it's been called, that means the offending
-// `co` didn't call aco_exit(co) instead of `return` to
-// finish its execution.
-public void aco_funcp_protector(void) {
- if ((void*)(aco_gtls_last_word_fp) != NULL) {
- aco_gtls_last_word_fp(NULL);
- } else {
- aco_default_protector_last_word(NULL);
- }
- aco_assert(0);
-}
-
-public aco_shared_stack_t* aco_shared_stack_new(size_t sz) {
- return aco_shared_stack_new2(sz, 1);
-}
-
-public aco_shared_stack_t* aco_shared_stack_new2(size_t sz, bool guard_page_enabled) {
- if (sz == 0) {
- sz = 1024 * 1024 * 2;
- }
- if (sz < 4096) {
- sz = 4096;
- }
- aco_assert(sz > 0);
-
- size_t u_pgsz = 0;
- if (guard_page_enabled) {
- // although gcc's Built-in Functions to Perform Arithmetic with
- // Overflow Checking is better, but it would require gcc >= 5.0
- long pgsz = sysconf(_SC_PAGESIZE);
- // pgsz must be > 0 && a power of two
- aco_assert(pgsz > 0 && (((pgsz - 1) & pgsz) == 0));
- u_pgsz = (size_t)((unsigned long)pgsz);
- // it should be always true in real life
- aco_assert(u_pgsz == (unsigned long)pgsz && ((u_pgsz << 1) >> 1) == u_pgsz);
- if (sz <= u_pgsz) {
- sz = u_pgsz << 1;
- } else {
- size_t new_sz;
- if ((sz & (u_pgsz - 1)) != 0) {
- new_sz = (sz & (~(u_pgsz - 1)));
- aco_assert(new_sz >= u_pgsz);
- aco_size_t_safe_add_assert(new_sz, (u_pgsz << 1));
- new_sz = new_sz + (u_pgsz << 1);
- aco_assert(sz / u_pgsz + 2 == new_sz / u_pgsz);
- } else {
- aco_size_t_safe_add_assert(sz, u_pgsz);
- new_sz = sz + u_pgsz;
- aco_assert(sz / u_pgsz + 1 == new_sz / u_pgsz);
- }
- sz = new_sz;
- aco_assert((sz / u_pgsz > 1) && ((sz & (u_pgsz - 1)) == 0));
- }
- }
-
- aco_shared_stack_t* p = aco_alloc(sizeof(aco_shared_stack_t));
- memset(p, 0, sizeof(aco_shared_stack_t));
-
- if (guard_page_enabled) {
- p->real_ptr = mmap(
- NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0
- );
- if (aco_unlikely(p->real_ptr == MAP_FAILED)) {
- fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n",
- __FILE__, __LINE__, __PRETTY_FUNCTION__);
- abort();
- }
- p->guard_page_enabled = true;
- aco_assert(0 == mprotect(p->real_ptr, u_pgsz, PROT_READ));
-
- p->ptr = (void*)(((uintptr_t)p->real_ptr) + u_pgsz);
- p->real_sz = sz;
- aco_assert(sz >= (u_pgsz << 1));
- p->sz = sz - u_pgsz;
- } else {
- //p->guard_page_enabled = 0;
- p->sz = sz;
- p->ptr = aco_alloc(sz);
- }
-
- p->owner = NULL;
-#ifdef ACO_USE_VALGRIND
- p->valgrind_stk_id = VALGRIND_STACK_REGISTER(
- p->ptr, (void*)((uintptr_t)p->ptr + p->sz)
- );
-#endif
-#if defined(__i386__) || defined(__x86_64__)
- uintptr_t u_p = (uintptr_t)(p->sz - (sizeof(void*) << 1) + (uintptr_t)p->ptr);
- u_p = (u_p >> 4) << 4;
- p->align_highptr = (void*)u_p;
- p->align_retptr = (void*)(u_p - sizeof(void*));
- *((void**)(p->align_retptr)) = (void*)(aco_funcp_protector_asm);
- aco_assert(p->sz > (16 + (sizeof(void*) << 1) + sizeof(void*)));
- p->align_limit = p->sz - 16 - (sizeof(void*) << 1);
-#else
- #error "platform not supporteded yet"
-#endif
- return p;
-}
-
-public void aco_shared_stack_destroy(aco_shared_stack_t* sstk) {
- aco_assert(sstk != NULL && sstk->ptr != NULL);
-#ifdef ACO_USE_VALGRIND
- VALGRIND_STACK_DEREGISTER(sstk->valgrind_stk_id);
-#endif
- if (sstk->guard_page_enabled) {
- aco_assert(0 == munmap(sstk->real_ptr, sstk->real_sz));
- sstk->real_ptr = NULL;
- sstk->ptr = NULL;
- } else {
- if (aco_dealloc_fn != NULL) aco_dealloc_fn(sstk->ptr);
- sstk->ptr = NULL;
- }
- if (aco_dealloc_fn != NULL) aco_dealloc_fn(sstk);
-}
-
-public 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_t* p = aco_alloc(sizeof(aco_t));
- memset(p, 0, sizeof(aco_t));
-
- if (main_co != NULL) { // non-main co
- aco_assertptr(shared_stack);
- p->shared_stack = shared_stack;
-#ifdef __i386__
- // POSIX.1-2008 (IEEE Std 1003.1-2008) - General Information - Data Types - Pointer Types
- // http://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/V2_chap02.html#tag_15_12_03
- p->reg[ACO_REG_IDX_RETADDR] = (void*)fp;
- // push retaddr
- p->reg[ACO_REG_IDX_SP] = p->shared_stack->align_retptr;
- #ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
- p->reg[ACO_REG_IDX_FPU + 1] = aco_gtls_fpucw_mxcsr[1];
- #endif
-#elif __x86_64__
- p->reg[ACO_REG_IDX_RETADDR] = (void*)fp;
- p->reg[ACO_REG_IDX_SP] = p->shared_stack->align_retptr;
- #ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
- #endif
-#else
- #error "platform not supporteded yet"
-#endif
- p->main_co = main_co;
- p->arg = arg;
- p->fp = fp;
- if (saved_stack_sz == 0) {
- saved_stack_sz = 64;
- }
- p->saved_stack.ptr = aco_alloc(saved_stack_sz);
- p->saved_stack.sz = saved_stack_sz;
-#if defined(__i386__) || defined(__x86_64__)
- p->saved_stack.valid_sz = 0;
-#else
- #error "platform not supporteded yet"
-#endif
- return p;
- } else { // main co
- p->main_co = NULL;
- p->arg = arg;
- p->fp = fp;
- p->shared_stack = NULL;
- p->saved_stack.ptr = NULL;
- return p;
- }
- aco_assert(0);
-}
-
-public aco_attr_no_asan
-void aco_resume(aco_t* resume_co) {
- aco_assert(resume_co != NULL && resume_co->main_co != NULL
- && !resume_co->is_finished
- );
- if (resume_co->shared_stack->owner != resume_co) {
- if (resume_co->shared_stack->owner != NULL) {
- aco_t* owner_co = resume_co->shared_stack->owner;
- aco_assert(owner_co->shared_stack == resume_co->shared_stack);
-#if defined(__i386__) || defined(__x86_64__)
- aco_assert(
- (
- (uintptr_t)(owner_co->shared_stack->align_retptr)
- >=
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
- )
- &&
- (
- (uintptr_t)(owner_co->shared_stack->align_highptr)
- -
- (uintptr_t)(owner_co->shared_stack->align_limit)
- <=
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
- )
- );
- owner_co->saved_stack.valid_sz =
- (uintptr_t)(owner_co->shared_stack->align_retptr)
- -
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]);
- if (owner_co->saved_stack.sz < owner_co->saved_stack.valid_sz) {
- if (aco_dealloc_fn != NULL) aco_dealloc_fn(owner_co->saved_stack.ptr);
- owner_co->saved_stack.ptr = NULL;
- while (1) {
- owner_co->saved_stack.sz = owner_co->saved_stack.sz << 1;
- aco_assert(owner_co->saved_stack.sz > 0);
- if (owner_co->saved_stack.sz >= owner_co->saved_stack.valid_sz) {
- break;
- }
- }
- owner_co->saved_stack.ptr = aco_alloc(owner_co->saved_stack.sz);
- }
- // TODO: optimize the performance penalty of memcpy function call
- // for very short memory span
- if (owner_co->saved_stack.valid_sz > 0) {
- #ifdef __x86_64__
- aco_fast_memcpy(
- owner_co->saved_stack.ptr,
- owner_co->reg[ACO_REG_IDX_SP],
- owner_co->saved_stack.valid_sz
- );
- #else
- memcpy(
- owner_co->saved_stack.ptr,
- owner_co->reg[ACO_REG_IDX_SP],
- owner_co->saved_stack.valid_sz
- );
- #endif
- owner_co->saved_stack.ct_save++;
- }
- if (owner_co->saved_stack.valid_sz > owner_co->saved_stack.max_cpsz) {
- owner_co->saved_stack.max_cpsz = owner_co->saved_stack.valid_sz;
- }
- owner_co->shared_stack->owner = NULL;
- owner_co->shared_stack->align_validsz = 0;
-#else
- #error "platform not supporteded yet"
-#endif
- }
- aco_assert(resume_co->shared_stack->owner == NULL);
-#if defined(__i386__) || defined(__x86_64__)
- aco_assert(
- resume_co->saved_stack.valid_sz
- <=
- resume_co->shared_stack->align_limit - sizeof(void*)
- );
- // TODO: optimize the performance penalty of memcpy function call
- // for very short memory span
- if (resume_co->saved_stack.valid_sz > 0) {
- void *dst = (void*)(
- (uintptr_t)(resume_co->shared_stack->align_retptr)
- - resume_co->saved_stack.valid_sz);
- #ifdef __x86_64__
- aco_fast_memcpy(dst, resume_co->saved_stack.ptr, resume_co->saved_stack.valid_sz);
- #else
- memcpy(dst, resume_co->saved_stack.ptr, resume_co->saved_stack.valid_sz);
- #endif
- resume_co->saved_stack.ct_restore++;
- }
- if (resume_co->saved_stack.valid_sz > resume_co->saved_stack.max_cpsz) {
- resume_co->saved_stack.max_cpsz = resume_co->saved_stack.valid_sz;
- }
- resume_co->shared_stack->align_validsz = resume_co->saved_stack.valid_sz + sizeof(void*);
- resume_co->shared_stack->owner = resume_co;
-#else
- #error "platform not supporteded yet"
-#endif
- }
- aco_gtls_co = resume_co;
- aco_yield_asm(resume_co->main_co, resume_co);
- aco_gtls_co = resume_co->main_co;
-}
-
-public void aco_destroy(aco_t* co) {
- aco_assertptr(co);
- if (aco_is_main_co(co)) {
- if (aco_dealloc_fn != NULL) aco_dealloc_fn(co);
- } else {
- if (co->shared_stack->owner == co) {
- co->shared_stack->owner = NULL;
- co->shared_stack->align_validsz = 0;
- }
- if (aco_dealloc_fn != NULL)
- aco_dealloc_fn(co->saved_stack.ptr);
- co->saved_stack.ptr = NULL;
- if (aco_dealloc_fn != NULL)
- aco_dealloc_fn(co);
- }
-}
-
-public void aco_exit_fn(void*) {
- aco_exit();
-}
diff --git a/lib/coroutines/aco.h b/lib/coroutines/aco.h
deleted file mode 100644
index 80d5542b..00000000
--- a/lib/coroutines/aco.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// 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
diff --git a/lib/coroutines/acoyield.S b/lib/coroutines/acoyield.S
deleted file mode 100644
index 7bc87ff1..00000000
--- a/lib/coroutines/acoyield.S
+++ /dev/null
@@ -1,208 +0,0 @@
-.text
-.globl aco_yield_asm
-#if defined(__APPLE__)
-#else
-.type aco_yield_asm, @function
-#endif
-.intel_syntax noprefix
-aco_yield_asm:
-/*
- extern void aco_yield_asm(aco_t* from_co, aco_t* to_co);
-
- struct aco_t {
- void* reg[X];
- // ...
- }
-
- reference:
- https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
-
- pitfall:
- http://man7.org/linux/man-pages/man7/signal.7.html
- http://man7.org/linux/man-pages/man2/sigaltstack.2.html
-
- > $ man 7 signal
- > ...
- > By default, the signal handler is invoked on the normal process
- > stack. It is possible to arrange that the signal handler
- > uses an alternate stack; see sigaltstack(2) for a discussion of
- > how to do this and when it might be useful.
- > ...
-
- This is a BUG example:
- https://github.com/Tencent/libco/blob/v1.0/coctx_swap.S#L27
-
- proof of correctness:
- https://github.com/hnes/libaco
-
- mxcsr & fpu:
- fnstcw * m2byte
- Store FPU control word to m2byte without checking for
- pending unmasked floating-point exceptions.
-
- fldcw m2byte
- Load FPU control word from m2byte.
-
- stmxcsr m32
- Store contents of MXCSR register to m32
-
- ldmxcsr m32
- Load MXCSR register from m32.
-*/
-/*
- 0x00 --> 0xff
- eip esp ebp edi esi ebx fpucw16 mxcsr32
- 0 4 8 c 10 14 18 1c
-*/
-#ifdef __i386__
- mov eax,DWORD PTR [esp+0x4] // from_co
- mov edx,DWORD PTR [esp] // retaddr
- lea ecx,[esp+0x4] // esp
- mov DWORD PTR [eax+0x8],ebp //<ebp
- mov DWORD PTR [eax+0x4],ecx //<esp
- mov DWORD PTR [eax+0x0],edx //<retaddr
- mov DWORD PTR [eax+0xc],edi //<edi
- mov ecx,DWORD PTR [esp+0x8] // to_co
- mov DWORD PTR [eax+0x10],esi //<esi
- mov DWORD PTR [eax+0x14],ebx //<ebx
-#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- fnstcw WORD PTR [eax+0x18] //<fpucw
- stmxcsr DWORD PTR [eax+0x1c] //<mxcsr
-#endif
- mov edx,DWORD PTR [ecx+0x4] //>esp
- mov ebp,DWORD PTR [ecx+0x8] //>ebp
- mov eax,DWORD PTR [ecx+0x0] //>retaddr
- mov edi,DWORD PTR [ecx+0xc] //>edi
- mov esi,DWORD PTR [ecx+0x10] //>esi
- mov ebx,DWORD PTR [ecx+0x14] //>ebx
-#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- fldcw WORD PTR [ecx+0x18] //>fpucw
- ldmxcsr DWORD PTR [ecx+0x1c] //>mxcsr
-#endif
- xor ecx,ecx
- mov esp,edx
- mov edx,eax
-
- // Pass the user-provided argument as first argument:
-#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- mov eax,DWORD PTR [ecx+0x24]
-#else
- mov eax,DWORD PTR [ecx+0x28]
-#endif
-
- jmp edx
-#elif __x86_64__
-/*
- 0x00 --> 0xff
- r12 r13 r14 r15 rip rsp rbx rbp fpucw16 mxcsr32
- 0 8 10 18 20 28 30 38 40 44
-*/
- // rdi - from_co | rsi - to_co
- mov rdx,QWORD PTR [rsp] // retaddr
- lea rcx,[rsp+0x8] // rsp
- mov QWORD PTR [rdi+0x0], r12
- mov QWORD PTR [rdi+0x8], r13
- mov QWORD PTR [rdi+0x10],r14
- mov QWORD PTR [rdi+0x18],r15
- mov QWORD PTR [rdi+0x20],rdx // retaddr
- mov QWORD PTR [rdi+0x28],rcx // rsp
- mov QWORD PTR [rdi+0x30],rbx
- mov QWORD PTR [rdi+0x38],rbp
-#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- fnstcw WORD PTR [rdi+0x40]
- stmxcsr DWORD PTR [rdi+0x44]
-#endif
- mov r12,QWORD PTR [rsi+0x0]
- mov r13,QWORD PTR [rsi+0x8]
- mov r14,QWORD PTR [rsi+0x10]
- mov r15,QWORD PTR [rsi+0x18]
- mov rax,QWORD PTR [rsi+0x20] // retaddr
- mov rcx,QWORD PTR [rsi+0x28] // rsp
- mov rbx,QWORD PTR [rsi+0x30]
- mov rbp,QWORD PTR [rsi+0x38]
-#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- fldcw WORD PTR [rsi+0x40]
- ldmxcsr DWORD PTR [rsi+0x44]
-#endif
-
- // Pass the user-provided argument as first argument:
-#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- mov rdi,QWORD PTR [rsi+0x48]
-#else
- mov rdi,QWORD PTR [rsi+0x50]
-#endif
-
- mov rsp,rcx
- jmp rax
-#else
- #error "platform not supported"
-#endif
-
-.globl aco_save_fpucw_mxcsr
-#if defined(__APPLE__)
-#else
-.type aco_save_fpucw_mxcsr, @function
-#endif
-.intel_syntax noprefix
-aco_save_fpucw_mxcsr:
-#ifdef __i386__
- mov eax,DWORD PTR [esp+0x4] // ptr
- fnstcw WORD PTR [eax]
- stmxcsr DWORD PTR [eax+0x4]
- ret
-#elif __x86_64__
- fnstcw WORD PTR [rdi]
- stmxcsr DWORD PTR [rdi+0x4]
- ret
-#else
- #error "platform not supported"
-#endif
-
-#if defined(__APPLE__)
-.globl _abort
-.globl _aco_funcp_protector
-#else
-.globl abort
-.globl aco_funcp_protector
-#endif
-
-.globl aco_funcp_protector_asm
-#if defined(__APPLE__)
-#else
-.type aco_funcp_protector_asm, @function
-#endif
-.intel_syntax noprefix
-aco_funcp_protector_asm:
-#ifdef __i386__
- and esp,0xfffffff0
- #if defined(__APPLE__)
- call _aco_funcp_protector
- call _abort
- #else
- #if defined(__pic__) || defined(__PIC__)
- call aco_funcp_protector@PLT
- call abort@PLT
- #else
- call aco_funcp_protector
- call abort
- #endif
- #endif
- ret
-#elif __x86_64__
- and rsp,0xfffffffffffffff0
- #if defined(__APPLE__)
- call _aco_funcp_protector
- call _abort
- #else
- #if defined(__pic__) || defined(__PIC__)
- call aco_funcp_protector@PLT
- call abort@PLT
- #else
- call aco_funcp_protector
- call abort
- #endif
- #endif
- ret
-#else
- #error "platform not supported"
-#endif
diff --git a/lib/coroutines/coroutines.tm b/lib/coroutines/coroutines.tm
deleted file mode 100644
index b530a685..00000000
--- a/lib/coroutines/coroutines.tm
+++ /dev/null
@@ -1,67 +0,0 @@
-# This is a coroutine library that uses libaco (https://libaco.org)
-#
-# Lua programmers will recognize this as similar to Lua's stackful coroutines.
-#
-# Async/Await programmers will weep at its beauty and gnash their teeth and
-# rend their garments in despair at what they could have had.
-
-use ./aco.h
-use ./aco.c
-use ./acoyield.S
-
-func main()
- say("Example usage")
- co := Coroutine(func()
- say("I'm in the coroutine!")
- yield()
- say("I'm back in the coroutine!")
- )
- >> co
- say("I'm in the main func")
- >> co.resume()
- say("I'm back in the main func")
- >> co.resume()
- say("I'm back in the main func again")
- >> co.resume()
-
-struct aco_t(; extern, opaque)
-struct aco_shared_stack_t(; extern, opaque)
-
-_main_co : @aco_t? = none
-_shared_stack : @aco_shared_stack_t? = none
-
-struct Coroutine(co:@aco_t)
- convert(fn:func() -> Coroutine)
- if not _main_co
- _init()
-
- main_co := _main_co
- shared_stack := _shared_stack
- aco_ptr := C_code:@aco_t(
- aco_create(@main_co, @shared_stack, 0, (void*)@fn.fn, @fn.userdata)
- )
- return Coroutine(aco_ptr)
-
- func is_finished(co:Coroutine->Bool; inline)
- return C_code:Bool(((aco_t*)@co.co)->is_finished)
-
- func resume(co:Coroutine->Bool)
- if co.is_finished()
- return no
- C_code { aco_resume(@co.co); }
- return yes
-
-func _init()
- C_code {
- aco_set_allocator(GC_malloc, NULL);
- aco_thread_init(aco_exit_fn);
- }
- _main_co = C_code:@aco_t(aco_create(NULL, NULL, 0, NULL, NULL))
-
- _shared_stack = C_code:@aco_shared_stack_t(aco_shared_stack_new(0))
-
-func yield(; inline)
- C_code {
- aco_yield();
- }
-