Skip to content

Repository files navigation

CMP

Coroutine Machine Process — a C++23 coroutine runtime project.

C++23 Module License

English · 简体中文 · 繁體中文

mcpp · Architecture · Issues

ci-linux ci-macos ci-windows

Important

CMP provides a lazy, single-consumer Task<T> / Task<void> and a caller-thread RunLoop with explicit scheduling. Cancellation, timers, asynchronous I/O, and detached execution are not implemented.

CMP is being built as a modern coroutine runtime and library on standard stackless C++ coroutines. The intended direction is an explicit co_await model that can grow, in small verified steps, toward scheduling, timers, asynchronous I/O, cancellation, and safe handling of blocking work.

Why CMP?

The name stands for Coroutine Machine Process. CMP uses C as the intended name for a lightweight coroutine execution unit. This is analogous to Go runtime's G as a naming and mental-model inspiration only; it is not a claim that a future CMP task is already equivalent to a goroutine.

The project is guided by a few principles:

  • use C++23 standard stackless coroutines and C++ Modules;
  • keep suspension explicit through co_await and purpose-built awaiters;
  • develop runtime pieces incrementally, with tests and small reviewable changes;
  • support more than server workloads;
  • keep mcpp as the single source of build and package truth.

Runtime Boundaries

C++ standard coroutines are a language mechanism, not a complete runtime. CMP therefore does not promise that:

  • a task is automatically equivalent to a Go goroutine;
  • an arbitrary blocking call becomes non-blocking;
  • coroutine switching is safe directly inside a signal handler;
  • M:N scheduling, work stealing, timers, cancellation, or async I/O already exist.

Those capabilities must be designed and verified individually. The expected direction is explicit async I/O awaiters, a dedicated blocking pool, and cooperative safe points.

Quick Start

Install xlings, then install the mcpp version pinned by .xlings.json:

xlings install
mcpp --version
mcpp build
mcpp test

Run the standalone consumer:

cd examples/basic
mcpp run

The example prints Coroutine result: 42 from inside a scheduled Task<void> coroutine and exits successfully. It proves that an independent mcpp package can resolve the path dependency, import mcpplibs.cmp, compose Tasks, and drive them through the public RunLoop.

Current API

import std;
import mcpplibs.cmp;

using mcpplibs::cmp::Task;
using mcpplibs::cmp::RunLoop;

Task<int> answer() {
    co_return 42;
}

Task<void> print_answer(RunLoop::Scheduler scheduler) {
    co_await scheduler.schedule();
    auto value = co_await answer();
    std::println("Coroutine result: {}", value);
    co_return;
}

int main() {
    RunLoop loop {};
    loop.run(print_answer(loop.get_scheduler()));
}

Task is lazy: calling answer() creates a suspended coroutine. It starts when consumed by co_await. A Task is move-only, has one consumer, and can only be awaited as an rvalue. It stores either a value or an exception, transfers directly between child and continuation, and destroys an unconsumed frame through RAII. Task<T&>, copying, move assignment, and detached execution are deliberately unsupported.

A translation unit that defines a coroutine must import std so the compiler can see the standard coroutine protocol types. CMP imports std privately and does not re-export the whole standard library.

RunLoop::run() consumes one root Task, executes ready coroutines on the calling thread, returns its value, and rethrows its exception. Scheduler::schedule() always suspends and queues the continuation. Scheduler handles are copyable, but remain tied to their originating RunLoop. Sequential run() calls are supported; nested or concurrent calls are rejected. A moved-from Task must not be awaited.

RunLoop is not a background thread and does not make blocking code asynchronous. A Task that suspends without arranging a future resume can leave run() waiting indefinitely. CMP does not provide automatic thread affinity: after an external awaiter resumes on another thread, explicitly await the desired Scheduler to return to its RunLoop.

Repository Layout

.
├── .xlings.json              # pinned project tool environment
├── mcpp.toml                 # package identity and test dependency
├── src/cmp.cppm              # root module interface
├── src/task.cppm             # Task module partition
├── src/run_loop.cppm         # RunLoop and Scheduler partition
├── tests/cmp_test.cpp        # Task contract and lifetime tests
├── tests/run_loop_test.cpp   # scheduler, boundary, and threading tests
├── examples/basic/           # standalone path-dependency consumer
├── docs/architecture.md      # current structure, boundaries, and evolution
└── .github/workflows/        # Linux, macOS, and Windows CI

The repository does not ship mcpp new templates yet. Purpose-built templates can be added after CMP has a stable runtime API worth demonstrating.

Development

The local verification path is:

mcpp build --cache=off
mcpp test --cache=off
cd examples/basic && mcpp run

CI runs the equivalent build, test, and standalone example flow on Linux, macOS, and Windows. The mcpp version is pinned by .xlings.json; contributors should not rely on an unrelated global mcpp installation.

CMP does not track mcpp.lock; .gitignore enforces that repository policy. Runtime dependencies belong in [dependencies]; gtest is declared explicitly under [dev-dependencies.compat].

Roadmap

Runtime work is split into independently reviewable phases:

  1. package identity and importable-module bootstrap — implemented;
  2. coroutine task and lifetime semantics — initial Task implemented;
  3. a root runner and minimal single-thread scheduler — initially implemented;
  4. timers, cancellation, and structured wake-up paths;
  5. multi-worker scheduling and work stealing;
  6. asynchronous I/O integration and a blocking pool.

The remaining order is directional, not a promise that a listed feature is already implemented.

Contributing

Read the architecture notes before changing module boundaries. Keep changes small, use C++23 module conventions, and treat mcpp build, mcpp test, the standalone example, and CI as the implementation facts.

License

Apache License 2.0

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

Generated from mcpplibs/template