Add posix-y compatibility extension class over Mach::Semaphore.
This commit is contained in:
		
							parent
							
								
									680527cbab
								
							
						
					
					
						commit
						8158666e90
					
				| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					require 'set'
 | 
				
			||||||
 | 
					require 'mach'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module ProcessShared
 | 
				
			||||||
 | 
					  module Mach
 | 
				
			||||||
 | 
					    include ::Mach
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The set of ports that should be shared to forked child
 | 
				
			||||||
 | 
					    # processes.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # FIXME: protect with (original ruby) mutex?
 | 
				
			||||||
 | 
					    def self.shared_ports
 | 
				
			||||||
 | 
					      @shared_ports ||= Set.new
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def self.after_fork_child
 | 
				
			||||||
 | 
					      parent_port = Task.self.get_bootstrap_port
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # give parent permission to send to child's task port
 | 
				
			||||||
 | 
					      Task.self.copy_send(parent_port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # create a second port and give the parent permission to send
 | 
				
			||||||
 | 
					      port = Port.new
 | 
				
			||||||
 | 
					      port.insert_right(:make_send)
 | 
				
			||||||
 | 
					      port.copy_send(parent_port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # parent copies sem, mutex port permissions directly to child
 | 
				
			||||||
 | 
					      # task port
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # wait for parent to send orig bootstrap port
 | 
				
			||||||
 | 
					      orig_bootstrap = port.receive_right
 | 
				
			||||||
 | 
					      Task.self.set_special_port(:bootstrap, orig_bootstrap)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def self.after_fork_parent(port)
 | 
				
			||||||
 | 
					      child_task_port = port.receive_right
 | 
				
			||||||
 | 
					      shared_ports.each do |p|
 | 
				
			||||||
 | 
					        p.insert_right(:copy_send, :ipc_space => child_task_port)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      child_port = port.receive_right
 | 
				
			||||||
 | 
					      ::Mach::bootstrap_port.copy_send(child_port)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Kernel
 | 
				
			||||||
 | 
					  # Override to call Process::fork.
 | 
				
			||||||
 | 
					  def fork(*args, &block)
 | 
				
			||||||
 | 
					    Process.fork(*args, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Process
 | 
				
			||||||
 | 
					  class << self
 | 
				
			||||||
 | 
					    unless respond_to? :__mach_original_fork__
 | 
				
			||||||
 | 
					      alias_method :__mach_original_fork__, :fork
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Override to first copy all shared ports (semaphores, etc.) from
 | 
				
			||||||
 | 
					    # parent process to child process.
 | 
				
			||||||
 | 
					    def fork
 | 
				
			||||||
 | 
					      # make a port for receiving message from child
 | 
				
			||||||
 | 
					      port = Mach::Port.new
 | 
				
			||||||
 | 
					      port.insert_right(:make_send)
 | 
				
			||||||
 | 
					      Mach::Task.self.set_bootstrap_port(port)
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if block_given?
 | 
				
			||||||
 | 
					        pid = __mach_original_fork__ do
 | 
				
			||||||
 | 
					          ProcessShared::Mach.after_fork_child
 | 
				
			||||||
 | 
					          yield
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProcessShared::Mach.after_fork_parent(port)
 | 
				
			||||||
 | 
					        pid
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        if pid = __mach_original_fork__
 | 
				
			||||||
 | 
					          ProcessShared::Mach.after_fork_parent(port)
 | 
				
			||||||
 | 
					          pid
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          ProcessShared::Mach.after_fork_child
 | 
				
			||||||
 | 
					          nil
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mach/time_spec'
 | 
				
			||||||
 | 
					require 'process_shared/time_spec'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Monkey patch to add #add_seconds! method
 | 
				
			||||||
 | 
					Mach::TimeSpec.send(:include, ProcessShared::TimeSpec)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					require 'mach'
 | 
				
			||||||
 | 
					require 'mach/error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'process_shared/mach'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module ProcessShared
 | 
				
			||||||
 | 
					  module Mach
 | 
				
			||||||
 | 
					    # Extends ::Mach::Semaphore to be compatible with ProcessShared::Semaphore
 | 
				
			||||||
 | 
					    class Semaphore < ::Mach::Semaphore
 | 
				
			||||||
 | 
					      include ProcessShared::Semaphore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def initialize(value = 1)
 | 
				
			||||||
 | 
					        super(:value => value)
 | 
				
			||||||
 | 
					        ProcessShared::Mach.shared_ports.add self
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def try_wait(timeout = nil)
 | 
				
			||||||
 | 
					        secs = timeout ? timeout : 0
 | 
				
			||||||
 | 
					        begin
 | 
				
			||||||
 | 
					          # TODO catch and convert exceptions...
 | 
				
			||||||
 | 
					          timedwait(secs)
 | 
				
			||||||
 | 
					        rescue Mach::Error::OPERATION_TIMED_OUT => e
 | 
				
			||||||
 | 
					          klass = secs == 0 ? Errno::EAGAIN : Errno::ETIMEDOUT
 | 
				
			||||||
 | 
					          raise klass, e.message
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      alias_method :post, :signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def value
 | 
				
			||||||
 | 
					        raise Errno::ENOTSUP
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def close
 | 
				
			||||||
 | 
					        # TODO
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -98,14 +98,13 @@ module ProcessShared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it 'returns after waiting if another processes posts' do
 | 
					      it 'returns after waiting if another processes posts' do
 | 
				
			||||||
        Semaphore.open(0) do |sem|
 | 
					        Semaphore.open(0) do |sem|
 | 
				
			||||||
          start = Time.now.to_f
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          pid = fork do
 | 
					          pid = fork do
 | 
				
			||||||
            sleep 0.01
 | 
					            sleep 0.01
 | 
				
			||||||
            sem.post
 | 
					            sem.post
 | 
				
			||||||
            Kernel.exit!
 | 
					            Kernel.exit!
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          start = Time.now.to_f
 | 
				
			||||||
          sem.try_wait(0.1)
 | 
					          sem.try_wait(0.1)
 | 
				
			||||||
          (Time.now.to_f - start).must be_lt(0.1)
 | 
					          (Time.now.to_f - start).must be_lt(0.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue