diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index f7db621abf..7f9f275d0e 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -433,13 +433,11 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy rescue ErrorDuringExecution raise CurlDownloadStrategyError, url end - ignore_interrupts do - cached_location.dirname.mkpath - temporary_path.rename(cached_location) - symlink_location.dirname.mkpath - end + cached_location.dirname.mkpath + temporary_path.rename(cached_location) end + symlink_location.dirname.mkpath FileUtils.ln_s cached_location.relative_path_from(symlink_location.dirname), symlink_location, force: true rescue CurlDownloadStrategyError raise if urls.empty? diff --git a/Library/Homebrew/extend/kernel.rb b/Library/Homebrew/extend/kernel.rb index df6d227fdb..61d1e0b610 100644 --- a/Library/Homebrew/extend/kernel.rb +++ b/Library/Homebrew/extend/kernel.rb @@ -349,30 +349,26 @@ module Kernel end end - def ignore_interrupts(_opt = nil) - # rubocop:disable Style/GlobalVars - $ignore_interrupts_nesting_level = 0 unless defined?($ignore_interrupts_nesting_level) - $ignore_interrupts_nesting_level += 1 + IGNORE_INTERRUPTS_MUTEX = Thread::Mutex.new.freeze - $ignore_interrupts_interrupted = false unless defined?($ignore_interrupts_interrupted) - old_sigint_handler = trap(:INT) do - $ignore_interrupts_interrupted = true - $stderr.print "\n" - $stderr.puts "One sec, cleaning up..." - end + def ignore_interrupts + IGNORE_INTERRUPTS_MUTEX.synchronize do + interrupted = T.let(false, T::Boolean) + old_sigint_handler = trap(:INT) do + interrupted = true - begin - yield - ensure - trap(:INT, old_sigint_handler) + $stderr.print "\n" + $stderr.puts "One sec, cleaning up..." + end - $ignore_interrupts_nesting_level -= 1 - if $ignore_interrupts_nesting_level == 0 && $ignore_interrupts_interrupted - $ignore_interrupts_interrupted = false - raise Interrupt + begin + yield + ensure + trap(:INT, old_sigint_handler) + + raise Interrupt if interrupted end end - # rubocop:enable Style/GlobalVars end def redirect_stdout(file) diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb index 061cb1b90a..31915d1f5a 100644 --- a/Library/Homebrew/system_command.rb +++ b/Library/Homebrew/system_command.rb @@ -238,14 +238,12 @@ class SystemCommand } options[:chdir] = chdir if chdir - raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = ignore_interrupts do - Open3.popen3( - env.merge({ "COLUMNS" => Tty.width.to_s }), - [executable, executable], - *args, - **options, - ) - end + raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = Open3.popen3( + env.merge({ "COLUMNS" => Tty.width.to_s }), + [executable, executable], + *args, + **options, + ) write_input_to(raw_stdin) raw_stdin.close_write diff --git a/Library/Homebrew/utils/fork.rb b/Library/Homebrew/utils/fork.rb index 7334225321..d37dda94ef 100644 --- a/Library/Homebrew/utils/fork.rb +++ b/Library/Homebrew/utils/fork.rb @@ -75,11 +75,13 @@ module Utils exit!(true) end - ignore_interrupts(:quietly) do # the child will receive the interrupt and marshal it back + pid = T.must(pid) + + begin begin socket = server.accept_nonblock rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR - retry unless Process.waitpid(T.must(pid), Process::WNOHANG) + retry unless Process.waitpid(pid, Process::WNOHANG) else socket.send_io(write) socket.close @@ -87,23 +89,24 @@ module Utils write.close data = read.read read.close - Process.wait(T.must(pid)) unless socket.nil? - - # 130 is the exit status for a process interrupted via Ctrl-C. - # We handle it here because of the possibility of an interrupted process terminating - # without writing its Interrupt exception to the error pipe. - raise Interrupt if $CHILD_STATUS.exitstatus == 130 - - if data.present? - error_hash = JSON.parse(T.must(data.lines.first)) - - e = ChildProcessError.new(error_hash) - - raise rewrite_child_error(e) - end - - raise "Forked child process failed: #{$CHILD_STATUS}" unless $CHILD_STATUS.success? + Process.waitpid(pid) unless socket.nil? + rescue Interrupt + Process.waitpid(pid) end + + # 130 is the exit status for a process interrupted via Ctrl-C. + raise Interrupt if $CHILD_STATUS.exitstatus == 130 + raise Interrupt if $CHILD_STATUS.termsig == Signal.list["INT"] + + if data.present? + error_hash = JSON.parse(T.must(data.lines.first)) + + e = ChildProcessError.new(error_hash) + + raise rewrite_child_error(e) + end + + raise "Forked child process failed: #{$CHILD_STATUS}" unless $CHILD_STATUS.success? end end end diff --git a/Library/Homebrew/utils/github/artifacts.rb b/Library/Homebrew/utils/github/artifacts.rb index 70290e579e..9e0756a5f1 100644 --- a/Library/Homebrew/utils/github/artifacts.rb +++ b/Library/Homebrew/utils/github/artifacts.rb @@ -43,12 +43,11 @@ class GitHubArtifactDownloadStrategy < AbstractFileDownloadStrategy rescue ErrorDuringExecution raise CurlDownloadStrategyError, url end - ignore_interrupts do - cached_location.dirname.mkpath - temporary_path.rename(cached_location) - symlink_location.dirname.mkpath - end + cached_location.dirname.mkpath + temporary_path.rename(cached_location) end + + symlink_location.dirname.mkpath FileUtils.ln_s cached_location.relative_path_from(symlink_location.dirname), symlink_location, force: true end