Try to cleanup dangling processes on int or timeout (#5, #6)

This commit is contained in:
Junegunn Choi 2013-09-28 18:53:18 +09:00
parent fe942d61d2
commit 3a4ffb49e9

View File

@ -328,22 +328,26 @@ endfunction
function! s:update_parallel(pull, threads) function! s:update_parallel(pull, threads)
ruby << EOF ruby << EOF
st = Time.now
require 'thread' require 'thread'
require 'fileutils' require 'fileutils'
require 'timeout' require 'timeout'
st = Time.now running = true
iswin = VIM::evaluate('s:is_win').to_i == 1 iswin = VIM::evaluate('s:is_win').to_i == 1
cd = iswin ? 'cd /d' : 'cd'
pull = VIM::evaluate('a:pull').to_i == 1 pull = VIM::evaluate('a:pull').to_i == 1
base = VIM::evaluate('g:plug_home') base = VIM::evaluate('g:plug_home')
all = VIM::evaluate('copy(g:plugs)') all = VIM::evaluate('copy(g:plugs)')
limit = VIM::evaluate('get(g:, "plug_timeout", 60)') limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
nthr = VIM::evaluate('a:threads').to_i
cd = iswin ? 'cd /d' : 'cd'
done = {} done = {}
tot = 0
skip = 'Already installed' skip = 'Already installed'
mtx = Mutex.new mtx = Mutex.new
take1 = proc { mtx.synchronize { all.shift } } take1 = proc { mtx.synchronize { running && all.shift } }
logh = proc { logh = proc {
cnt, tot = done.length, VIM::evaluate('len(g:plugs)') cnt = done.length
tot = VIM::evaluate('len(g:plugs)') || tot
$curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
$curbuf[2] = '[' + ('=' * cnt).ljust(tot) + ']' $curbuf[2] = '[' + ('=' * cnt).ljust(tot) + ']'
VIM::command('normal! 2G') VIM::command('normal! 2G')
@ -360,6 +364,7 @@ function! s:update_parallel(pull, threads)
} }
bt = proc { |cmd| bt = proc { |cmd|
begin begin
fd = nil
Timeout::timeout(limit) do Timeout::timeout(limit) do
if iswin if iswin
tmp = VIM::evaluate('tempname()') tmp = VIM::evaluate('tempname()')
@ -367,19 +372,39 @@ function! s:update_parallel(pull, threads)
data = File.read(tmp).chomp data = File.read(tmp).chomp
File.unlink tmp rescue nil File.unlink tmp rescue nil
else else
data = `#{cmd}`.chomp fd = IO.popen(cmd)
data = fd.read.chomp
fd.close
end end
[$? == 0, data] [$? == 0, data]
end end
rescue Timeout::Error rescue Timeout::Error, Interrupt => e
[false, "Timeout!"] if fd && !fd.closed?
Process.kill 'KILL', fd.pid
fd.close
end end
[false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
end
}
main = Thread.current
threads = []
watcher = Thread.new {
while VIM::evaluate('getchar(1)')
sleep 0.1
end
mtx.synchronize do
running = false
threads.each { |t| t.raise Interrupt }
end
threads.each { |t| t.join rescue nil }
main.kill
} }
until all.empty? until all.empty?
names = all.keys names = all.keys
[names.length, VIM::evaluate('a:threads').to_i].min.times.map { |i| [names.length, nthr].min.times do
Thread.new(i) do mtx.synchronize do
threads << Thread.new {
while pair = take1.call while pair = take1.call
name = pair.first name = pair.first
dir, uri, branch = pair.last.values_at *%w[dir uri branch] dir, uri, branch = pair.last.values_at *%w[dir uri branch]
@ -393,8 +418,10 @@ function! s:update_parallel(pull, threads)
else else
[true, skip] [true, skip]
end end
elsif current_uri =~ /^Interrupted|^Timeout/
[false, current_uri]
else else
[false, "PlugClean required. Invalid status."] [false, "PlugClean required: #{current_uri}"]
end end
else else
FileUtils.mkdir_p(base) FileUtils.mkdir_p(base)
@ -404,11 +431,15 @@ function! s:update_parallel(pull, threads)
result = result.lines.to_a.last result = result.lines.to_a.last
log.call name, (result && result.strip), ok log.call name, (result && result.strip), ok
end end
} if running
end end
}.each(&:join) end
all.merge! VIM::evaluate("s:extend(#{names.inspect})") threads.each(&:join)
mtx.synchronize { threads.clear }
all.merge!(VIM::evaluate("s:extend(#{names.inspect})") || {})
logh.call logh.call
end end
watcher.kill
$curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec." $curbuf[1] = "Updated. Elapsed time: #{"%.6f" % (Time.now - st)} sec."
EOF EOF
endfunction endfunction