Skip to content

Conversation

@ElFantasma
Copy link
Collaborator

@ElFantasma ElFantasma commented Jan 23, 2026

EDIT (27-01-2026):

Ran Devin review and fixed all found issues:
https://app.devin.ai/review/lambdaclass/spawned/pull/140

Summary

Adds rt::ctrl_c() to both tasks and threads modules with identical call syntax:

// Both versions use the same API:
send_message_on(handle.clone(), rt::ctrl_c(), Msg::Shutdown);
  • Tasks: returns an async future
  • Threads: returns a closure that blocks (handler registered immediately to avoid race conditions)

Also adds join() method to ActorRef for waiting on actor completion:

actor.join().await;  // tasks
actor.join();        // threads

Includes signal_test and signal_test_threads examples demonstrating usage.

Closes #58
Closes #116

Test plan

  • cargo build --workspace
  • cargo test --workspace
  • cargo clippy --workspace
  • cargo run --bin signal_test -- async - press Ctrl+C, verify teardown runs
  • cargo run --bin signal_test -- blocking - press Ctrl+C, verify teardown runs
  • cargo run --bin signal_test -- thread - press Ctrl+C, verify teardown runs
  • cargo run --bin signal_test_threads - press Ctrl+C, verify teardown runs

@ElFantasma ElFantasma changed the base branch from feature/rename-genserver-to-actor to main January 26, 2026 15:55
@ElFantasma ElFantasma changed the base branch from main to feature/rename-genserver-to-actor January 26, 2026 15:56
@ElFantasma ElFantasma force-pushed the feature/ctrl-c-signal-handling branch from 8b6bcb9 to 823ba05 Compare January 26, 2026 16:23
@ElFantasma ElFantasma changed the base branch from feature/rename-genserver-to-actor to main January 26, 2026 16:42
@ElFantasma ElFantasma changed the base branch from main to feature/rename-genserver-to-actor January 26, 2026 16:46
@ElFantasma ElFantasma changed the base branch from feature/rename-genserver-to-actor to main January 26, 2026 16:47
@ElFantasma ElFantasma force-pushed the feature/ctrl-c-signal-handling branch from 823ba05 to 6edc25c Compare January 26, 2026 16:50
@ElFantasma
Copy link
Collaborator Author

/claude

@ElFantasma
Copy link
Collaborator Author

/kimi

@ElFantasma
Copy link
Collaborator Author

/codex

@github-actions
Copy link

🤖 Kimi Code Review

Security Review

Critical - None found
High - None found
Medium - None found
Low - None found

Bug Review

1. Race condition in signal handler registration (Medium)

File: rt/src/threads/mod.rs (lines 77-97)

The ctrl_c() function uses a global OnceLock to register the signal handler, but there's a race condition between checking if the handler is registered and adding new subscribers. If two threads call ctrl_c() concurrently during initialization, they might both try to register the handler, potentially causing the second registration to fail silently.

Fix: Use a proper synchronization mechanism or ensure the handler registration is atomic.

2. Potential panic in signal handler (Medium)

File: rt/src/tasks/tokio/mod.rs (lines 22-24)

The ctrl_c() function panics on error with .expect("Failed to listen for Ctrl+C"). This could cause the entire application to crash if signal handling fails (e.g., on platforms where signals aren't supported).

Fix: Return a Result instead of panicking, or handle the error gracefully.

3. Unbounded memory growth in signal subscribers (Low)

File: rt/src/threads/mod.rs (lines 77-97)

The CTRL_C_SUBSCRIBERS vector grows indefinitely as new actors are created and register for Ctrl+C handling. There's no cleanup mechanism for removed/dropped actors.

Fix: Implement cleanup for dropped subscribers or use a bounded collection.

4. Inconsistent API between tasks and threads (Low)

File: rt/src/tasks/tokio/mod.rs vs rt/src/threads/mod.rs

The tasks version returns a future (async fn ctrl_c()) while the threads version returns a closure (impl FnOnce()). This API inconsistency could confuse users.

Fix: Consider unifying the API or clearly documenting the difference.

Performance Issues

None found - the changes appear to be focused on functionality rather than performance optimization.


Automated review by Kimi (Moonshot AI)

@github-actions
Copy link

🤖 Codex Code Review

I can’t review PR #140 yet because there are no local changes to diff. git diff and git diff --stat are empty, and the repo is in a detached HEAD with only a merge commit in history. That means the PR’s changes aren’t checked out in this workspace.

Please provide the PR diff or check out the PR branch/commit locally (then I can re-run git diff and review).


Automated review by OpenAI Codex · custom prompt

Replace JoinHandle-based join() with completion signal pattern:
- tasks: use tokio::sync::watch channel
- threads: use Condvar with completion flag

All clones of ActorRef can now call join() and be notified when the
actor stops, instead of only the first caller.
@ElFantasma
Copy link
Collaborator Author

Response to Kimi Review

Issue Status Notes
1. Race condition in handler registration ❌ Invalid OnceLock::get_or_init is atomic and thread-safe. Only one thread executes the init closure; others block until complete. No race condition exists.
2. Panic in tasks ctrl_c ⚠️ Pre-existing Not introduced by this PR. Design choice - could return Result but outside PR scope.
3. Unbounded memory growth ✅ Fixed guard.retain(|tx| tx.send(()).is_ok()) now removes dead subscribers when Ctrl+C is received.
4. Inconsistent API ⚠️ By design tasks uses async fn, threads returns closure for use with send_message_on(handle, rt::ctrl_c(), msg). Different APIs match their respective paradigms.

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.

Enable Ctrl+C signal handling for start_blocking() Catch ctrl_c signaling on genservers that where spawned with start_blocking()

4 participants