diff --git a/README.md b/README.md index 9fc7633..2c3a3ed 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,6 @@ To be clear, this is a programming paradigm on structuring your code. Which can You can read [Fibers, Oh My!](https://graphitemaster.github.io/fibers/) for a breakdown on how the actual context switch here is achieved by assembly. This library incorporates [libuv](http://docs.libuv.org) in a way that make providing callbacks unnecessary, same as in [Using C++ Resumable Functions with Libuv](https://devblogs.microsoft.com/cppblog/using-ibuv-with-c-resumable-functions/). **Libuv** is handling any hardware or multi-threading CPU access. This not necessary for library usage, the setup can be replaced with some other Event Loop library, or just disabled. There is a unmaintained [libasync](https://github.com/btrask/libasync) package tried combining **libco**, with **libuv** too, Linux only. -Two videos covering things to keep in mind about concurrency, [Building Scalable Deployments with Multiple Goroutines](https://www.youtube.com/watch?v=LNNaxHYFhw8) and [Detecting and Fixing Unbound Concurrency Problems](https://www.youtube.com/watch?v=gggi4GIvgrg). - ## Table of Contents * [Introduction](#introduction) @@ -55,9 +53,13 @@ All internal functions that needs memory allocation is using these routines. There will be at least one coroutine always present, the initial, required `co_main()`. When a coroutine finish execution either by returning or exceptions, memory is released/freed. +> Note: This _resources management system_ outlined above has been _decoupled_ to _external libraries_ and now brought in as _dependencies_. Where the above is just wrapper calls to: [c-raii](https://github.com/zelang-dev/c-raii) for complete **Defer**, plus **C++ RAII** behavior, with an custom **malloc** replacement [rpmalloc](https://github.com/zelang-dev/rpmalloc), and emulated **C11 Threads and thread Pool** [cthread](https://github.com/zelang-dev/cthread). + +- As such, the listed external libraries allow _smart auto memory management_ behaviors in any application, or any other **coroutine** library for that matter. + The other problem with **C** is the low level usage view. I initially started out with the concept of creating ***Yet Another Programming language***. -But after discovering [Cello High Level C](https://libcello.org/), and the general issues and need to still integrate with exiting C libraries. -This repo is now staging area the missing **C** runtime, [ZeLang](https://docs.zelang.dev). The documentation **WIP**. + +But after discovering [Cello High Level C](https://libcello.org/), realizing the general issues and need to still integrate with exiting C libraries. This repo is now the staging area for the missing **C** runtime, [ZeLang](https://docs.zelang.dev). The documentation **WIP**, and source code hasn't been updated to recent changes in this library. This **page**, `coroutine.h` and _examples folder_ files is the only current docs, but basic usage should be apparent. The _coroutine execution_ part here is _completed_, but how it operates/behaves with other system resources is what still being developed and tested. diff --git a/docs/index.md b/docs/index.md index 169920c..ef3d085 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,8 +14,6 @@ To be clear, this is a programming paradigm on structuring your code. Which can You can read [Fibers, Oh My!](https://graphitemaster.github.io/fibers/) for a breakdown on how the actual context switch here is achieved by assembly. This library incorporates [libuv](http://docs.libuv.org) in a way that make providing callbacks unnecessary, same as in [Using C++ Resumable Functions with Libuv](https://devblogs.microsoft.com/cppblog/using-ibuv-with-c-resumable-functions/). **Libuv** is handling any hardware or multi-threading CPU access. This not necessary for library usage, the setup can be replaced with some other Event Loop library, or just disabled. There is a unmaintained [libasync](https://github.com/btrask/libasync) package tried combining **libco**, with **libuv** too, Linux only. -Two videos covering things to keep in mind about concurrency, [Building Scalable Deployments with Multiple Goroutines](https://www.youtube.com/watch?v=LNNaxHYFhw8) and [Detecting and Fixing Unbound Concurrency Problems](https://www.youtube.com/watch?v=gggi4GIvgrg). - ## Table of Contents * [Introduction](#introduction) @@ -55,9 +53,13 @@ All internal functions that needs memory allocation is using these routines. There will be at least one coroutine always present, the initial, required `co_main()`. When a coroutine finish execution either by returning or exceptions, memory is released/freed. +> Note: This _resources management system_ outlined above has been _decoupled_ to _external libraries_ and now brought in as _dependencies_. Where the above is just wrapper calls to: [c-raii](https://github.com/zelang-dev/c-raii) for complete **Defer**, plus **C++ RAII** behavior, with an custom **malloc** replacement [rpmalloc](https://github.com/zelang-dev/rpmalloc), and emulated **C11 Threads and thread Pool** [cthread](https://github.com/zelang-dev/cthread). + +- As such, the listed external libraries allow _smart auto memory management_ behaviors in any application, or any other **coroutine** library for that matter. + The other problem with **C** is the low level usage view. I initially started out with the concept of creating ***Yet Another Programming language***. -But after discovering [Cello High Level C](https://libcello.org/), and the general issues and need to still integrate with exiting C libraries. -This repo is now staging area the missing **C** runtime, [ZeLang](https://docs.zelang.dev). The documentation **WIP**. + +But after discovering [Cello High Level C](https://libcello.org/), realizing the general issues and need to still integrate with exiting C libraries. This repo is now the staging area for the missing **C** runtime, [ZeLang](https://docs.zelang.dev). The documentation **WIP**, and source code hasn't been updated to recent changes in this library. This **page**, `coroutine.h` and _examples folder_ files is the only current docs, but basic usage should be apparent. The _coroutine execution_ part here is _completed_, but how it operates/behaves with other system resources is what still being developed and tested. diff --git a/include/coroutine.h b/include/coroutine.h index 4346e57..d2fd690 100644 --- a/include/coroutine.h +++ b/include/coroutine.h @@ -6,6 +6,8 @@ #endif #define time_Second 1000 +#define time_Minute 60000 +#define time_Hour 3600000 #include "uv_routine.h" #include "raii.h" @@ -740,6 +742,17 @@ C_API void coroutine_dec_count(void); C_API void coroutine_log_reset(void); C_API uv_args_t *coroutine_event_args(void); +/* Collect coroutines with references preventing immediate cleanup. */ +C_API void gc_coroutine(routine_t *); + +/* Collect channels with references preventing immediate cleanup. */ +C_API void gc_channel(channel_t *); + +C_API gc_channel_t *gc_channel_list(void); +C_API gc_coroutine_t *gc_coroutine_list(void); +C_API void gc_coroutine_free(void); +C_API void gc_channel_free(void); + C_API void channel_print(channel_t *); C_API channel_t *channel_create(int, int); C_API void channel_free(channel_t *); @@ -889,13 +902,6 @@ C_API string_t co_itoa(int64_t number); C_API int co_strpos(string_t text, string pattern); C_API void co_strcpy(string dest, string_t src, size_t len); -C_API void gc_coroutine(routine_t *); -C_API void gc_channel(channel_t *); -C_API gc_channel_t *gc_channel_list(void); -C_API gc_coroutine_t *gc_coroutine_list(void); -C_API void gc_coroutine_free(void); -C_API void gc_channel_free(void); - /* Check if validated by json type */ C_API bool is_json(json_t *); diff --git a/src/channel.c b/src/channel.c index a07b275..7c65f0b 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1,24 +1,24 @@ #include "coroutine.h" static thread_local int channel_id_generate = 0; -static thread_local gc_channel_t *channel_list = NULL; +thrd_local_static(gc_channel_t *, channel_list, NULL) static char error_message[ERROR_SCRAPE_SIZE] = {0}; void gc_channel(channel_t *ch) { - if (!channel_list) - channel_list = ht_channel_init(); + if (is_channel_list_empty()) + channel_list_update(ht_channel_init()); if (is_type(ch, CO_CHANNEL)) - hash_put(channel_list, co_itoa(ch->id), ch); + hash_put(channel_list(), co_itoa(ch->id), ch); } -CO_FORCE_INLINE gc_channel_t *gc_channel_list(void) { - return channel_list; +void gc_channel_free(void) { + if (!is_channel_list_empty()) + hash_free(channel_list()); } -void gc_channel_free(void) { - if (channel_list) - hash_free(channel_list); +CO_FORCE_INLINE gc_channel_t *gc_channel_list(void) { + return channel_list(); } channel_t *channel_create(int elem_size, int bufsize) { diff --git a/src/coroutine.c b/src/coroutine.c index d70dd6a..bac32e2 100644 --- a/src/coroutine.c +++ b/src/coroutine.c @@ -1,22 +1,22 @@ #include "coroutine.h" -static thread_local gc_coroutine_t *coroutine_list = NULL; +thrd_local_static(gc_coroutine_t *, coroutine_list, NULL) void gc_coroutine(routine_t *co) { - if (!coroutine_list) - coroutine_list = (gc_coroutine_t *)ht_group_init(); + if (is_coroutine_list_empty()) + coroutine_list_update(ht_group_init()); if (co->magic_number == CO_MAGIC_NUMBER) - hash_put(coroutine_list, co_itoa(co->cid), co); + hash_put(coroutine_list(), co_itoa(co->cid), co); } void gc_coroutine_free() { - if (coroutine_list) - hash_free(coroutine_list); + if (!is_coroutine_list_empty()) + hash_free(coroutine_list()); } CO_FORCE_INLINE gc_coroutine_t *gc_coroutine_list() { - return coroutine_list; + return coroutine_list(); } values_type args_get(void_t params, int item) {