Skip to content

Feature: Green Threads (Cooperative Concurrency) #9

Description

@sashml

What

Add cooperative multitasking (green threads) to O²L via a spawn keyword, a cooperative Scheduler, and first-class Channel values for coroutine communication.

Key additions:

  • spawn <expr> — launches a new coroutine that runs cooperatively inside the same OS thread
  • Channel built-in — buffered/unbuffered channel for send/receive between coroutines
  • io.sleep(ms) — suspends the calling coroutine for a duration without blocking the scheduler
  • io.yield() — voluntarily yields the CPU to the next ready coroutine
  • IOThreadPool — offloads blocking I/O to a background thread pool; the calling coroutine suspends and resumes when the I/O completes

Why

O²L targets application-level scripting where concurrent tasks (timers, network calls, event handlers) are common. OS threads are too heavy for fine-grained concurrency; callbacks fragment control flow. Cooperative green threads let code stay sequential in style while handling many concurrent logical tasks efficiently — the same tradeoff that made Go goroutines and Python asyncio popular.

How

Runtime:

  • Coroutine — owns an ASTNode* body and a cloned Context; carries state (Ready, Running, Suspended, Completed, Failed) and an optional resume value
  • Scheduler (singleton run-loop) — maintains a ready_queue_ (deque), timer_queue_, and suspended_ map; drives evaluation by calling body->evaluate(context) on each coroutine in turn
  • Suspension is signalled by throwing SuspendException inside evaluate(); the scheduler catches it and moves the coroutine to the appropriate queue
  • IOThreadPool — a fixed thread pool; when a coroutine suspends for I/O the work lambda is posted there; on completion Scheduler::resumeCoroutine(id, result) is called from the pool thread
  • ChannelInstance — value-typed channel with configurable buffer capacity; send suspends the sender when full, receive suspends the receiver when empty

Language:

  • New token SPAWN in the lexer
  • SpawnNode AST node — clones the current Context, calls Scheduler::spawn(body, ctx)
  • Channel exposed as a global class object; Channel.new(capacity) creates a channel

Tests (8 new unit test files):

  • test_scheduler.cpp — run-loop, multi-coroutine scheduling
  • test_spawn_basic.cppspawn keyword end-to-end
  • test_channel_basic.cpp — send/receive, buffering, blocking
  • test_resume_logic.cppsuspendCurrent / resumeCoroutine round-trip
  • test_io_yield.cppyield and sleep integration
  • test_suspend_exception.cpp — exception propagation through coroutines
  • test_context_clone.cpp — context isolation between coroutines
  • test_carray_from_list.cppCArray.fromList() helper (used by FFI bridge in async callbacks)

All 464 tests pass (including pre-existing suite).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions