Виртуальная оболочка Ruby kill открыта с помощью PTY.spawn - PullRequest
3 голосов
/ 10 июня 2011

В сценарии ruby ​​я запускаю больше виртуальных оболочек, каждая из которых управляется объектом диспетчера оболочки, например:

@shell = PTY.spawn 'env PS1="\w>" TERM=dumb COLUMNS=63 LINES=21 sh -i'

В какой-то более поздний момент я хотел бы уничтожить этот экземпляр, а также уничтожить связанный процесс оболочки. К сожалению, я не могу заставить что-либо работать должным образом. Вот то, что я попробовал, в порядке вероятности для работы:

  • Ничего, ожидая, что процесс оболочки будет закрыт, когда управляющий объект будет уничтожен.
  • Уничтожение всех процессов, запущенных в оболочке (это работает), с помощью команды kill, а затем уничтожение самой оболочки с помощью system("kill #{@shell[2]"). Это не имеет никакого эффекта.
  • Использование -9 в приведенном выше. Это оставляет процесс оболочки несуществующим.

Все оболочки закрываются при выходе из программы ruby, но я хочу убить их, продолжая работу программы. Кто-нибудь сталкивался с чем-то подобным раньше?

1 Ответ

5 голосов
/ 10 июня 2011

Проблема зомби. Да, действительно.

Все ядра Unix-стиля оставляют процесс, пока кто-то его не ждет. (Это для того, чтобы отслеживать PID, статус выхода и немного другого.) Они называются зомби и имеют Z-состояние в списке ps (1). Вы не можете убить их, потому что они уже мертвы. Они уходят, когда вы их ждете.

Итак, как очистить ваш @shell объект:

@shell[0].close
@shell[1].close
begin
  Process.wait @shell[2]
rescue PTY::ChildExited
end

Вам может не понадобиться спасательный блок в зависимости от того, есть ли у вас слои более высокого уровня, перехватывающие исключения слишком широко. (Вздох, как мой ирб.)

Кстати, причина, по которой ваш процесс, наконец, исчез при выходе из программы Ruby, заключается в том, что тогда зомби также стал сиротой (без родительского процесса) и либо оболочка, либо init (8) в конечном итоге будут ждать всех сирот. *

...