fix run_command_in_foreground to disconnect from stdin while in backgound

Not sure how I didn't notice this when implementing it for the first
time but well. This is all fairly confusing.
This commit is contained in:
Michael Hudson-Doyle 2019-09-30 16:11:31 +13:00
parent f69a393380
commit 93732dfb73
1 changed files with 18 additions and 7 deletions

View File

@ -299,23 +299,34 @@ class Application:
def run_command_in_foreground(self, cmd, **kw): def run_command_in_foreground(self, cmd, **kw):
screen = self.loop.screen screen = self.loop.screen
# Calling screen.stop() sends the INPUT_DESCRIPTORS_CHANGED
# signal. This calls _reset_input_descriptors() which calls
# unhook_event_loop / hook_event_loop on the screen. But this all
# happens before _started is set to False on the screen and so this
# does not actually do anything -- we end up attempting to read from
# stdin while in a background process group, something that gets the
# kernel upset at us.
#
# The cleanest fix seems to be to just send the signal again once
# stop() has returned which, now that screen._started is False,
# correctly stops listening from stdin.
#
# There is an exactly analagous problem with screen.start() except
# there the symptom is that we are running in the foreground but not
# listening to stdin! The fix is the same.
def run(): def run():
subprocess.run(cmd, **kw) subprocess.run(cmd, **kw)
def restore(fut): def restore(fut):
screen.start() screen.start()
# Calling screen.start() sends the INPUT_DESCRIPTORS_CHANGED
# signal. This calls _reset_input_descriptors() which calls
# unhook_event_loop / hook_event_loop on the screen. But this all
# happens before _started is set on the screen, so hook_event_loop
# does not actually do anything -- and we end up not listening to
# stdin, obviously a defective situation for a console
# application. So send it again now the screen is started...
urwid.emit_signal( urwid.emit_signal(
screen, urwid.display_common.INPUT_DESCRIPTORS_CHANGED) screen, urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
tty.setraw(0) tty.setraw(0)
screen.stop() screen.stop()
urwid.emit_signal(
screen, urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
self.run_in_bg(run, restore) self.run_in_bg(run, restore)
def _connect_base_signals(self): def _connect_base_signals(self):