{"id":16991646,"url":"https://github.com/pstolarz/coopthreads","last_synced_at":"2025-03-22T15:30:58.557Z","repository":{"id":44752153,"uuid":"247685082","full_name":"pstolarz/CoopThreads","owner":"pstolarz","description":"Lightweight, platform agnostic, stackful cooperative threads library.","archived":false,"fork":false,"pushed_at":"2024-03-28T16:36:24.000Z","size":98,"stargazers_count":32,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-18T13:15:36.411Z","etag":null,"topics":["arduino","arduino-library","cooperative","multitasking","multithreading","scheduler","threads"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pstolarz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-16T11:29:00.000Z","updated_at":"2024-12-19T04:10:53.000Z","dependencies_parsed_at":"2024-03-28T17:30:30.405Z","dependency_job_id":"f2d74390-1ccd-45c2-b8a5-a63621bf1398","html_url":"https://github.com/pstolarz/CoopThreads","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pstolarz%2FCoopThreads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pstolarz%2FCoopThreads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pstolarz%2FCoopThreads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pstolarz%2FCoopThreads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pstolarz","download_url":"https://codeload.github.com/pstolarz/CoopThreads/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244978510,"owners_count":20541864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","arduino-library","cooperative","multitasking","multithreading","scheduler","threads"],"created_at":"2024-10-14T03:26:45.731Z","updated_at":"2025-03-22T15:30:58.144Z","avatar_url":"https://github.com/pstolarz.png","language":"C","readme":"# CoopThreads\n[![Arduino builds](https://github.com/pstolarz/CoopThreads/actions/workflows/arduino-builds.yml/badge.svg?branch=master)](https://github.com/pstolarz/CoopThreads/actions/workflows/arduino-builds.yml)\n[![Tests status](https://github.com/pstolarz/CoopThreads/actions/workflows/ut.yml/badge.svg?branch=master)](https://github.com/pstolarz/CoopThreads/actions/workflows/ut.yml)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/pstolarz/library/CoopThreads.svg)](https://registry.platformio.org/libraries/pstolarz/CoopThreads)\n\u003cbr\u003e\n\n`CoopThreads` is a lightweight, platform agnostic, stackful cooperative threads\nlibrary with round-robin scheduler. The library is intended to be used on\nresource constrained platforms (e.g. 8-bit AVR) where using fully-fledged RTOS\nwould be problematic.\n\nThe library has been tested on the following platforms:\n\n* Arduino AVR.\n    * Tested on Arduino UNO (ATmega328P).\n* Arduino ESP32.\n    * Tested on ESP32-WROOM-32\n* Arduino ESP8266.\n    * Tested on WeMos D1\n* STM32CubeMX (HAL API)\n    * Tested on STM32WB5MMG\n* Unix/POSIX\n    * Mostly used for unit testing. See [`extras/test`](extras/test) directory\n      content as a reference how to use the library on POSIX conforming platforms.\n\n## Features\n\n* Core of the library uses `setjmp(3)`/`longjmp(3)` (part of standard C library)\n  and `alloca(3)` to save/restore execution context and allocate thread stacks\n  respectively. Therefore it shall be possible to use for large number of\n  conforming platforms.\n* `CoopThreads` doesn't use heap memory. Threads stacks are allocated on the\n  main stack the library runs on. No stack copy occurs on thread context switch.\n* Idle related API allows switching the platform to a desired sleep mode and\n  reduce power consumption.\n* Wait/notify support for effective threads synchronization.\n* Small and configurable footprint. Unused features may be turned off and reduce\n  footprint of a compiled image.\n* Although the library was created for Arduino environment in mind, it may be\n  easily ported for other development platforms. See [Platform Callbacks](#platform-callbacks)\n  section for more details.\n\n## Usage\n\nRefer to [`examples`](examples) directory for examples presenting usage of the\nvarious library features in Arduino environment. Thorough API specification is\ncontained as inline documentation in [`src/coop_threads.h`](src/coop_threads.h)\nheader.\n\nFile [`src/coop_config.h`](src/coop_config.h) contains parameters\nconfiguring the library functionality. See the file for more details.\n\n## Thread Stack\n\n`CoopThreads` is a stackful threads library, which means each thread running\nunder control of the library works on its own stack. The stack size may be set\nfor each thread separately during thread creation. It's important to note the\nthread stacks are created on the main stack the library code is running on,\ntherefore it is **critical to assure proper main stack size while using the\nlibrary.**\n\nThe library controls thread stack creation and removal as explained on the\nfollowing example.\n\n```\n|  Scheduler stack  |  ^        |  Scheduler stack  |\n+-------------------+  |        +-------------------+\n|                   |  |        |                   |      |                   |\n|  Thread 3 stack   |  |        |  Thread 3 stack   |      |Thread 3 terminated|\n|                   |  |        |                   |      |                   |\n+-------------------+  |        +-------------------+      | Thread 2,3 stacks |\n|                   |  | Main   |                   |      |  freed (unwinded) |\n|  Thread 2 stack   |  | Stack  |Thread 2 terminated|      |                   |\n|                   |  |        |    (stack-hole)   |      |New scheduler stack|\n+-------------------+  |        +-------------------+      +-------------------+\n|                   |  |        |                   |      |                   |\n|  Thread 1 stack   |  |        |  Thread 1 stack   |      |  Thread 1 stack   |\n|                   |  |        |                   |      |                   |\n+-------------------+  |        +-------------------+      +-------------------+\n        Fig 1                           Fig 2                      Fig 3\n```\n1. Fig. 1. Three threads are created - thread 1 (as first), 2, 3 (as last) by\n   calling `coop_sched_thread()` routine. The threads are created on the main\n   stack with their stack sizes specified during the thread creation by passing\n   appropriate argument to `coop_sched_thread()`. The scheduler stack is now\n   located above the lastly created thread stack (that is thread 3), therefore\n   doesn't interfere with working thread stacks.\n\n2. Fig. 2. Thread 2 terminates. Since its stack is not located as the last on\n   the stacks chain, the already terminated thread 2 stack starts a *stack-hole*.\n   That is it still occupies the main stack space even its thread is already\n   terminated.\n\n3. Fig. 3. Thread 3 terminates. Since there is no working thread stacks between\n   the thread 3 stack and the thread 1 stack (now the last stack in the chain)\n   the stack is unwinded and the scheduler stack is now located on the position\n   previously occupied by thread 2. From now all new thread stacks will be located\n   over the thread 1 stack.\n\n**IMPORTANT NOTE**: Setting up thread stack size shall take into account not\nonly dynamic changes of the thread stack resulting from activities performed\nby a thread during its run-time (e.g. calls to `printf(3)`, which extensively\nuses stack allocated space), but also must foresee some additional stack space\nrequired by preemptive ISRs activities (for platforms with such ISR characteristics).\nFor this reason the exact minimal thread stack size for a given thread routine\nis fluent and may substantially differ for various platforms and development\nenvironments. If low memory RAM usage is critical, it's usually feasible to\nstart with the trial and error method - try with some minimal thread stack size\nvalue and increase its size in case of platform instability/crashes. If the\nlibrary is configured with `CONFIG_OPT_STACK_WM`, `coop_stack_wm()` may be used\nto assess maximum thread stack usage while choosing the optimal thread stack\nsize configuration.\n\n## Platform Callbacks\n\nThe library uses callbacks routines to access platform specific functionality.\nThe following callbacks are defined:\n\n* `coop_tick_cb()` - callback used to get clock tick value at the routine call\n  time. The routine is called-back if the library was configured with time\n  related functionality (configuration parameters: `CONFIG_OPT_IDLE`,\n  `CONFIG_OPT_YIELD_AFTER`,`CONFIG_OPT_WAIT`). Note, the library doesn't define\n  the *tick* in terms of time duration. This quantity is platform specific.\n\n* `coop_idle_cb()` - switch the platform into the idle mode. The routine is\n  called-back if the library was configured with idle API support (`CONFIG_OPT_IDLE`\n  configuration parameter) and all active threads are going to be idle for a\n  specific amount of time. Implementing this routine enables switching the\n  platform into a desired sleep-mode therefore reducing power consumption while\n  in no-activity time.\n\n* `coop_dbg_log_cb()` - callback used to log debug messages. Called only if\n  compiled with debug logs turned on (`COOP_DEBUG` parameter).\n\n[`src/platform`](src/platform) directory contains basic, default implementation\nof `CoopThreads` library callbacks for various platforms. The implementation\nserves as an example, which should be sufficient for most of the needs. Every\nof the callbacks may be overridden by defining appropriate configuration parameter\nto provide custom version of the callback.\n\nFor example if there is a need to provide low-power sleep modes support during\nthe system idle state, a library user may require to:\n\n* Provide custom implementation of `coop_idle_cb()` (`CONFIG_IDLE_CB_ALT` parameter)\n  to switch the platform into a desired sleep mode.\n\n* Provide custom implementation of `coop_tick_cb()` (`CONFIG_TICK_CB_ALT` parameter)\n  to adjust the clock ticks with the time spent during the sleep mode.\n\n## License\n\n2 clause BSD license. See [`LICENSE`](LICENSE) file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpstolarz%2Fcoopthreads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpstolarz%2Fcoopthreads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpstolarz%2Fcoopthreads/lists"}