Refactor Mach FFI wrapper; get unit tests working again.

This commit is contained in:
Patrick Mahoney 2012-02-08 21:30:18 -06:00
parent d373ed5996
commit da42ac4875
5 changed files with 173 additions and 141 deletions

View File

@ -1,12 +1,109 @@
require 'mach/port' require 'ffi'
require 'mach/semaphore'
require 'mach/task' require 'mach/types'
require 'mach/functions'
module Mach module Mach
extend Mach::Types
class MsgHeader < FFI::Struct
layout(:bits, :mach_msg_bits_t,
:size, :mach_msg_size_t,
:remote_port, :mach_port_t,
:local_port, :mach_port_t,
:reserved, :mach_msg_size_t,
:id, :mach_msg_id_t)
end
class MsgBody < FFI::Struct
layout(:descriptor_count, :mach_msg_size_t)
end
class MsgBase < FFI::Struct
layout(:header, MsgHeader,
:body, MsgBody)
end
class MsgTrailer < FFI::Struct
layout(:type, :mach_msg_trailer_type_t,
:size, :mach_msg_trailer_size_t)
end
class MsgPortDescriptor < FFI::Struct
layout(:name, :mach_port_t,
:pad1, :mach_msg_size_t, # FIXME: leave oout on __LP64__
:pad2, :uint16, # :uint
:disposition, :uint8, # :mach_msg_type_name_t
:type, :uint8) # :mach_msg_descriptor_type_t
end
SyncPolicy = enum( :fifo, 0x0,
:fixed_priority, 0x1,
:reversed, 0x2,
:order_mask, 0x3,
:lifo, 0x0 | 0x2, # um...
:max, 0x7 )
PortRight = enum( :send, 0,
:receive,
:send_once,
:port_set,
:dead_name,
:labelh,
:number )
# port type macro
def self.pt(*syms)
acc = 0
syms.each do |sym|
acc |= (1 << (PortRight[sym] + 16))
end
acc
end
PORT_NULL = 0
MSG_TIMEOUT_NONE = 0
PortType =
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))
MsgType =
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
SpecialPort =
enum( :kernel, 1,
:host,
:name,
:bootstrap )
KERN_SUCCESS = 0
# @return [Port] the original bootstrap port; different from that # @return [Port] the original bootstrap port; different from that
# affected by {get,set}_special_port # affected by {get,set}_special_port
def self.bootstrap_port def self.bootstrap_port
@bootstrap_port ||= Mach::Port.new(:port => Mach::Functions::bootstrap_port) @bootstrap_port ||= Mach::Port.new(:port => Mach::Functions::bootstrap_port)
end end
end end
require 'mach/port'
require 'mach/semaphore'
require 'mach/task'
require 'mach/functions'

View File

@ -1,5 +1,6 @@
require 'ffi' require 'ffi'
require 'mach/types'
require 'mach/time_spec' require 'mach/time_spec'
module Mach module Mach
@ -7,134 +8,10 @@ module Mach
# specific). # specific).
module Functions module Functions
extend FFI::Library extend FFI::Library
extend Types
ffi_lib 'c' ffi_lib 'c'
typedef :__darwin_mach_port_t, :mach_port_t
typedef :__darwin_natural_t, :natural_t
typedef :int, :integer_t
typedef :int, :kern_return_t # true for 64 bit??
typedef :int, :mach_error_t
typedef :int, :sync_policy_t # SyncPolicy
typedef :int, :clock_id_t
typedef :int, :clock_res_t
typedef :string, :name_t
typedef :mach_port_t, :host_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 :uint, :mach_msg_bits_t
typedef :uint, :mach_msg_trailer_type_t
typedef :uint, :mach_msg_trailer_size_t
typedef :uint, :mach_msg_descriptor_type_t
typedef :natural_t, :mach_msg_timeout_t
typedef :natural_t, :mach_msg_size_t
typedef :integer_t, :mach_msg_id_t
typedef :integer_t, :mach_msg_options_t
typedef :integer_t, :mach_msg_option_t
class MsgHeader < FFI::Struct
layout(:bits, :mach_msg_bits_t,
:size, :mach_msg_size_t,
:remote_port, :mach_port_t,
:local_port, :mach_port_t,
:reserved, :mach_msg_size_t,
:id, :mach_msg_id_t)
end
class MsgBody < FFI::Struct
layout(:descriptor_count, :mach_msg_size_t)
end
class MsgBase < FFI::Struct
layout(:header, MsgHeader,
:body, MsgBody)
end
class MsgTrailer < FFI::Struct
layout(:type, :mach_msg_trailer_type_t,
:size, :mach_msg_trailer_size_t)
end
class MsgPortDescriptor < FFI::Struct
layout(:name, :mach_port_t,
:pad1, :mach_msg_size_t, # FIXME: leave oout on __LP64__
:pad2, :uint16, # :uint
:disposition, :uint8, # :mach_msg_type_name_t
:type, :uint8) # :mach_msg_descriptor_type_t
end
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
MACH_PORT_NULL = 0
MACH_MSG_TIMEOUT_NONE = 0
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 )
KERN_SUCCESS = 0
# Replace methods in +syms+ with error checking wrappers that # Replace methods in +syms+ with error checking wrappers that
# invoke the original method and raise a {SystemCallError}. # invoke the original method and raise a {SystemCallError}.
# #
@ -232,7 +109,7 @@ module Mach
attach_mach_function(:mach_port_allocate, attach_mach_function(:mach_port_allocate,
[:ipc_space_t, [:ipc_space_t,
MachPortRight, PortRight,
:mach_port_name_pointer_t], :mach_port_name_pointer_t],
:kern_return_t) :kern_return_t)
@ -250,7 +127,7 @@ module Mach
[:ipc_space_t, [:ipc_space_t,
:mach_port_name_t, :mach_port_name_t,
:mach_port_t, :mach_port_t,
MachMsgType], MsgType],
:kern_return_t) :kern_return_t)
################## ##################
@ -271,13 +148,13 @@ module Mach
attach_mach_function(:task_get_special_port, attach_mach_function(:task_get_special_port,
[:task_t, [:task_t,
MachSpecialPort, SpecialPort,
:mach_port_pointer_t], :mach_port_pointer_t],
:kern_return_t) :kern_return_t)
attach_mach_function(:task_set_special_port, attach_mach_function(:task_set_special_port,
[:task_t, [:task_t,
MachSpecialPort, SpecialPort,
:mach_port_t], :mach_port_t],
:kern_return_t) :kern_return_t)

View File

@ -76,7 +76,7 @@ module Mach
# Insert +right+ into another ipc space. The current task must # Insert +right+ into another ipc space. The current task must
# have sufficient rights to insert the requested right. # have sufficient rights to insert the requested right.
# #
# @param [MachMsgType] right # @param [MsgType] right
# #
# @param [Hash] opts # @param [Hash] opts
# #
@ -100,9 +100,9 @@ module Mach
msg[:header].tap do |h| msg[:header].tap do |h|
h[:remote_port] = remote_port.to_i h[:remote_port] = remote_port.to_i
h[:local_port] = MACH_PORT_NULL h[:local_port] = PORT_NULL
h[:bits] = h[:bits] =
(MachMsgType[right] | (0 << 8)) | 0x80000000 # MACH_MSGH_BITS_COMPLEX (MsgType[right] | (0 << 8)) | 0x80000000 # MACH_MSGH_BITS_COMPLEX
h[:size] = 40 # msg.size h[:size] = 40 # msg.size
end end
@ -110,8 +110,8 @@ module Mach
msg[:port].tap do |p| msg[:port].tap do |p|
p[:name] = port p[:name] = port
p[:disposition] = MachMsgType[right] p[:disposition] = MsgType[right]
p[:type] = 0 # MACH_MSG_PORT_DESCRIPTOR; p[:type] = 0 # MSG_PORT_DESCRIPTOR;
end end
mach_msg_send msg mach_msg_send msg
@ -130,12 +130,12 @@ module Mach
msg = ReceiveRightMsg.new msg = ReceiveRightMsg.new
mach_msg(msg, mach_msg(msg,
2, # MACH_RCV_MSG, 2, # RCV_MSG,
0, 0,
msg.size, msg.size,
port, port,
MACH_MSG_TIMEOUT_NONE, MSG_TIMEOUT_NONE,
MACH_PORT_NULL) PORT_NULL)
self.class.new :port => msg[:port][:name] self.class.new :port => msg[:port][:name]
end end

54
lib/mach/types.rb Normal file
View File

@ -0,0 +1,54 @@
require 'ffi'
module Mach
module Types
extend FFI::Library
typedef :__darwin_mach_port_t, :mach_port_t
typedef :__darwin_natural_t, :natural_t
typedef :int, :integer_t
typedef :int, :kern_return_t # true for 64 bit??
typedef :int, :mach_error_t
typedef :int, :sync_policy_t # SyncPolicy
typedef :int, :clock_id_t
typedef :int, :clock_res_t
typedef :string, :name_t
typedef :mach_port_t, :host_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 :uint, :mach_msg_bits_t
typedef :uint, :mach_msg_trailer_type_t
typedef :uint, :mach_msg_trailer_size_t
typedef :uint, :mach_msg_descriptor_type_t
typedef :natural_t, :mach_msg_timeout_t
typedef :natural_t, :mach_msg_size_t
typedef :integer_t, :mach_msg_id_t
typedef :integer_t, :mach_msg_options_t
typedef :integer_t, :mach_msg_option_t
def self.typedefs
@ffi_typedefs
end
def find_type(t)
Mach::Types.find_type(t) || super
end
def enum(*args)
Mach::Types.enum(*args)
end
end
end

View File

@ -46,6 +46,10 @@ end
module Kernel module Kernel
# Override to call Process::fork. # Override to call Process::fork.
def self.fork(*args, &block)
Process.fork(*args, &block)
end
def fork(*args, &block) def fork(*args, &block)
Process.fork(*args, &block) Process.fork(*args, &block)
end end