Skip to content

Commit

Permalink
Add ChildProcess.close_on_exec helper to work around #1.
Browse files Browse the repository at this point in the history
  • Loading branch information
jarib committed Nov 8, 2010
1 parent 2c3080c commit 74225fd
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 4 deletions.
20 changes: 18 additions & 2 deletions lib/childprocess.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'childprocess/errors'
require 'childprocess/abstract_process'
require 'childprocess/abstract_io'
require "fcntl"

module ChildProcess
autoload :Unix, 'childprocess/unix'
Expand Down Expand Up @@ -67,6 +68,21 @@ def os
end
)
end

#
# By default, a child process will inherit open files and sockets from the parent process.
# This helper provides a cross-platform way of making sure that doesn't happen for the given file.
#

end
end
def close_on_exec(file)
if windows?
Windows.dont_inherit file
elsif file.respond_to?(:fcntl) && defined?(Fcntl::FD_CLOEXEC)
file.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
else
raise Error, "not sure how to set close-on-exec for #{file.inspect} on #{platform}"
end
end

end # class << self
end # ChildProcess
11 changes: 11 additions & 0 deletions lib/childprocess/windows/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ def waitpid2(pid, flags = 0)
[pid, code] if code
end

def dont_inherit(file)
unless file.respond_to?(:fileno)
raise ArgumentError, "expected #{file.inspect} to respond to :fileno"
end

handle = Lib.get_os_file_handle(file.fileno)

ok = Lib.set_handle_information(handle, HANDLE_FLAG_INHERIT, 0)
ok or raise Error, Lib.last_error_message
end

private

def no_hang?(flags)
Expand Down
2 changes: 1 addition & 1 deletion lib/childprocess/windows/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module ChildProcess::Windows

STARTF_USESTDHANDLES = 0x00000100
INVALID_HANDLE_VALUE = 0xFFFFFFFF

HANDLE_FLAG_INHERIT = 0x00000001

module Lib
enum :wait_status, [ :wait_object_0, 0,
Expand Down
10 changes: 9 additions & 1 deletion lib/childprocess/windows/functions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def self.create_proc(cmd, opts = {})
flags = 0
inherit = !!opts[:inherit]

flags |= DETACHED_PROCESS if opts[:detach]
flags |= DETACHED_PROCESS if opts[:detach]

si = StartupInfo.new
pi = ProcessInfo.new
Expand Down Expand Up @@ -183,6 +183,14 @@ def self.get_os_file_handle(fd_or_io)

attach_function :_get_osfhandle, :_get_osfhandle, [:int], :long

# BOOL WINAPI SetHandleInformation(
# __in HANDLE hObject,
# __in DWORD dwMask,
# __in DWORD dwFlags
# );

attach_function :set_handle_information, :SetHandleInformation, [:long, :ulong, :ulong], :bool

end # Lib
end # Windows
end # ChildProcess
13 changes: 13 additions & 0 deletions spec/childprocess_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,17 @@
end
end

it "can set close-on-exec when IO is inherited" do
server = TCPServer.new("localhost", 4433)
ChildProcess.close_on_exec server

process = sleeping_ruby
process.io.inherit!

process.start
server.close

lambda { TCPServer.new("localhost", 4433).close }.should_not raise_error
end

end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

require 'childprocess'
require 'spec'
require 'spec/autorun'
require 'tempfile'
require "socket"

module ChildProcessSpecHelper
RUBY = defined?(Gem) ? Gem.ruby : 'ruby'
Expand Down

0 comments on commit 74225fd

Please sign in to comment.