Subject: Re: [ruby-ffi] Passing a struct by value, and typedef |
From: Maurizio De Santis |
Date: 3/10/13 11:50 AM |
To: ruby-ffi@googlegroups.com |
:buffer_in, and :buffer_out are optimization hints for VMs when they need to copy data from VM heap memory to native memory::buffer_in means "allocate some temporary native memory, copy the contents of this object to it, then pass the temporary memory address to the function":buffer_out means "allocate some temporary native memory, pass that address to the function, then afterwards, copy the contents of the temporary memory area back to the VM heap object":pointer and :buffer_inout are analogous and mean "do both of the above" - i.e. copies both in to and out of the temporary memory area.If you're using a MemoryPointer as your memory (as Struct does), then it is already native, so it doesn't matter, so you can just use :pointer.The original rationale behind the :buffer_in and :buffer_out directives was that allocating VM heap objects is really cheap, and most VMs have a very hard time managing native memory allocations. So from an implementation point of view, it was better to bias towards VM heap allocations and copy data in/out of temporary native memory. Thats where FFI::Buffer came from - it was VM heap memory that was always copied to/from native memory when passed as a parameter.In practice, people found it difficult and confusing to understand, so I just made native allocation management work as best it could in JRuby-1.7.tl;dr - just use :pointer - it will work just fine, at an occasional minor performance penalty.--On Monday, 4 March 2013 11:45:38 UTC+10, Postmodern wrote:You want :pointer in this case. I believe :buffer_out is a meant as a hint to FFI that data will be written back into an Array of chars/ints.
On 03/03/2013 05:41 PM, Maurizio De Santis wrote:
I think I can substitute :pointer with :buffer_out , am I right?Another question: glibtop_get_cpu takes a struct as parameter, and fills it with informations about cpu.I declared it as
attach_function :glibtop_get_cpu, [:pointer], :void
--
Maurizio De Santis
2013/3/4 Maurizio De Santis <desantis...@gmail.com>
Thank you a lot, your suggestions are precious.
--
Maurizio De Santis
2013/3/3 postmodern <postmod...@gmail.com>
You can simplify that code to just:
This will allocate memory for a GlibtopCpu struct, pass the pointer to the memory to glibtop_get_cpu and access to the struct field within the memory. Once you are done with the "a" variable, Ruby will just GC it and FFI will free the underlying memory.a = LibGtop::GlibtopCpu.new LibGtop.glibtop_get_cpu(a) p a[:frequency]
On 03/02/2013 07:54 PM, Maurizio De Santis wrote:
Thank you. Now, the code runs without errors:Another question: I initialized the pointer with clear = true, because the struct pointed by the pointer gets filled by glibtop_get_cpu, and then must be managed by Ruby, since glibtop_get_cpu just fills the struct. Am I wrong?
require 'ffi'
module LibGtop
extend FFI::Library
ffi_lib 'libgtop-2.0'
typedef :uint64, :guint64
attach_function :glibtop_get_cpu, [:pointer], :void
class GlibtopCpu < FFI::Struct
layout :flags, :guint64,
:total, :guint64,
:user, :guint64,
:nice, :guint64,
:sys, :guint64,
:idle, :guint64,
:iowait, :guint64,
:irq, :guint64,
:softirq, :guint64,
:frequency, :guint64,
:xcpu_total, [:guint64, 32],
:xcpu_user, [:guint64, 32],
:xcpu_nice, [:guint64, 32],
:xcpu_sys, [:guint64, 32],
:xcpu_idle, [:guint64, 32],
:xcpu_iowait, [:guint64, 32],
:xcpu_irq, [:guint64, 32],
:xcpu_softirq, [:guint64, 32],
:xcpu_flags, :guint64
end
end
# taken from https://github.com/ffi/ffi/wiki/Structs
pointer = FFI::MemoryPointer.new :uint64, LibGtop::GlibtopCpu.size, true
a = LibGtop::GlibtopCpu.new pointer
LibGtop.glibtop_get_cpu(a)
p a[:frequency]
--
Maurizio De Santis
2013/3/3 postmodern <postmod...@gmail.com>
You need to find out guint64's underlying type, and create the typedef in Ruby:
module LibGtop extend FFI::Library typedef :uint64, :guint64 end
On 03/02/2013 06:06 PM, Maurizio De Santis wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-ffi+u...@googlegroups.com.You received this message because you are subscribed to the Google Groups "ruby-ffi" group.I am writing a libgtop2 wrapper using ffi in order to learn how to use ffi; I am new to ffi, so I have a lot of doubts.
libgtop2 lets get system and processes informations (cpu usage, memory usage, ...).
Here some informations about glibtop_get_cpu:
Library function `glibtop_get_cpu':
void glibtop_get_cpu (glibtop_cpu *buf);
void glibtop_get_cpu_l (glibtop *server, glibtop_cpu *buf);
Declaration of `glibtop_cpu' in `<glibtop/cpu.h>':
typedef struct _glibtop_cpu glibtop_cpu;
struct _glibtop_cpu
{
guint64 flags,
total,
user,
nice,
sys,
idle,
iowait,
irq,
softirq,
frequency,
xcpu_total [GLIBTOP_NCPU],
xcpu_user [GLIBTOP_NCPU],
xcpu_nice [GLIBTOP_NCPU],
xcpu_sys [GLIBTOP_NCPU],
xcpu_idle [GLIBTOP_NCPU],
xcpu_iowait [GLIBTOP_NCPU],
xcpu_irq [GLIBTOP_NCPU],
xcpu_softirq [GLIBTOP_NCPU],
xcpu_flags;
};
...
Here is what I wrote:
require 'ffi'
class GlibtopCpu < FFI::Struct
layout :flags, :guint64,
:total, :guint64,
:user, :guint64,
:nice, :guint64,
:sys, :guint64,
:idle, :guint64,
:iowait, :guint64,
:irq, :guint64,
:softirq, :guint64,
:frequency, :guint64,
:xcpu_total, :guint64,
:xcpu_user, :guint64,
:xcpu_nice, :guint64,
:xcpu_sys, :guint64,
:xcpu_idle, :guint64,
:xcpu_iowait, :guint64,
:xcpu_irq, :guint64,
:xcpu_softirq, :guint64,
:xcpu_flags, :guint64
end
module LibGtop
extend FFI::Library
ffi_lib 'libgtop-2.0'
attach_function :glibtop_get_cpu, [:pointer], :void
end
# taken from https://github.com/ffi/ffi/wiki/Structs
pointer = FFI::MemoryPointer.new :byte, GlibtopCpu.size, false
a = GlibtopCpu.new pointer
p LibGtop.glibtop_get_cpu(a)
Executing this gives (unsurprisingly) an error:
$ ruby lib/lib_gtop.rb
/home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/ffi-1.4.0/lib/ffi/types.rb:57:in `find_type': unable to resolve type 'guint64' (TypeError)
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/ffi-1.4.0/lib/ffi/struct.rb:316:in `find_type'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/ffi-1.4.0/lib/ffi/struct.rb:309:in `find_field_type'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/ffi-1.4.0/lib/ffi/struct.rb:351:in `array_layout'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/ffi-1.4.0/lib/ffi/struct.rb:261:in `layout'
from lib/lib_gtop.rb:4:in `<class:GlibtopCpu>'
from lib/lib_gtop.rb:3:in `<main>'
It doesn't find the guint64 type; how should I declare it?
Also: xcpu_total, xcpu_user are arrays... how should I declare them?
Finally... if someone could give me an explanation and an example of how to implement the bind to glibtop_get_cpu, I would appreciate it very much :) --
---
-- Blog: http://postmodern.github.com/ GitHub: https://github.com/postmodern Twitter: @postmodern_mod3 PGP: 0xB9515E77
--To unsubscribe from this group and stop receiving emails from it, send an email to ruby-ffi+u...@googlegroups.com.
---
You received this message because you are subscribed to the Google Groups "ruby-ffi" group.
-- Blog: http://postmodern.github.com/ GitHub: https://github.com/postmodern Twitter: @postmodern_mod3 PGP: 0xB9515E77
--To unsubscribe from this group and stop receiving emails from it, send an email to ruby-ffi+u...@googlegroups.com.
---
You received this message because you are subscribed to the Google Groups "ruby-ffi" group.
-- Blog: http://postmodern.github.com/ GitHub: https://github.com/postmodern Twitter: @postmodern_mod3 PGP: 0xB9515E77
---
You received this message because you are subscribed to a topic in the Google Groups "ruby-ffi" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ruby-ffi/sG-TsAHcWiM/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to ruby-ffi+unsubscribe@googlegroups.com.