Skip to content

Commit de3d8e9

Browse files
committed
prevent to child process handle leak
To wait process terminate with timeout, use Process.detach and Thread#join(timeout)
1 parent 6c85a8e commit de3d8e9

File tree

1 file changed

+41
-25
lines changed

1 file changed

+41
-25
lines changed

lib/yamatanooroti/windows/terminal.rb

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@ class Yamatanooroti::WindowsTerminalTerm
22
include Yamatanooroti::WindowsTermMixin
33

44
@@count = 0
5+
@@cradle = {}
6+
7+
def call_spawn(command)
8+
pid = spawn(command)
9+
if t = Process.detach(pid)
10+
@@cradle[pid] = t
11+
end
12+
pid
13+
end
14+
15+
def kill_and_wait(pid)
16+
return unless pid
17+
t = @@cradle[pid]
18+
begin
19+
Process.kill(:KILL, pid)
20+
rescue Errno::ESRCH # No such process
21+
end
22+
if t
23+
if t.join(@timeout) == nil
24+
puts "Caution: process #{pid} does not terminate in #{@timeout} seconds."
25+
end
26+
@@cradle.delete(pid)
27+
end
28+
end
529

630
def get_size
731
attach_terminal do |conin, conout|
@@ -27,10 +51,10 @@ def pid_from_windowtitle(name)
2751
do_tasklist("WINDOWTITLE eq #{name}")
2852
end
2953

30-
private def invoke_wt_process(command, marker, timeout)
31-
spawn(command)
54+
private def invoke_wt_process(command, marker)
55+
call_spawn(command)
3256
# wait for create console process complete
33-
wait_until = Time.now + timeout + 3 # 2sec timeout seems to be too short
57+
wait_until = Time.now + @timeout + 3 # 2sec timeout seems to be too short
3458
marker_pid = loop do
3559
pid = pid_from_imagename(marker)
3660
break pid if pid
@@ -46,7 +70,7 @@ def pid_from_windowtitle(name)
4670
end
4771

4872
keeper_pid = attach_terminal do
49-
spawn(CONSOLE_KEEPING_COMMAND)
73+
call_spawn(CONSOLE_KEEPING_COMMAND)
5074
end
5175
@console_process_id = keeper_pid
5276

@@ -56,29 +80,29 @@ def pid_from_windowtitle(name)
5680
sleep 0.01 * 2**n
5781
end
5882

59-
Process.kill(:KILL, marker_pid)
83+
kill_and_wait(marker_pid)
6084
return keeper_pid
6185
end
6286

63-
def new_wt(rows, cols, timeout)
87+
def new_wt(rows, cols)
6488
marker_command = CONSOLE_MARKING_COMMAND
6589

6690
@wt_id = "yamaoro#{Process.pid}##{@@count}"
6791
@@count += 1
6892
command = "#{Yamatanooroti::WindowsConsoleSettings.wt_exe} -w #{@wt_id} --size #{cols},#{rows} nt --title #{@wt_id} #{marker_command}"
6993

70-
return invoke_wt_process(command, marker_command.split(" ").first, timeout)
94+
return invoke_wt_process(command, marker_command.split(" ").first)
7195
end
7296

73-
def split_pane(div = 0.5, timeout)
97+
def split_pane(div = 0.5)
7498
marker_command = CONSOLE_MARKING_COMMAND
7599

76100
command = "#{Yamatanooroti::WindowsConsoleSettings.wt_exe} -w #{@wt_id} sp -V --title #{@wt_id} -s #{div} #{marker_command}"
77-
return invoke_wt_process(command, marker_command.split(" ").first, timeout)
101+
return invoke_wt_process(command, marker_command.split(" ").first)
78102
end
79103

80104
def close_pane
81-
Process.kill(:KILL, @console_process_id)
105+
kill_and_wait(@console_process_id)
82106
@console_process_id = @terminal_process_id
83107
end
84108

@@ -107,12 +131,12 @@ def self.setup_console(height, width, wait, timeout)
107131
loop do
108132
w = dw = @@div_to_width[div]
109133
unless w
110-
wt.split_pane(div/100.0, timeout)
134+
wt.split_pane(div/100.0)
111135
size = wt.get_size
112136
w = @@div_to_width[div] = size[1]
113137
end
114138
if w == width
115-
wt.split_pane(div/100.0, timeout) if dw
139+
wt.split_pane(div/100.0) if dw
116140
@@width_to_div[width] = div
117141
return wt
118142
else
@@ -137,10 +161,11 @@ def self.setup_console(height, width, wait, timeout)
137161

138162
def initialize(height, width, wait, timeout)
139163
@wait = wait
164+
@timeout = timeout
140165
@result = nil
141166
@codepage_success_p = nil
142167

143-
@terminal_process_id = new_wt(height, width, timeout)
168+
@terminal_process_id = new_wt(height, width)
144169
end
145170

146171
def close
@@ -154,17 +179,8 @@ def close_console
154179
if @target && !@target.closed?
155180
@target.close
156181
end
157-
begin
158-
Process.kill("KILL", @console_process_id) if @console_process_id
159-
rescue Errno::ESRCH # No such process
160-
ensure
161-
begin
162-
if @console_process_id != @terminal_process_id
163-
Process.kill("KILL", @terminal_process_id)
164-
end
165-
rescue Errno::ESRCH # No such process
166-
end
167-
@console_process_id = @terminal_process_id = nil
168-
end
182+
kill_and_wait(@console_process_id) if @console_process_id
183+
kill_and_wait(@terminal_process_id) if @console_process_id != @terminal_process_id
184+
@console_process_id = @terminal_process_id = nil
169185
end
170186
end

0 commit comments

Comments
 (0)