2

I'm currently trying to bridge Numo::NArray and FFI, so that an FFI Pointer can access the raw data in a Numo::NArray without having to copy data through String like I do now (thus causing GC churn and a wasted extra copy).

There is a C function exposed by Numo::NArray called nary_get_pointer_for_read_write, and this is used already by Numo::FFTW. However, the parameter to this function is CRuby's internal VALUE type, and I haven't found a way to pass that VALUE using FFI.

Here's a non-working rough draft of what I'd like to try. If this isn't possible, my next step might be writing another C extension gem to do the bridging, and after that maybe trying to PR a function to get an FFI pointer into the numo-narray project.

require 'numo/narray'
require 'ffi'

module NArrayFFI
  ffi_lib FFI::CURRENT_PROCESS
  attach_function :nary_get_pointer_for_read, [:RAW_RUBY_VALUE_IF_FFI_CAN_DO_THIS], :pointer
  attach_function :nary_get_pointer_for_write, [:RAW_RUBY_VALUE_IF_FFI_CAN_DO_THIS], :pointer
  attach_function :nary_get_pointer_for_read_write, [:RAW_RUBY_VALUE_IF_FFI_CAN_DO_THIS], :pointer
end

data = Numo::SFloat[1,2,3,4,5]
data_ptr = NArrayFFI.nary_get_pointer_for_read_write(data)
SomeOtherFFI.function_that_takes_pointer(data_ptr)

So, is it possible to pass the raw VALUE of a Ruby value to a function attached using FFI?


Here are references I've checked so far, that didn't have an answer, but might be useful to others with similar questions:

1 Answer 1

0

As VALUE is just a uintptr, you can use :pointer as a parameter type. To get its value you can use a bit of a hack that Fiddle.dlwrap on MRI simply returns its argument, converted to number. But you need to be aware of GC when doing that, better define your own type with to_native converter. You need to remember not only to prevent your object from being garbage collected, but also from being moved (might not be a problem if its defined in a native extension and isn't marked as movable), for this fiddle has Fiddle::Pinned, not sure about ffi.

And this only applies to parameters, you cannot safely convert pointer to Ruby value. Fiddle.dlunwrap "works", but between your function returns and dlunwrap calls NUM2PTR, your VALUE is no longer on the stack, neither marked as accessible by other means, and thus can be GCed. Not sure about ObjectSpace._id2ref, but it's argument is different and since Ruby 2.7.0 ids are no longer simply VALUEs divided by 2.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.