Skip to content

feat: add green threads (cooperative concurrency) with spawn, Channel, and async I/O#10

Merged
zombocoder merged 10 commits into
zombocoder:developfrom
sashml:feat/green-threads-upstream
Apr 30, 2026
Merged

feat: add green threads (cooperative concurrency) with spawn, Channel, and async I/O#10
zombocoder merged 10 commits into
zombocoder:developfrom
sashml:feat/green-threads-upstream

Conversation

@sashml
Copy link
Copy Markdown
Contributor

@sashml sashml commented Apr 25, 2026

Closes #9

Summary

  • Adds spawn <expr> keyword to launch cooperative coroutines within the same OS thread
  • Introduces Scheduler singleton run-loop with ready/timer/suspended queues and correct exception propagation from the root coroutine
  • ChannelInstance provides buffered/unbuffered send/receive with suspend-on-full / suspend-on-empty semantics
  • IOThreadPool offloads blocking work to background threads; coroutines resume via Scheduler::resumeCoroutine
  • Context::clone() isolates each coroutine's variable bindings from the spawning scope
  • ConcurrencyLibrary exposes Channel.new(capacity), io.sleep(ms), io.yield() to O²L programs
  • CArray.fromList() completes the FFI bridge for async callback use

Test plan

  • test_scheduler.cpp — run-loop, multi-coroutine scheduling, exception propagation
  • 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() correctness
  • All 464 tests pass (464 total including pre-existing suite)

@zombocoder
Copy link
Copy Markdown
Owner

This is a super draft implementation, pls folow the code style guidelines and add more tests and examples

@sashml sashml force-pushed the feat/green-threads-upstream branch from 1c18c5c to b25d9fb Compare April 28, 2026 00:22
…, and async I/O

Introduces cooperative multitasking to O²L:

- `spawn <expr>` keyword: launches a new coroutine that runs cooperatively
  within the same OS thread (SpawnNode AST node, Lexer/Parser support)
- `Scheduler` (singleton run-loop): drives coroutines via a ready_queue_,
  timer_queue_, suspended_ map, and thread-safe IO completion queue
- `Coroutine`: owns body ASTNode + cloned Context; carries state
  (Ready/Running/Suspended/Completed/Failed) with block_resume_stack for
  nested block resumption
- `ChannelInstance`: buffered/unbuffered channel for send/receive between
  coroutines; senders suspend when full, receivers suspend when empty
- `ConcurrencyLibrary`: exposes `Channel.new(capacity)` and `io.sleep(ms)` /
  `io.yield()` to O²L programs
- `IOThreadPool`: fixed thread pool offloading blocking I/O; uses thread-safe
  `enqueueReady` to post completions back to the scheduler
- `Context::clone()`: deep-copies variable bindings for coroutine isolation
- `CArray.fromList()`: copies a ListInstance into a CArrayInstance for FFI
- BlockNode/WhileStatementNode: use block_resume_stack for correct nested
  coroutine resumption
- Cross-platform: MSVC Value variant alias, unistd.h for macOS/Linux,
  holds_Int_Value/holds_Long_Value helpers, Windows socket defines

All existing tests pass; adds 9 new concurrency test suites.
@sashml sashml force-pushed the feat/green-threads-upstream branch from b25d9fb to 0023bd1 Compare April 28, 2026 07:53
sashml added 9 commits April 28, 2026 11:07
…lures

- Parser: accept keyword 'new' as method name after '.' so Channel.new()
  parses correctly (fixes ConcurrencyTest.channel_basic and
  ConcurrencyTest.concurrency_advanced)
- Scheduler: store root coroutine exception in root_exception_ and
  expose it via getRootException(); clear on reset()
- Interpreter: rethrow root coroutine exception after scheduler.run()
  so EvaluationErrors propagate to callers (fixes IntegrationTest
  DemoAccessError and ErrorHandling)
…plementation

- Fix YieldNode ODR violation between test_resume_logic.cpp and
  test_suspend_exception.cpp by wrapping each in anonymous namespaces
  (root cause of MSVC 0xc0000005 crash — linker picked wrong vtable)
- Fix YieldNode to check hasResumeValue() before yielding to prevent
  infinite re-suspension on resume
- Remove debug cerr prints from BlockNode, WhileStatementNode, Scheduler
- Remove unused <iostream> includes from BlockNode and WhileStatementNode
- Use EXPECT_EQ instead of assert in test_resume_logic
- Parser: simplify Channel.new() member name token handling
- Context::clone(): preserve this_stack_ for spawn inside object methods
- yield_in_false_loop: while(false) body never executes yield
- yield_single_iteration: loop terminates on first resume (condition false)
- yield_deeply_nested: 3 levels of BlockNode nesting exercises block_resume_stack depth
- root_exception_captured: root coroutine error stored in root_exception_, rethrowable
- non_root_exception_ignored: non-root errors don't set root_exception_
- root_exception_null_on_success: successful root leaves root_exception_ null
…mption

- error_after_resume: yield then throw on resume, verify root_exception_ captured
- scheduler_clean_after_run: isActive()==false after success, error, and yield+error
- error_in_condition_after_resume: condition throws after yield-resume cycle completes
- yield_nested_inner_loop: yield in inner while-while, 4 yields across 2*2 iterations
- yield_nested_outer_body: yield in outer body after inner loop completes, 2 yields
  Both exercise block_resume_stack at 4+ nesting levels
- channel_producer_consumer_values: producer sends 3 values via channel, consumer sums them
- three_coroutine_round_robin: 3 coroutines yield to shared log, verify deterministic order
- channel_multiple_producers: 2 producers send to one buffered channel
- channel_multiple_consumers: 2 consumers receive from one buffered channel
- channel_unbuffered_blocking: sender blocks until receiver is ready
- channel_buffered_full: sender blocks when buffer at capacity
- suspend_for_io_basic: IO lambda result delivered to coroutine on resume
- suspend_for_io_different_thread: IO work runs on a background thread
- suspend_for_io_multiple: 3 concurrent IO suspensions all complete correctly
@sashml sashml changed the base branch from main to develop April 30, 2026 17:47
@zombocoder zombocoder merged commit 122013c into zombocoder:develop Apr 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Green Threads (Cooperative Concurrency)

2 participants