Class: Hakuban::FFIObject

Inherits:
Object
  • Object
show all
Defined in:
lib/hakuban/ffi-object.rb

Defined Under Namespace

Classes: PointerAlreadyDropped

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFFIObject

Returns a new instance of FFIObject.



10
11
12
# File 'lib/hakuban/ffi-object.rb', line 10

def initialize
  @pointer_mutex = Mutex.new
end

Class Method Details

.from_ffi_pointer(cls, pointer) ⇒ Object



20
21
22
# File 'lib/hakuban/ffi-object.rb', line 20

def self.from_ffi_pointer(cls, pointer)
  cls.allocate.tap { |new_instance| new_instance.initialize_from_ffi_pointer(pointer) }
end

.generate_finalizer(symbol, pointer_address) ⇒ Object



95
96
97
98
99
# File 'lib/hakuban/ffi-object.rb', line 95

def self.generate_finalizer(symbol, pointer_address)
  proc { |_|
    FFI::method(symbol).call(::FFI::Pointer.new(pointer_address)) 
  }
end

.with_pointers(objects, &original_block) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/hakuban/ffi-object.rb', line 61

def self.with_pointers(objects,&original_block)
  do_locked = proc { |original_block, remaining_objects, pointers|
    if remaining_objects.size == 0
      original_block.call(pointers)
    else
      object, i = remaining_objects.shift
      object.with_pointer { |pointer|
        pointers[i] = pointer
        do_locked.call(original_block, remaining_objects, pointers)
      }
    end
  }
  do_locked.call(original_block, objects.each.with_index.sort_by { |object, i| object.instance_variable_get(:@pointer) || -i }, Array.new(objects.size))
end

Instance Method Details

#do_and_drop_or_return(&block) ⇒ Object

this should always be called with interrupts disabled, in the same section where pointer creation occurs



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/hakuban/ffi-object.rb', line 103

def do_and_drop_or_return(&block)
  if block
    begin
      Thread.handle_interrupt(Object => :immediate) {
        yield self
      }
    ensure
      self.drop
    end
  else
    self
  end
end

#dropObject



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/hakuban/ffi-object.rb', line 77

def drop
  @pointer_mutex.synchronize {
    Thread.handle_interrupt(Object => :never) {
      if !!@pointer
        ObjectSpace.undefine_finalizer(self)
        FFI::method(@drop_fn).call(::FFI::Pointer.new(@pointer))
        @pointer = nil
      end
    }
  }
end

#dropped?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/hakuban/ffi-object.rb', line 90

def dropped?
  !@pointer
end

#initialize_copy(original) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/hakuban/ffi-object.rb', line 30

def initialize_copy(original)
  Thread.handle_interrupt(Object => :never) {
    if @clone_fn.nil?
      @pointer_mutex.synchronize {
        raise PointerAlreadyDropped  if original.instance_variable_get(:@pointer).nil?
        original.instance_variable_set(:@pointer, nil)
        ObjectSpace.undefine_finalizer(original)
      }
    else
      original.with_pointer { |pointer|
        @pointer = FFI::method(@clone_fn).call(::FFI::Pointer.new(pointer)).address 
      }
    end
    @pointer_mutex = Mutex.new
    ObjectSpace.undefine_finalizer(self)
    ObjectSpace.define_finalizer(self, FFIObject::generate_finalizer(@drop_fn, @pointer))
  }
end

#inspectObject



117
118
119
# File 'lib/hakuban/ffi-object.rb', line 117

def inspect
  "#<#{self.class.name} #{self.dropped? ? "DROPPED" : "%016X"%@pointer}>"
end

#with_pointerObject



50
51
52
53
54
55
56
57
58
# File 'lib/hakuban/ffi-object.rb', line 50

def with_pointer
  @pointer_mutex.synchronize {
    if @pointer
      yield ::FFI::Pointer.new(@pointer)
    else
      raise PointerAlreadyDropped
    end
  }
end