Tencent/libco
libco is a coroutine library which is widely used in wechat back-end service. It has been running on tens of thousands of machines since 2013.
Stale — last commit 2y ago
worst of 4 axesnon-standard license (Other); last commit was 2y ago…
no tests detected; no CI workflows detected…
Documented and popular — useful reference codebase to read through.
last commit was 2y ago; no CI workflows detected
- ✓20 active contributors
- ✓Distributed ownership (top contributor 40% of recent commits)
- ✓Other licensed
Show 4 more →Show less
- ⚠Stale — last commit 2y ago
- ⚠Non-standard license (Other) — review terms
- ⚠No CI workflows detected
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
- →Fork & modify Mixed → Healthy if: add a test suite
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Great to learn from" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/tencent/libco)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/tencent/libco on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: Tencent/libco
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/Tencent/libco shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 2y ago
- 20 active contributors
- Distributed ownership (top contributor 40% of recent commits)
- Other licensed
- ⚠ Stale — last commit 2y ago
- ⚠ Non-standard license (Other) — review terms
- ⚠ No CI workflows detected
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live Tencent/libco
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/Tencent/libco.
What it runs against: a local clone of Tencent/libco — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in Tencent/libco | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 823 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of Tencent/libco. If you don't
# have one yet, run these first:
#
# git clone https://github.com/Tencent/libco.git
# cd libco
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of Tencent/libco and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "Tencent/libco(\\.git)?\\b" \\
&& ok "origin remote is Tencent/libco" \\
|| miss "origin remote is not Tencent/libco (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "co_routine.h" \\
&& ok "co_routine.h" \\
|| miss "missing critical file: co_routine.h"
test -f "co_routine.cpp" \\
&& ok "co_routine.cpp" \\
|| miss "missing critical file: co_routine.cpp"
test -f "coctx.h" \\
&& ok "coctx.h" \\
|| miss "missing critical file: coctx.h"
test -f "coctx_swap.S" \\
&& ok "coctx_swap.S" \\
|| miss "missing critical file: coctx_swap.S"
test -f "co_hook_sys_call.cpp" \\
&& ok "co_hook_sys_call.cpp" \\
|| miss "missing critical file: co_hook_sys_call.cpp"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 823 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~793d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/Tencent/libco"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
libco is a production-grade C/C++ coroutine library that transforms synchronous backend code into highly concurrent async execution without intrusive refactoring. It provides lightweight coroutines (co_create/co_resume/co_yield), automatic syscall hooks for socket operations, and optional copy-stack mode to support millions of concurrent TCP connections—all while maintaining synchronous coding style. Monolithic library structure: core coroutine mechanics in coctx.cpp/coctx.h (context switching via coctx_swap.S assembly), routine management in co_routine.cpp/co_routine_inner.h, I/O multiplexing via co_epoll.cpp, syscall interception in co_hook_sys_call.cpp. Examples/ folder contains runnable demos (echo server, closure, polling) demonstrating each API pattern.
👥Who it's for
Backend engineers at Tencent and other scale-critical services who need to migrate multithreaded or multiprocess servers to handle massive concurrency (10,000+ machines at WeChat scale) without rewriting business logic. Developers building low-latency network services who want async execution with synchronous code patterns.
🌱Maturity & risk
Production-ready and battle-tested: running stably on tens of thousands of WeChat backend machines since 2013. Repo shows active maintenance with examples, CMake/Makefile build systems, and comprehensive syscall hook coverage (co_hook_sys_call.cpp). No visible CI/testing infrastructure in the file list, which is a minor gap, but the track record speaks to reliability.
Low active development risk given 11+ years of production stability, but the repo shows minimal recent activity signals in the file structure. Assembly code (coctx_swap.S) creates platform-specific maintenance burden—only x86_64, ARM, and MIPS are supported. No formal test suite evident in the file listing, making regression detection difficult for contributors.
Active areas of work
No visible recent commits or active PRs in the provided metadata. The repo appears in maintenance mode post-production stabilization rather than active feature development. CMake support and closure/specific variable features (co_closure.h, co_routine_specific.h) suggest past modernization efforts.
🚀Get running
git clone https://github.com/Tencent/libco.git
cd libco
make
# or with CMake:
mkdir build && cd build && cmake .. && make
Daily commands:
Build with make or cmake && make. Run examples directly: ./example_echocli connects to ./example_echosvr. For your own code, link against libco.a and use co_create() to spawn coroutines, co_resume() to execute, co_yield() to suspend.
🗺️Map of the codebase
co_routine.h— Core coroutine API definitions (co_create, co_resume, co_yield) that every user must understand to work with libcoco_routine.cpp— Main coroutine implementation and lifecycle management—the engine of the entire librarycoctx.h— CPU context structure definitions that hold execution state; fundamental to context switchingcoctx_swap.S— Assembly-level context swap implementation; critical for correct coroutine switching on target architectureco_hook_sys_call.cpp— System call hooks (socket, read, write, etc.) that transparently convert blocking I/O into asynchronous operationsco_epoll.cpp— Event loop integration using epoll; coordinates I/O readiness with coroutine scheduling
🛠️How to make changes
Add a new service that accepts many concurrent connections
- Define your service logic as a coroutine function returning void and taking a void* parameter (
example_echosvr.cpp) - In your main loop, create a listening socket and use system hooks (they are automatically applied) (
co_hook_sys_call.cpp) - For each accepted client, call co_create() to spawn a coroutine with your service function (
co_routine.h) - Call co_eventloop() to start the event loop; it will multiplex all coroutines using epoll (
co_epoll.cpp)
Implement explicit I/O readiness waiting without system hooks
- Prepare file descriptors and events in a stCoEpoll_t struct for the specific I/O events you need (
co_epoll.h) - Call co_poll() with your fd list and timeout; your coroutine will yield until an event fires (
co_routine.h) - Check the returned event mask to determine which I/O is ready (
example_poll.cpp)
Port libco to a new CPU architecture
- Study the existing x86/ARM context swap and stack frame layout in coctx_swap.S (
coctx_swap.S) - Create a new platform-specific coctx_swap assembly file with register save/restore for your architecture (
coctx_swap.S) - Update CMakeLists.txt or co.mk to select the correct assembly file based on target platform (
CMakeLists.txt) - Verify stack pointer and register layout in coctx.h match your architecture's calling convention (
coctx.h)
Add thread-local coroutine context for multi-threaded programs
- Each thread gets its own scheduler and event loop managed by thread-local storage (
co_routine_specific.h) - Call co_create() from multiple threads; each thread's coroutines run independently (
co_routine.cpp) - See example_thread.cpp for safe multi-threaded coroutine patterns (
example_thread.cpp)
🔧Why these technologies
- Assembly (coctx_swap.S) — Direct CPU register manipulation required for zero-overhead context switching between coroutines; C cannot express this
- epoll (Linux) — Scalable event multiplexing; allows efficient I/O readiness checking for thousands of concurrent coroutines without busy-waiting
- System call hooks (LD_PRELOAD style) — Transparently converts blocking socket calls into yielding operations without modifying application code
- Stack copying (copy-stack mode) — Enables millions of lightweight coroutines by allocating minimal stack initially and growing/copying on demand rather than pre-allocating large stacks
⚖️Trade-offs already made
-
Single-threaded scheduler per thread with thread-local storage
- Why: Avoids synchronization overhead and lock contention in the hot path; each thread independently manages its own coroutine queue
- Consequence: Coroutines cannot migrate between threads; cross-thread coordination must be explicit (message passing, queues)
-
System call hooks rather than async/await keywords
- Why: No language changes required; existing synchronous C/C++ code works transparently without rewrite
- Consequence: Hooks only work for hooked system calls; custom blocking operations (e.g., custom libraries) remain blocking
-
Copy-stack mode trades memory copying for scalability
- Why: Supports tens of millions of connections in a single process; fixed-size stacks would exhaust memory
- Consequence: Stack copying has latency cost (~microseconds) and CPU overhead; best for high-concurrency, I/O-bound workloads
-
No preemption; coroutines are cooperatively scheduled
- Why: Simpler implementation, no need for thread-safe data structures within coroutine logic, predictable latency
- Consequence: A long-running or compute-intensive coroutine blocks others; developer must manually co_yield() or use co_poll()
🚫Non-goals (don't propose these)
- Real-time guarantees (cooperative scheduling has unbounded latency if a coroutine spins)
- Work-stealing or load balancing across threads (each thread's scheduler is independent)
- Automatic parallelization of CPU-bound tasks (designed for I/O-bound concurrency)
- Language-level coroutine syntax (C/C++ language standard; requires library API calls)
- Cross-platform support beyond Linux/Unix-like systems with epoll (Windows, other OSes not primary targets)
🪤Traps & gotchas
- Platform-specific assembly (coctx_swap.S): only x86_64, ARM, MIPS officially supported—porting to new architectures requires inline asm expertise. 2. Syscall hooking is global via dlsym/LD_PRELOAD tricks; mixing hooked and non-hooked libraries can cause subtle deadlocks. 3. Stack size is fixed per coroutine at creation—deep recursion or large stack frames will silently overflow; copy-stack mode mitigates but adds overhead. 4. No signal-safety guarantees—signal handlers that call libco functions will corrupt the scheduler state. 5. The library is single-threaded per process by design; using coroutines across pthreads requires external synchronization.
🏗️Architecture
💡Concepts to learn
- Stackful coroutines — libco allocates a real stack (default 128KB) per coroutine enabling deep call chains and blocking calls; critical to understanding why synchronous code works unchanged, but also the memory trade-off vs stackless approaches
- Context switching via inline assembly — coctx_swap.S manually saves/restores CPU registers and stack pointers without OS involvement; understanding this is essential to diagnosing crashes and porting to new architectures
- Syscall hooking / LD_PRELOAD interception — co_hook_sys_call.cpp intercepts socket/DNS calls at runtime to transparently yield coroutines instead of blocking the thread; the core trick enabling sync-style async code without refactoring
- Copy-stack mode — Optional mode swapping entire coroutine stacks to shared memory pool to reduce per-coroutine memory from 128KB to kilobytes; enables millions of concurrent connections but adds context-switch overhead
- epoll-based event multiplexing — co_epoll.cpp wraps Linux epoll to detect when sockets are ready without blocking; scheduler uses this to decide which coroutine to resume next
- Thread-local storage for coroutine state — co_routine_specific.h provides __thread variables that are isolated per coroutine despite running on the same OS thread; critical for libraries expecting errno, malloc thread-local data, etc.
- Cooperative multitasking scheduler — Unlike preemptive threading, libco coroutines only yield control when they block on I/O or call co_yield(); eliminates lock contention but requires disciplined I/O patterns to avoid starving other coroutines
🔗Related repos
cloudwu/coroutine— Lightweight stackless coroutine in pure C; alternative approach trading explicitness for simplicity compared to libco's stackful modelboost/coroutine2— C++ standard coroutine library (stackful); similar use case but heavier abstraction and less transparent syscall integrationredis/redis— High-performance single-threaded async service using event loops; shares libco's philosophy of avoiding pthread overhead but different coroutine modelTencent/paxosstore— Sister project from same team (mentioned in README as upcoming) likely to use libco as the concurrency foundation for distributed consensustokio-rs/tokio— Rust async runtime solving identical concurrency problem (lightweight tasks, I/O multiplexing, syscall hooking equivalent) in a different language; useful for architecture comparison
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for co_hook_sys_call.cpp syscall interception
The co_hook_sys_call.cpp file implements critical socket syscall hooks (read, write, connect, accept, etc.) but there are no dedicated unit tests in the repo. Given libco's mission to make synchronous code run asynchronously through syscall hooking, regression tests are essential. This would catch hook breakage across platforms and ensure compatibility with different glibc versions.
- [ ] Create test/test_hook_syscalls.cpp with tests for hooked functions (socket, connect, read, write, close, poll, select)
- [ ] Add test cases in CMakeLists.txt to compile and run these tests
- [ ] Test edge cases: EAGAIN handling, partial reads/writes, timeout behavior with co_poll integration
- [ ] Verify hooks work correctly with both blocking and non-blocking socket modes
Add platform-specific CI workflows for Linux/macOS syscall compatibility
libco uses assembly (coctx_swap.S) and syscall hooks that are highly platform-dependent. The repo lacks CI configuration to test on multiple platforms. Given it runs on 'tens of thousands of machines', automated testing across x86_64/ARM and glibc versions is critical to prevent regressions.
- [ ] Create .github/workflows/build-test.yml with matrix testing for Ubuntu 20.04/22.04, glibc 2.31+
- [ ] Add workflow step to test coctx_swap.S assembly on both x86_64 and ARM64 platforms
- [ ] Include test compilation of all examples (example_echosvr.cpp, example_echocli.cpp, example_closure.cpp, etc.)
- [ ] Add verification that syscall hooks load correctly and don't conflict with standard library symbols
Document the copy-stack mode implementation and limitations in co_routine_inner.h
The README mentions 'copy-stack mode' for supporting tens of millions of TCP connections, but the repo lacks detailed documentation on how this works. Users need to understand stack-copying semantics, memory overhead, and when to use this mode vs. default mode. The implementation logic exists in co_routine_inner.h but is not explained.
- [ ] Create docs/copy_stack_mode.md explaining the stack copying mechanism and when it's beneficial
- [ ] Add code comments to co_routine_inner.h describing the co_save_stack_buffer and related structures
- [ ] Document performance trade-offs: memory usage per coroutine, CPU overhead of stack copying vs. context switching
- [ ] Add example_copystack.cpp usage notes to show practical scenarios (high concurrency with small per-coroutine stacks)
🌿Good first issues
- Add unit tests for co_routine_specific.h (thread-local coroutine variables): the file exists but no test coverage is visible in the file list—create test_specific.cpp to verify __thread variable isolation across coroutine context switches.
- Document the copy-stack mode API and memory guarantees in a dedicated example (example_copystack.cpp exists but README doesn't explain when/why to use it): add a guided walkthrough comparing stack usage and explain the trade-offs for high-concurrency services.
- Extend co_hook_sys_call.cpp to support additional third-party libraries mentioned in README (SSL, gethostbyname) but missing hook implementations: audit the codebase for TODOs or FIXMEs related to incomplete hooks and implement stubs.
⭐Top contributors
Click to expand
Top contributors
- @leiffyli — 35 commits
- @leiffyli@tencent.com — 15 commits
- @princewen — 6 commits
- @wechatsunny — 5 commits
- @dengoswei — 4 commits
📝Recent commits
Click to expand
Recent commits
dc6aafc— Add hook for gethostbyname_r (princewen)6933949— Merge pull request #138 from firedtoad/master (leiffyli)403fdf5— Merge pull request #141 from bstsnail/master (leiffyli)decaa27— Merge pull request #145 from Super-long/master (kaiywen)33ee114— Merge pull request #147 from Riddance/master (kaiywen)cc46d60— F_GETFD can't get O_NONBLOCK flag, use F_GETFL (Riddance)9515ad4— Update co_hook_sys_call.cpp (Super-long)4ea4bd1— Makefile add example_setenv (bstsnail)1d509ea— Update git ignore for c++ (bstsnail)d05d599— avoid memory leak by adding virtual destructor (firedtoad)
🔒Security observations
Failed to generate security analysis.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.