Skip to content

Conversation

@saltbo
Copy link

@saltbo saltbo commented Aug 11, 2025

Problem

Resolve #1461

When using --exit-no-conn or --once options, ttyd would exit immediately without properly waiting for the child process to terminate. This could result in:

  • Child processes not receiving the configured signal
  • Incomplete cleanup of child process resources
  • Orphaned processes in some cases

Root Cause

On certain systems (particularly macOS), the waitpid() system call may fail to properly reap zombie processes in some edge cases, causing the process_exit_cb callback to never be invoked, leading ttyd to wait indefinitely.

Solution

Implemented a dual-mechanism approach for robust process termination handling:

  1. Primary mechanism: Preserve existing waitpid() and process_exit_cb logic
  2. Fallback mechanism: Add uv_timer_t that periodically checks process status using kill(pid, 0)

If the primary mechanism fails, the fallback timer detects when the process no longer exists and triggers ttyd exit.

Changes

  • Added exit_timer field to pty_ctx_t structure
  • Implemented exit_timer_cb() for periodic process status checking
  • Modified process cleanup logic to handle both normal and fallback exit paths
  • Enhanced --once and --exit-no-conn behavior to properly wait for process termination

Testing

  • Verified on macOS with various command types including asciinema
  • Confirmed that configured signals are properly sent to child processes
  • Tested that ttyd exits cleanly after child process termination
  • No impact on normal operation when not using --once or --exit-no-conn

Compatibility

  • Backward compatible, no breaking changes
  • Only affects behavior when using --once or --exit-no-conn options
  • Minimal performance overhead (timer only active during exit sequence)

Fixes the issue where ttyd would not properly wait for child process termination, ensuring reliable signal delivery and process cleanup.

…-once

- Add fallback timer mechanism for process exit detection
- Fix issue where ttyd wouldn't wait for child process to terminate properly
- Improve process cleanup reliability on systems where waitpid() may fail
- Ensure configured signal is sent to command process before ttyd exits

Fixes issue where --exit-no-conn option would exit ttyd immediately
without waiting for the child process to receive the signal and terminate
cleanly. This could lead to orphaned processes or incomplete cleanup.

The fix implements a dual mechanism:
1. Primary: existing waitpid() and process_exit_cb logic
2. Fallback: uv_timer_t that periodically checks process status using kill(pid, 0)

This ensures ttyd will always exit properly after the child process
terminates, regardless of system-specific waitpid() behavior.
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.

When exiting while using both -c and --exit-no-conn, the -s signal is not passed to the command.

1 participant