Permalink
Browse files

Reintegrate pull requests and split platforms.

Version bumped to 0.0.2.
  • Loading branch information...
1 parent 65f0206 commit 1eadc3eae8d7eead040752940dada43079abaa2c @headius committed Jul 25, 2012
Showing with 211 additions and 165 deletions.
  1. +5 −162 lib/spoon.rb
  2. +165 −0 lib/spoon/unix.rb
  3. +38 −0 lib/spoon/windows.rb
  4. +3 −3 spoon.gemspec
View
167 lib/spoon.rb 100644 → 100755
@@ -1,164 +1,7 @@
-require 'ffi'
+require 'rbconfig'
-module Spoon
-
- class FileActions
- attr_reader :pointer
- SIZE = FFI::Platform.mac? ? FFI.type_size(:pointer) : 128
-
- def initialize
- @pointer = FFI::AutoPointer.new(LibC.malloc(SIZE), self.class)
- error = LibC.posix_spawn_file_actions_init(@pointer)
- raise SystemCallError.new("posix_file_actions_init", error) unless error == 0
- end
-
- def self.release(ptr)
- LibC.posix_spawn_file_actions_destroy(ptr)
- LibC.free(ptr)
- end
-
- def open(fd, path, oflag, mode)
- error = LibC.posix_spawn_file_actions_addopen(@pointer, fd, path, oflag, mode)
- raise SystemCallError.new("posix_file_actions_addopen", error) unless error == 0
- self
- end
-
- def close(fd)
- error = LibC.posix_spawn_file_actions_addclose(@pointer, fd)
- raise SystemCallError.new("posix_file_actions_addclose", error) unless error == 0
- self
- end
-
- def dup2(fd, newfd)
- error = LibC.posix_spawn_file_actions_adddup2(@pointer, fd, newfd)
- raise SystemCallError.new("posix_file_actions_adddup2", error) unless error == 0
- self
- end
- end
-
- class SpawnAttributes
- attr_reader :pointer
- SIZE = FFI::Platform.mac? ? FFI.type_size(:pointer) : 128
-
- def initialize
- @pointer = FFI::AutoPointer.new(LibC.malloc(SIZE), self.class)
- error = LibC.posix_spawnattr_init(@pointer)
- raise SystemCallError.new("posix_spawnattr_init", error) unless error == 0
- end
-
- def self.release(ptr)
- LibC.posix_spawnattr_destroy(ptr)
- LibC.free(ptr)
- end
-
- def pgroup=(group)
- error = LibC.posix_spawnattr_setpgroup(pointer, group)
- raise SystemCallError.new("posix_spawnattr_setpgroup", error) unless error == 0
- group
- end
-
- def pgroup
- group = FFI::MemoryPointer.new :pid_t
- error = LibC.posix_spawnattr_getpgroup(pointer, group)
- raise SystemCallError.new("posix_spawnattr_getpgroup", error) unless error == 0
- get_pid(group)
- end
- end
-
- def self.posix_spawn(path, file_actions, spawn_attr, argv, env = ENV)
- pid_ptr, argv_ptr, env_ptr = _prepare_spawn_args(argv, env)
- error = LibC.posix_spawnp(pid_ptr, path, file_actions, spawn_attr, argv_ptr, env_ptr)
- raise SystemCallError.new(path, error) unless error == 0
- get_pid(pid_ptr)
- end
-
- def self.posix_spawnp(file, file_actions, spawn_attr, argv, env = ENV)
- pid_ptr, argv_ptr, env_ptr = _prepare_spawn_args(argv, env)
- error = LibC.posix_spawnp(pid_ptr, file, file_actions, spawn_attr, argv_ptr, env_ptr)
- raise SystemCallError.new(file, error) unless error == 0
- get_pid(pid_ptr)
- end
-
- def self.spawn(*args)
- posix_spawn(args[0], nil, nil, args, ENV)
- end
-
- def self.spawnp(*args)
- posix_spawnp(args[0], nil, nil, args, ENV)
- end
-
- private
-
- class PointerArray
- def initialize
- @ary = []
- end
-
- def <<(ptr)
- @ary << ptr
- self
- end
-
- def pointer
- if @pointer.nil? || (@pointer.size / @pointer.type_size) <= @ary.length
- ptr = FFI::MemoryPointer.new(:pointer, @ary.length + 1)
- ptr.put_array_of_pointer(0, @ary)
- @pointer = ptr
- end
- @pointer
- end
- end
-
- if FFI.type_size(:pid_t) == 4
- def self.get_pid(ptr)
- ptr.get_int32(0)
- end
- else
- def self.get_pid(ptr)
- ptr.get_int64(0)
- end
- end
-
- def self._prepare_spawn_args(argv, env)
- pid_ptr = FFI::MemoryPointer.new(:pid_t, 1)
-
- args_ary = argv.inject(PointerArray.new) { |ary, str| ary << FFI::MemoryPointer.from_string(str) }
- env_ary = PointerArray.new
- env.each_pair { |key, value| env_ary << FFI::MemoryPointer.from_string("#{key}=#{value}") }
-
- [pid_ptr, args_ary, env_ary]
- end
-
- module LibC
- extend FFI::Library
- ffi_lib FFI::Library::LIBC
-
- class PointerConverter
- extend FFI::DataConverter
- native_type FFI::Type::POINTER
-
- def self.to_native(value, ctx)
- value ? value.pointer : nil
- end
- end
-
- typedef PointerConverter, :file_actions
- typedef PointerConverter, :spawn_attr
- typedef PointerConverter, :ptr_array
-
- attach_function :posix_spawn, [:pointer, :string, :file_actions, :spawn_attr, :ptr_array, :ptr_array ], :int
- attach_function :posix_spawnp, [:pointer, :string, :file_actions, :spawn_attr, :ptr_array, :ptr_array ], :int
- attach_function :posix_spawn_file_actions_init, [ :pointer ], :int
- attach_function :posix_spawn_file_actions_destroy, [ :pointer ], :int
- attach_function :posix_spawn_file_actions_adddup2, [ :pointer, :int, :int ], :int
- attach_function :posix_spawn_file_actions_addclose, [ :pointer, :int ], :int
- attach_function :posix_spawn_file_actions_addopen, [ :pointer, :int, :string, :int, :mode_t ], :int
- attach_function :posix_spawnattr_init, [ :pointer ], :int
- attach_function :posix_spawnattr_destroy, [ :pointer ], :int
- attach_function :posix_spawnattr_setpgroup, [ :pointer, :pid_t ], :int
- attach_function :posix_spawnattr_getpgroup, [ :pointer, :pointer ], :int
- attach_function :malloc, [ :size_t ], :pointer
- attach_function :free, [ :pointer ], :void
- attach_function :strerror, [ :int ], :string
- end
+if RbConfig::CONFIG['host_os'] =~ /mingw|mswin|bccwin/
+ require 'spoon/windows'
+else
+ require 'spoon/unix'
end
View
165 lib/spoon/unix.rb
@@ -0,0 +1,165 @@
+# UNIX posix_spawn
+
+require 'ffi'
+
+module Spoon
+ class FileActions
+ attr_reader :pointer
+ SIZE = FFI::Platform.mac? ? FFI.type_size(:pointer) : 128
+
+ def initialize
+ @pointer = FFI::AutoPointer.new(LibC.malloc(SIZE), self.class)
+ error = LibC.posix_spawn_file_actions_init(@pointer)
+ raise SystemCallError.new("posix_file_actions_init", error) unless error == 0
+ end
+
+ def self.release(ptr)
+ LibC.posix_spawn_file_actions_destroy(ptr)
+ LibC.free(ptr)
+ end
+
+ def open(fd, path, oflag, mode)
+ error = LibC.posix_spawn_file_actions_addopen(@pointer, fd, path, oflag, mode)
+ raise SystemCallError.new("posix_file_actions_addopen", error) unless error == 0
+ self
+ end
+
+ def close(fd)
+ error = LibC.posix_spawn_file_actions_addclose(@pointer, fd)
+ raise SystemCallError.new("posix_file_actions_addclose", error) unless error == 0
+ self
+ end
+
+ def dup2(fd, newfd)
+ error = LibC.posix_spawn_file_actions_adddup2(@pointer, fd, newfd)
+ raise SystemCallError.new("posix_file_actions_adddup2", error) unless error == 0
+ self
+ end
+ end
+
+ class SpawnAttributes
+ attr_reader :pointer
+ SIZE = FFI::Platform.mac? ? FFI.type_size(:pointer) : 128
+
+ def initialize
+ @pointer = FFI::AutoPointer.new(LibC.malloc(SIZE), self.class)
+ error = LibC.posix_spawnattr_init(@pointer)
+ raise SystemCallError.new("posix_spawnattr_init", error) unless error == 0
+ end
+
+ def self.release(ptr)
+ LibC.posix_spawnattr_destroy(ptr)
+ LibC.free(ptr)
+ end
+
+ def pgroup=(group)
+ error = LibC.posix_spawnattr_setpgroup(pointer, group)
+ raise SystemCallError.new("posix_spawnattr_setpgroup", error) unless error == 0
+ group
+ end
+
+ def pgroup
+ group = FFI::MemoryPointer.new :pid_t
+ error = LibC.posix_spawnattr_getpgroup(pointer, group)
+ raise SystemCallError.new("posix_spawnattr_getpgroup", error) unless error == 0
+ get_pid(group)
+ end
+ end
+
+ def self.posix_spawn(path, file_actions, spawn_attr, argv, env = ENV)
+ pid_ptr, argv_ptr, env_ptr = _prepare_spawn_args(argv, env)
+ error = LibC.posix_spawnp(pid_ptr, path, file_actions, spawn_attr, argv_ptr, env_ptr)
+ raise SystemCallError.new(path, error) unless error == 0
+ get_pid(pid_ptr)
+ end
+
+ def self.posix_spawnp(file, file_actions, spawn_attr, argv, env = ENV)
+ pid_ptr, argv_ptr, env_ptr = _prepare_spawn_args(argv, env)
+ error = LibC.posix_spawnp(pid_ptr, file, file_actions, spawn_attr, argv_ptr, env_ptr)
+ raise SystemCallError.new(file, error) unless error == 0
+ get_pid(pid_ptr)
+ end
+
+ def self.spawn(*args)
+ posix_spawn(args[0], nil, nil, args, ENV)
+ end
+
+ def self.spawnp(*args)
+ posix_spawnp(args[0], nil, nil, args, ENV)
+ end
+
+ private
+
+ class PointerArray
+ def initialize
+ @ary = []
+ end
+
+ def <<(ptr)
+ @ary << ptr
+ self
+ end
+
+ def pointer
+ if @pointer.nil? || (@pointer.size / @pointer.type_size) <= @ary.length
+ ptr = FFI::MemoryPointer.new(:pointer, @ary.length + 1)
+ ptr.put_array_of_pointer(0, @ary)
+ @pointer = ptr
+ end
+ @pointer
+ end
+ end
+
+ if FFI.type_size(:pid_t) == 4
+ def self.get_pid(ptr)
+ ptr.get_int32(0)
+ end
+ else
+ def self.get_pid(ptr)
+ ptr.get_int64(0)
+ end
+ end
+
+ module LibC
+ extend FFI::Library
+ ffi_lib FFI::Library::LIBC
+
+ class PointerConverter
+ extend FFI::DataConverter
+ native_type FFI::Type::POINTER
+
+ def self.to_native(value, ctx)
+ value ? value.pointer : nil
+ end
+ end
+
+ typedef PointerConverter, :file_actions
+ typedef PointerConverter, :spawn_attr
+ typedef PointerConverter, :ptr_array
+
+ attach_function :posix_spawn, [:pointer, :string, :file_actions, :spawn_attr, :ptr_array, :ptr_array ], :int
+ attach_function :posix_spawnp, [:pointer, :string, :file_actions, :spawn_attr, :ptr_array, :ptr_array ], :int
+ attach_function :posix_spawn_file_actions_init, [ :pointer ], :int
+ attach_function :posix_spawn_file_actions_destroy, [ :pointer ], :int
+ attach_function :posix_spawn_file_actions_adddup2, [ :pointer, :int, :int ], :int
+ attach_function :posix_spawn_file_actions_addclose, [ :pointer, :int ], :int
+ attach_function :posix_spawn_file_actions_addopen, [ :pointer, :int, :string, :int, :mode_t ], :int
+ attach_function :posix_spawnattr_init, [ :pointer ], :int
+ attach_function :posix_spawnattr_destroy, [ :pointer ], :int
+ attach_function :posix_spawnattr_setpgroup, [ :pointer, :pid_t ], :int
+ attach_function :posix_spawnattr_getpgroup, [ :pointer, :pointer ], :int
+ attach_function :malloc, [ :size_t ], :pointer
+ attach_function :free, [ :pointer ], :void
+ attach_function :strerror, [ :int ], :string
+ end
+
+ def self._prepare_spawn_args(argv, env)
+ pid_ptr = FFI::MemoryPointer.new(:pid_t, 1)
+
+ args_ary = argv.inject(PointerArray.new) { |ary, str| ary << FFI::MemoryPointer.from_string(str) }
+ env_ary = PointerArray.new
+ env.each_pair { |key, value| env_ary << FFI::MemoryPointer.from_string("#{key}=#{value}") }
+
+ [pid_ptr, args_ary, env_ary]
+ end
+end
View
38 lib/spoon/windows.rb
@@ -0,0 +1,38 @@
+# Windows _spawnv
+
+require 'ffi'
+
+module Spoon
+ P_NOWAIT = 1
+
+ attach_function :_spawnve, [:int, :string, :pointer, :pointer], :int
+ attach_function :_spawnvpe, [:int, :string, :pointer, :pointer], :int
+
+ ffi_lib 'kernel32'
+ ffi_convention :stdcall
+ attach_function :_get_process_id, :GetProcessId, [:int], :ulong
+
+ def self.spawn(*args)
+ spawn_args = _prepare_spawn_args(args)
+ _get_process_id(_spawnve(*spawn_args))
+ end
+
+ def self.spawnp(*args)
+ spawn_args = _prepare_spawn_args(args)
+ _get_process_id(_spawnvpe(*spawn_args))
+ end
+
+ private
+
+ def self._prepare_spawn_args(args)
+ args_ary = FFI::MemoryPointer.new(:pointer, args.length + 1)
+ str_ptrs = args.map {|str| FFI::MemoryPointer.from_string(str)}
+ args_ary.put_array_of_pointer(0, str_ptrs)
+
+ env_ary = FFI::MemoryPointer.new(:pointer, ENV.length + 1)
+ env_ptrs = ENV.map {|key,value| FFI::MemoryPointer.from_string("#{key}=#{value}")}
+ env_ary.put_array_of_pointer(0, env_ptrs)
+
+ [P_NOWAIT, args[0], args_ary, env_ary]
+ end
+end
View
6 spoon.gemspec
@@ -1,9 +1,9 @@
Gem::Specification.new do |s|
s.name = "spoon"
- s.version = "0.0.1"
+ s.version = "0.0.2"
s.authors = ["Charles Oliver Nutter"]
- s.date = "2010-01-10"
- s.description = s.summary = "Spoon is an FFI binding of the posix_spawn function, providing fork+exec functionality in a single shot."
+ s.date = "2012-04-20"
+ s.description = s.summary = "Spoon is an FFI binding of the posix_spawn function (and Windows equivalent), providing fork+exec functionality in a single shot."
s.files = "lib/spoon.rb"
s.require_paths = ["lib"]
s.add_dependency('ffi') unless defined?(JRUBY_VERSION) # JRuby includes ffi

0 comments on commit 1eadc3e

Please sign in to comment.