Commit 1b89770
bugfix: crash on rapidly received SIGWINCH (#165)
**Problem**: pytermgui calls print() and eventually sys.stdout.flush()
from within a signal handler, which is a blocking operating, and can
cause crashes::
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
<details>
Traceback (most recent call last):
File "/home/jq/Code/pytermgui/examples/simple_app.py", line 213, in <module>
main(sys.argv[1:])
~~~~^^^^^^^^^^^^^^
File "/home/jq/Code/pytermgui/examples/simple_app.py", line 141, in main
with ptg.WindowManager() as manager:
~~~~~~~~~~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/manager.py", line 117, in __exit__
self.run()
~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/manager.py", line 198, in run
self._run_input_loop()
~~~~~~~~~~~~~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/manager.py", line 135, in _run_input_loop
key = getch(interrupts=False)
File "/home/jq/Code/pytermgui/pytermgui/input.py", line 438, in getch
key = _getch()
File "/home/jq/Code/pytermgui/pytermgui/input.py", line 152, in __call__
buff = "".join(self.get_chars())
File "/home/jq/Code/pytermgui/pytermgui/input.py", line 140, in get_chars
yield self._read(1)
~~~~~~~~~~^^^
File "/home/jq/Code/pytermgui/pytermgui/input.py", line 119, in _read
char = os.read(sys.stdin.fileno(), 1)
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 358, in _update_size
self._call_listener(self.RESIZE, self.size)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 339, in _call_listener
callback(data)
~~~~~~~~^^^^^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/manager.py", line 174, in on_resize
self.compositor.redraw()
~~~~~~~~~~~~~~~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/compositor.py", line 270, in redraw
self.draw(force=True)
~~~~~~~~~^^^^^^^^^^^^
File "/home/jq/Code/pytermgui/pytermgui/window_manager/compositor.py", line 259, in draw
with self.terminal.frame() as frame:
~~~~~~~~~~~~~~~~~~~^^
File "/home/jq/.pyenv/versions/3.15.0a5/lib/python3.15/contextlib.py", line 148, in __exit__
next(self.gen)
~~~~^^^^^^^^^^
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 465, in frame
self.flush()
~~~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 601, in flush
self._stream.flush()
~~~~~~~~~~~~~~~~~~^^
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 353, in _update_size
if hasattr(self, "resolution"):
~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/home/jq/.pyenv/versions/3.15.0a5/lib/python3.15/functools.py", line 1146, in __get__
val = self.func(instance)
File "/home/jq/Code/pytermgui/pytermgui/term.py", line 308, in resolution
sys.stdout.flush()
~~~~~~~~~~~~~~~~^^
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
</details>
I have written about "signal safety" with SIGNWICH here, and apply a
similar solution for pytermgui,
https://blessed.readthedocs.io/en/latest/measuring.html#using-sigwinch
- Remove screen wipe (``\x1b[H\x1b[2J``) from resize handler
- this was the cause of the crash
- use threading.Event() as a semaphore, thread-safe, naturally
- Reduce windows polling period from 0.001 to 0.01s
- main loop periodically checks process_pending_resize()
Co-authored-by: Balázs Cene <bczsalba@gmail.com>1 parent 7aeb3df commit 1b89770
2 files changed
+30
-8
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
263 | 264 | | |
264 | 265 | | |
265 | 266 | | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
266 | 270 | | |
267 | 271 | | |
268 | 272 | | |
| |||
278 | 282 | | |
279 | 283 | | |
280 | 284 | | |
281 | | - | |
| 285 | + | |
282 | 286 | | |
283 | 287 | | |
284 | 288 | | |
285 | 289 | | |
286 | 290 | | |
287 | 291 | | |
288 | | - | |
| 292 | + | |
289 | 293 | | |
290 | | - | |
| 294 | + | |
291 | 295 | | |
292 | 296 | | |
293 | 297 | | |
| |||
348 | 352 | | |
349 | 353 | | |
350 | 354 | | |
351 | | - | |
| 355 | + | |
352 | 356 | | |
353 | | - | |
354 | | - | |
| 357 | + | |
355 | 358 | | |
356 | | - | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
357 | 370 | | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
358 | 377 | | |
359 | 378 | | |
360 | 379 | | |
361 | 380 | | |
| 381 | + | |
| 382 | + | |
362 | 383 | | |
363 | 384 | | |
364 | 385 | | |
| |||
459 | 480 | | |
460 | 481 | | |
461 | 482 | | |
462 | | - | |
463 | 483 | | |
464 | 484 | | |
465 | 485 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
| 69 | + | |
68 | 70 | | |
69 | 71 | | |
70 | 72 | | |
| |||
0 commit comments