Skip to content

Conversation

@pasky
Copy link

@pasky pasky commented Jan 17, 2026

Root cause: action_suspend_process sent SIGTSTP, whose handler called suspend_application_mode() which does _key_thread.join(). This blocks waiting for the input thread, but the input thread may be posting messages via asyncio which needs the event loop - but the event loop can't run while blocked in the signal handler. This causes a deadlock.

Fix:

  • action_suspend_process now calls suspend_application_mode() directly in normal context, then sends SIGSTOP (not SIGTSTP)
  • SIGTSTP handler (for external kill -TSTP) schedules the action via call_soon_threadsafe to run in event loop context
  • _resume_signal now calls refresh(layout=True) to redraw after resume

Fixes #6298

Root cause: action_suspend_process sent SIGTSTP, whose handler called
suspend_application_mode() which does _key_thread.join(). This blocks
waiting for the input thread, but the input thread may be posting
messages via asyncio which needs the event loop - but the event loop
can't run while blocked in the signal handler. This causes a deadlock.

Fix:
- action_suspend_process now calls suspend_application_mode() directly
  in normal context, then sends SIGSTOP (not SIGTSTP)
- SIGTSTP handler (for external kill -TSTP) schedules the action via
  call_soon_threadsafe to run in event loop context
- _resume_signal now calls refresh(layout=True) to redraw after resume

Fixes Textualize#6298
# With that out of the way, send the SIGTSTP signal.
os.kill(os.getpid(), signal.SIGTSTP)
self._driver.suspend_application_mode()
self._driver._must_signal_resume = True
Copy link
Author

@pasky pasky Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

N.B. this feels like a layering violation, but I wanted a minimal patch and the whole WINDOWS test cuts through the abstraction anyway.

Perhaps .suspend_application_mode() should just take an argument whether to suspend the process and all of action_suspend_process() would be moved to driver-specific code?

@pasky
Copy link
Author

pasky commented Jan 18, 2026

(Note that I decided to ultimately switch from textual to urwid for my project since I couldn't figure out how to avoid textual's input lag [w/o setting insane FPS], so I'm unlikely to make any followups on this PR - hopefully it still serves as a good base for a fix!)

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.

action_suspend_process leaves the terminal the raw state

1 participant