Add FFI wrapper around some of the Mach API (in Mac OS X).
This commit is contained in:
		
							parent
							
								
									3d01ce1ed6
								
							
						
					
					
						commit
						252d606c09
					
				| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
module Mach
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
require 'ffi'
 | 
			
		||||
 | 
			
		||||
require 'mach'
 | 
			
		||||
require 'mach/types'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  module Bootstrap
 | 
			
		||||
    extend FFI::Library
 | 
			
		||||
    include Types
 | 
			
		||||
 | 
			
		||||
    ffi_lib 'c'
 | 
			
		||||
 | 
			
		||||
    attach_variable :port, :bootstrap_port, :mach_port_t
 | 
			
		||||
 | 
			
		||||
    attach_function(:bootstrap_strerror,
 | 
			
		||||
                    [:kern_return_t],
 | 
			
		||||
                    :pointer)
 | 
			
		||||
 | 
			
		||||
    attach_function(:register,
 | 
			
		||||
                    :bootstrap_register,
 | 
			
		||||
                    [:mach_port_t, :name_t, :mach_port_t],
 | 
			
		||||
                    :kern_return_t)
 | 
			
		||||
 | 
			
		||||
    error_check :register
 | 
			
		||||
 | 
			
		||||
    # NOTE: api does not say this string must be freed; assuming it
 | 
			
		||||
    # does not
 | 
			
		||||
    #
 | 
			
		||||
    # @return [String] the error string or nil
 | 
			
		||||
    def self.strerror(errno)
 | 
			
		||||
      ptr = bootstrap_strerror(errno)
 | 
			
		||||
      ptr.null? ? nil : ptr.read_string()
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
require 'ffi'
 | 
			
		||||
 | 
			
		||||
require 'mach/functions'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  class Error < StandardError
 | 
			
		||||
    class INVALID_ADDRESS < Error; end
 | 
			
		||||
    class PROTECTION_FAILURE < Error; end
 | 
			
		||||
    class NO_SPACE < Error; end
 | 
			
		||||
    class INVALID_ARGUMENT < Error; end
 | 
			
		||||
    class INVALID_NAME < Error; end
 | 
			
		||||
    class FAILURE < Error; end
 | 
			
		||||
 | 
			
		||||
    include Functions
 | 
			
		||||
 | 
			
		||||
    def self.new(msg, errno)
 | 
			
		||||
      klass = case errno
 | 
			
		||||
              when 1; then INVALID_ADDRESS
 | 
			
		||||
              when 2; then PROTECTION_FAILURE
 | 
			
		||||
              when 3; then NO_SPACE
 | 
			
		||||
              when 4; then INVALID_ARGUMENT
 | 
			
		||||
              when 5; then FAILURE
 | 
			
		||||
              when 15; then INVALID_NAME
 | 
			
		||||
              else FAILURE
 | 
			
		||||
              end
 | 
			
		||||
 | 
			
		||||
      e = klass.allocate
 | 
			
		||||
      e.send(:initialize, msg, errno)
 | 
			
		||||
      e
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attr_reader :errno
 | 
			
		||||
 | 
			
		||||
    def initialize(msg, errno)
 | 
			
		||||
      super(msg)
 | 
			
		||||
      @errno = errno
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def to_s
 | 
			
		||||
      "#{super}: #{error_string(errno)}"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    protected
 | 
			
		||||
 | 
			
		||||
    # NOTE: api does not say this string must be freed; assuming it
 | 
			
		||||
    # does not
 | 
			
		||||
    def error_string(errno)
 | 
			
		||||
      ptr = mach_error_string(errno)
 | 
			
		||||
      ptr.null? ? nil : ptr.read_string()
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,252 @@
 | 
			
		|||
module Mach
 | 
			
		||||
  # FFI wrapper around a subset of the Mach API (likely Mac OS X
 | 
			
		||||
  # specific).
 | 
			
		||||
  module Functions
 | 
			
		||||
    extend FFI::Library
 | 
			
		||||
 | 
			
		||||
    ffi_lib 'c'
 | 
			
		||||
 | 
			
		||||
    typedef :__darwin_mach_port_t, :mach_port_t
 | 
			
		||||
    typedef :__darwin_natural_t, :natural_t
 | 
			
		||||
 | 
			
		||||
    typedef :mach_port_t, :task_t
 | 
			
		||||
    typedef :mach_port_t, :ipc_space_t
 | 
			
		||||
    typedef :mach_port_t, :semaphore_t
 | 
			
		||||
    typedef :pointer, :mach_port_pointer_t
 | 
			
		||||
 | 
			
		||||
    typedef :natural_t, :mach_port_name_t
 | 
			
		||||
    typedef :natural_t, :mach_port_right_t # MachPortRight
 | 
			
		||||
    typedef :pointer, :mach_port_name_array_t
 | 
			
		||||
    typedef :pointer, :mach_port_name_pointer_t
 | 
			
		||||
 | 
			
		||||
    typedef :uint, :mach_msg_type_name_t
 | 
			
		||||
 | 
			
		||||
    typedef :int, :kern_return_t # true for 64 bit??
 | 
			
		||||
    typedef :int, :mach_error_t
 | 
			
		||||
    typedef :int, :sync_policy_t # SyncPolicy
 | 
			
		||||
 | 
			
		||||
    typedef :string, :name_t
 | 
			
		||||
 | 
			
		||||
    SyncPolicy = enum( :fifo, 0x0,
 | 
			
		||||
                       :fixed_priority, 0x1,
 | 
			
		||||
                       :reversed, 0x2,
 | 
			
		||||
                       :order_mask, 0x3,
 | 
			
		||||
                       :lifo, 0x0 | 0x2, # um...
 | 
			
		||||
                       :max, 0x7 )
 | 
			
		||||
 | 
			
		||||
    MachPortRight = enum( :send, 0,
 | 
			
		||||
                          :receive,
 | 
			
		||||
                          :send_once,
 | 
			
		||||
                          :port_set,
 | 
			
		||||
                          :dead_name,
 | 
			
		||||
                          :labelh,
 | 
			
		||||
                          :number )
 | 
			
		||||
 | 
			
		||||
    # port type
 | 
			
		||||
    def self.pt(*syms)
 | 
			
		||||
      acc = 0
 | 
			
		||||
      syms.each do |sym|
 | 
			
		||||
        acc |= (1 << (MachPortRight[sym] + 16))
 | 
			
		||||
      end
 | 
			
		||||
      acc
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    MachPortType =
 | 
			
		||||
      enum(:none, 0,
 | 
			
		||||
           :send, pt(:send),
 | 
			
		||||
           :receive, pt(:receive),
 | 
			
		||||
           :send_once, pt(:send_once),
 | 
			
		||||
           :port_set, pt(:port_set),
 | 
			
		||||
           :dead_name, pt(:dead_name),
 | 
			
		||||
           :labelh, pt(:labelh),
 | 
			
		||||
           
 | 
			
		||||
           :send_receive, pt(:send, :receive),
 | 
			
		||||
           :send_rights, pt(:send, :send_once),
 | 
			
		||||
           :port_rights, pt(:send, :send_once, :receive),
 | 
			
		||||
           :port_or_dead, pt(:send, :send_once, :receive, :dead_name),
 | 
			
		||||
           :all_rights, pt(:send, :send_once, :receive, :dead_name, :port_set))
 | 
			
		||||
 | 
			
		||||
    MachMsgType =
 | 
			
		||||
      enum( :move_receive, 16, # must hold receive rights
 | 
			
		||||
            :move_send,        # must hold send rights
 | 
			
		||||
            :move_send_once,   # must hold sendonce rights
 | 
			
		||||
            :copy_send,        # must hold send rights
 | 
			
		||||
            :make_send,        # must hold receive rights
 | 
			
		||||
            :make_send_once,   # must hold receive rights
 | 
			
		||||
            :copy_receive )    # must hold receive rights
 | 
			
		||||
 | 
			
		||||
    MachSpecialPort =
 | 
			
		||||
      enum( :kernel, 1,
 | 
			
		||||
            :host,
 | 
			
		||||
            :name,
 | 
			
		||||
            :bootstrap )
 | 
			
		||||
 | 
			
		||||
    class Timespec < FFI::ManagedStruct
 | 
			
		||||
      layout(:tv_sec, :uint,
 | 
			
		||||
             :tv_nsec, :int)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    KERN_SUCCESS = 0
 | 
			
		||||
 | 
			
		||||
    # Replace methods in +syms+ with error checking wrappers that
 | 
			
		||||
    # invoke the original method and raise a {SystemCallError}.
 | 
			
		||||
    #
 | 
			
		||||
    # The original method is invoked, and it's return value is passed
 | 
			
		||||
    # to the block (or a default check).  The block should return true
 | 
			
		||||
    # if the return value indicates an error state.
 | 
			
		||||
    def self.error_check(*syms, &is_err)
 | 
			
		||||
      unless block_given?
 | 
			
		||||
        is_err = lambda { |v| (v != KERN_SUCCESS) }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      syms.each do |sym|
 | 
			
		||||
        method = self.method(sym)
 | 
			
		||||
 | 
			
		||||
        new_method_body = proc do |*args|
 | 
			
		||||
          ret = method.call(*args)
 | 
			
		||||
          if is_err.call(ret)
 | 
			
		||||
            raise Error.new("error in #{sym}", ret)
 | 
			
		||||
          else
 | 
			
		||||
            ret
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        define_singleton_method(sym, &new_method_body)
 | 
			
		||||
        define_method(sym, &new_method_body)
 | 
			
		||||
       end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Replace methods in +syms+ with error checking wrappers that
 | 
			
		||||
    # invoke the original method and raise a {SystemCallError}.
 | 
			
		||||
    #
 | 
			
		||||
    # The original method is invoked, and it's return value is passed
 | 
			
		||||
    # to the block (or a default check).  The block should return true
 | 
			
		||||
    # if the return value indicates an error state.
 | 
			
		||||
    def self.error_check_bootstrap(*syms, &is_err)
 | 
			
		||||
      unless block_given?
 | 
			
		||||
        is_err = lambda { |v| (v != KERN_SUCCESS) }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      syms.each do |sym|
 | 
			
		||||
        method = self.method(sym)
 | 
			
		||||
 | 
			
		||||
        new_method_body = proc do |*args|
 | 
			
		||||
          ret = method.call(*args)
 | 
			
		||||
          if is_err.call(ret)
 | 
			
		||||
            ptr = bootstrap_strerror(ret)
 | 
			
		||||
            msg = ptr.null? ? nil : ptr.read_string()
 | 
			
		||||
            raise "error in #{sym}: #{msg}"
 | 
			
		||||
          else
 | 
			
		||||
            ret
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        define_singleton_method(sym, &new_method_body)
 | 
			
		||||
        define_method(sym, &new_method_body)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Attach a function as with +attach_function+, but check the
 | 
			
		||||
    # return value and raise an exception on errors.
 | 
			
		||||
    def self.attach_mach_function(sym, argtypes, rettype)
 | 
			
		||||
      attach_function(sym, argtypes, rettype)
 | 
			
		||||
      error_check(sym)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.new_memory_pointer(type)
 | 
			
		||||
      FFI::MemoryPointer.new(find_type(type))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def new_memory_pointer(type)
 | 
			
		||||
      Mach::Functions.new_memory_pointer(type)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attach_function :mach_task_self, [], :task_t
 | 
			
		||||
    attach_function :mach_error_string, [:mach_error_t], :pointer
 | 
			
		||||
 | 
			
		||||
    #######################
 | 
			
		||||
    # Bootstrap functions #
 | 
			
		||||
    #######################
 | 
			
		||||
 | 
			
		||||
    attach_variable :bootstrap_port, :mach_port_t
 | 
			
		||||
 | 
			
		||||
    attach_function(:bootstrap_strerror,
 | 
			
		||||
                    [:kern_return_t],
 | 
			
		||||
                    :pointer)
 | 
			
		||||
 | 
			
		||||
    attach_function(:bootstrap_register,
 | 
			
		||||
                    [:mach_port_t, :name_t, :mach_port_t],
 | 
			
		||||
                    :kern_return_t)
 | 
			
		||||
    error_check_bootstrap :bootstrap_register
 | 
			
		||||
 | 
			
		||||
    ##################
 | 
			
		||||
    # Port functions #
 | 
			
		||||
    ##################
 | 
			
		||||
 | 
			
		||||
    attach_mach_function(:mach_port_allocate,
 | 
			
		||||
                         [:ipc_space_t,
 | 
			
		||||
                          MachPortRight,
 | 
			
		||||
                          :mach_port_name_pointer_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    
 | 
			
		||||
    attach_mach_function(:mach_port_destroy,
 | 
			
		||||
                         [:ipc_space_t,
 | 
			
		||||
                          :mach_port_name_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    
 | 
			
		||||
    attach_mach_function(:mach_port_deallocate,
 | 
			
		||||
                         [:ipc_space_t,
 | 
			
		||||
                          :mach_port_name_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    
 | 
			
		||||
    attach_mach_function(:mach_port_insert_right,
 | 
			
		||||
                         [:ipc_space_t,
 | 
			
		||||
                          :mach_port_name_t,
 | 
			
		||||
                          :mach_port_t,
 | 
			
		||||
                          MachMsgType],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
 | 
			
		||||
    ##################
 | 
			
		||||
    # Task functions #
 | 
			
		||||
    ##################
 | 
			
		||||
 | 
			
		||||
    attach_mach_function(:task_get_special_port,
 | 
			
		||||
                         [:task_t,
 | 
			
		||||
                          :int,
 | 
			
		||||
                          :mach_port_pointer_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
 | 
			
		||||
    attach_mach_function(:task_set_special_port,
 | 
			
		||||
                         [:task_t,
 | 
			
		||||
                          :int,
 | 
			
		||||
                          :mach_port_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
 | 
			
		||||
    #######################
 | 
			
		||||
    # Semaphore functions #
 | 
			
		||||
    #######################
 | 
			
		||||
 | 
			
		||||
    attach_mach_function(:semaphore_create,
 | 
			
		||||
                         [:task_t, :pointer, SyncPolicy, :int],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    attach_mach_function(:semaphore_destroy,
 | 
			
		||||
                         [:task_t, :semaphore_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
 | 
			
		||||
    attach_mach_function(:semaphore_signal,
 | 
			
		||||
                         [:semaphore_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    attach_mach_function(:semaphore_signal_all,
 | 
			
		||||
                         [:semaphore_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    attach_mach_function(:semaphore_wait,
 | 
			
		||||
                         [:semaphore_t],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
    attach_mach_function(:semaphore_timedwait,
 | 
			
		||||
                         [:semaphore_t, Timespec.val],
 | 
			
		||||
                         :kern_return_t)
 | 
			
		||||
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require 'mach/error'
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
require 'mach/functions'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  class Port
 | 
			
		||||
    include Functions
 | 
			
		||||
 | 
			
		||||
    attr_reader :ipc_space, :port
 | 
			
		||||
 | 
			
		||||
    # either initialize(port, opts) -or- initialize(opts)
 | 
			
		||||
    def initialize(opts = {}, opts2 = {})
 | 
			
		||||
      if opts.kind_of? Hash
 | 
			
		||||
        ipc_space = opts[:ipc_space] || mach_task_self
 | 
			
		||||
        right = opts[:right] || :receive
 | 
			
		||||
 | 
			
		||||
        mem = new_memory_pointer(:mach_port_right_t)
 | 
			
		||||
        mach_port_allocate(ipc_space, right, mem)
 | 
			
		||||
 | 
			
		||||
        @port = mem.get_uint(0)
 | 
			
		||||
        @ipc_space = ipc_space
 | 
			
		||||
      else
 | 
			
		||||
        @port = opts
 | 
			
		||||
        @ipc_space = opts2[:ipc_space] || mach_task_self
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def ==(other)
 | 
			
		||||
      (port == other.port) && (ipc_space == other.ipc_space)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy(opts = {})
 | 
			
		||||
      ipc_space = opts[:ipc_space] || @ipc_space
 | 
			
		||||
      mach_port_destroy(ipc_space, @port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def deallocate(opts = {})
 | 
			
		||||
      ipc_space = opts[:ipc_space] || @ipc_space
 | 
			
		||||
      mach_port_deallocate(ipc_space, @port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def insert_right(msg_type, opts = {})
 | 
			
		||||
      ipc_space = opts[:ipc_space] || @ipc_space
 | 
			
		||||
      port_name = opts[:port_name] || @port
 | 
			
		||||
      
 | 
			
		||||
      mach_port_insert_right(ipc_space, port_name, @port, msg_type)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
require 'mach/functions'
 | 
			
		||||
require 'mach/port'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  class Semaphore < Port
 | 
			
		||||
    include Functions
 | 
			
		||||
 | 
			
		||||
    # Create a new Semaphore.
 | 
			
		||||
    #
 | 
			
		||||
    # @param [Integer] value the initial value of the semaphore
 | 
			
		||||
    #
 | 
			
		||||
    # @param [Hash] opts
 | 
			
		||||
    #
 | 
			
		||||
    # @option opts [Integer] :task the Mach task that owns the
 | 
			
		||||
    # semaphore (defaults to Mach.task_self)
 | 
			
		||||
    #
 | 
			
		||||
    # @options opts [Integer] :sync_policy the sync policy for this
 | 
			
		||||
    # semaphore (defaults to SyncPolicy::FIFO)
 | 
			
		||||
    #
 | 
			
		||||
    # @return [Integer] a semaphore port name
 | 
			
		||||
    def initialize(value = 1, opts = {})
 | 
			
		||||
      task = opts[:task] || ipc_space || mach_task_self
 | 
			
		||||
      sync_policy = opts[:sync_policy] || :fifo
 | 
			
		||||
 | 
			
		||||
      mem = new_memory_pointer(:semaphore_t)
 | 
			
		||||
      semaphore_create(task, mem, sync_policy, value)
 | 
			
		||||
      super(mem.get_uint(0), :ipc_space => task)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Destroy a Semaphore.
 | 
			
		||||
    #
 | 
			
		||||
    # @param [Hash] opts
 | 
			
		||||
    #
 | 
			
		||||
    # @option opts [Integer] :task the Mach task that owns the
 | 
			
		||||
    # semaphore (defaults to the owning task)
 | 
			
		||||
    def destroy(opts = {})
 | 
			
		||||
      task = opts[:task] || ipc_space || mach_task_self
 | 
			
		||||
      semaphore_destroy(task, port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def signal
 | 
			
		||||
      semaphore_signal(port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def signal_all
 | 
			
		||||
      semaphore_signal_all(port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def wait
 | 
			
		||||
      semaphore_wait(port)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # TODO: implement
 | 
			
		||||
    def timedwait(secs)
 | 
			
		||||
      semaphore_timedwait(port, timespec)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
require 'mach/functions'
 | 
			
		||||
require 'mach/port'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  class Task < Port
 | 
			
		||||
    include Functions
 | 
			
		||||
 | 
			
		||||
    # @return [Task]
 | 
			
		||||
    def self.self
 | 
			
		||||
      new(Functions.mach_task_self)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def initialize(task)
 | 
			
		||||
      super(task)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    alias_method :task, :port
 | 
			
		||||
 | 
			
		||||
    def get_special_port(which_port)
 | 
			
		||||
      mem = FFI::MemoryPointer.new(:int)
 | 
			
		||||
      task_get_special_port(task, which_port, mem)
 | 
			
		||||
      Port.new(mem.get_int(0))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # @param [Port,Integer] newport
 | 
			
		||||
    def set_special_port(which_port, newport)
 | 
			
		||||
      p = newport.respond_to?(:port) ? newport.port : newport
 | 
			
		||||
      task_set_special_port(task, which_port, p)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def get_bootstrap_port
 | 
			
		||||
      get_special_port(:bootstrap)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def set_bootstrap_port(port)
 | 
			
		||||
      set_special_port(:bootstrap, port)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
require 'mach/port'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  describe Port do
 | 
			
		||||
    it 'creates a port' do
 | 
			
		||||
      port = Port.new
 | 
			
		||||
      port.destroy
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'raises exception with invalid args' do
 | 
			
		||||
      p = proc { Port.new(:right => 1234) }
 | 
			
		||||
      p.must_raise Error::FAILURE
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'inserts rights' do
 | 
			
		||||
      port = Port.new
 | 
			
		||||
      port.insert_right(:make_send)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
require 'mach/error'
 | 
			
		||||
require 'mach/functions'
 | 
			
		||||
require 'mach/semaphore'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  describe 'low level semaphore functions' do
 | 
			
		||||
    include Functions
 | 
			
		||||
 | 
			
		||||
    it 'raises exception with invalid args' do
 | 
			
		||||
      p = proc { semaphore_create(mach_task_self, nil, 1234, 1) }
 | 
			
		||||
      p.must_raise Error::INVALID_ARGUMENT
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Semaphore do
 | 
			
		||||
    it 'creates a semaphore' do
 | 
			
		||||
      sem = Semaphore.new
 | 
			
		||||
      sem.destroy
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'raises exception with invalid args' do
 | 
			
		||||
      p = proc { Semaphore.new(1, :sync_policy => :no_such) }
 | 
			
		||||
      p.must_raise ArgumentError # Error::INVALID_ARGUMENT
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'signals/waits in same task' do
 | 
			
		||||
      sem = Semaphore.new(0)
 | 
			
		||||
      sem.signal
 | 
			
		||||
      sem.wait
 | 
			
		||||
      sem.destroy
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
require 'mach'
 | 
			
		||||
require 'mach/port'
 | 
			
		||||
require 'mach/task'
 | 
			
		||||
 | 
			
		||||
module Mach
 | 
			
		||||
  describe Task do
 | 
			
		||||
    before :each do
 | 
			
		||||
      @task = Task.self
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'gets special ports' do
 | 
			
		||||
      bp = @task.get_special_port(:bootstrap)
 | 
			
		||||
      bp.must_equal @task.get_bootstrap_port
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'redefines bootstrap port' do
 | 
			
		||||
      bp = @task.get_bootstrap_port
 | 
			
		||||
      new_bp = Port.new
 | 
			
		||||
      bp.wont_equal(new_bp)
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        new_bp.insert_right(:make_send)
 | 
			
		||||
        @task.set_bootstrap_port(new_bp)
 | 
			
		||||
        @task.get_bootstrap_port.must_equal(new_bp)
 | 
			
		||||
      ensure
 | 
			
		||||
        @task.set_bootstrap_port(bp)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
		Reference in New Issue