A lightweight user-space cooperative green threads runtime written in C23, designed for exploring how scheduling, context switching, and runtime systems work at a low level.
This project is not a framework or application. It is a systems-level runtime experiment focused on building and understanding:
- Cooperative multitasking in user space
- Scheduling and execution control
- Minimal runtime abstractions
- Deterministic execution models
This project focuses strictly on runtime systems concepts:
- User-space thread scheduling (green threads)
- Task lifecycle management
- Context switching abstractions (future backend experiments)
- Memory and execution control at the runtime level
- Performance and correctness trade-offs in concurrency models
The project explicitly avoids:
- OS-level kernel thread implementation
- High-level application frameworks
- Blocking or OS-dependent concurrency abstractions as core design elements
Early-stage systems project (v1)
Core architecture is under active design and incremental implementation.
The runtime is designed as a layered systems library with strict separation between core runtime logic and external consumers.
src/ Core runtime implementation
include/ Public API headers
internal/ Internal/private headers
tests/ Unit, integration, stress, and regression tests
examples/ Runnable demonstration programs
benchmarks/ Performance measurement workloads
design/ Architecture decisions and system invariants
docs/ Project documentation
debug/ Debugging utilities and tools
build/ Generated artifacts (not tracked)
The system follows a library-first architecture.
The runtime is compiled into a static library:
libgt.a
The library contains:
- Scheduler implementation
- Task management primitives
- Runtime execution logic
- Internal synchronization mechanisms
All execution layers depend on the core library:
- Tests — correctness validation
- Examples — usage demonstrations
- Benchmarks — performance evaluation
Each consumer is built as an independent executable linked against libgt.a.
The project uses a Makefile-driven dependency graph build system.
All compiled output is isolated under:
build/<profile>/
Supported profiles:
debugrelease
Directory structure:
build/<profile>/
├── obj/ Object files (.o)
├── dep/ Dependency files (.d)
├── lib/ Static libraries
└── bin/ Executables
The build system follows a strict dependency graph:
src/*.c
↓
object files (.o)
↓
libgt.a
↓
tests / examples / benchmarks
- Incremental compilation
- Automatic dependency tracking via
.dfiles - Single runtime library artifact
- Thin executable wrappers around the runtime
Runtime implementation remains isolated from all execution layers.
Everything depends on libgt.a.
Dependencies are tracked explicitly through Make.
New modules can be added without changing the build model.
The Makefile acts as the single source of truth for compilation, linking, and dependency tracking.
make allBuilds:
- Static runtime library (
libgt.a) - Tests
- Examples
- Benchmarks
make libProduces:
libgt.a
make tests
make examples
make benchmarksEach target produces independent executables linked against the runtime library.
Each subsystem produces standalone executables.
make run-testsBehavior:
- Executes all test binaries
- Fails fast on first error
- Used for correctness validation
make run-examplesBehavior:
- Runs all example programs
- Intended for exploration and demonstration
- Failures do not stop execution
make run-benchmarksBehavior:
- Runs performance workloads
- Measures runtime behavior and scalability
- Failures do not stop execution
make checkRuns:
- Static analysis (
cppcheck) - Tests
Used as the primary correctness gate.
make formatFormats all source files using clang-format.
make check-envVerifies required tooling:
- Clang
- GNU Make
- ar
- cppcheck
- clang-format
All generated output is stored under:
build/<profile>/
Where <profile> is either:
debug
release
Directory layout:
obj/ Compiled object files
dep/ Dependency tracking files
lib/ Static libraries
bin/ Executable binaries
Benefits:
- Reproducible builds
- No source tree pollution
- Clear separation of generated artifacts
The project follows a simple development loop:
- Build
make all- Verify Correctness
make run-tests- Analyze
make lint- Format
make formatGoals:
- Correctness
- Consistency
- Maintainability
When working in this project, think in terms of four layers.
Everything originates from src/ and ultimately becomes:
libgt.a
Tests, examples, and benchmarks are clients of the runtime, not part of the runtime itself.
Make resolves:
source → objects → libgt.a → executables
tests → correctness
examples → usability
benchmarks → performance
Released under the MIT License.