Subject: Re: [ruby-ffi] Passing a struct by value, and typedef |
From: Wayne Meissner |
Date: 3/11/13 3:20 AM |
To: ruby-ffi@googlegroups.com |
Thank you, the porting is going well; if you want you can see the progress at https://github.com/Now I have some troubles: I need to use g_free from glib, so I tried to wrap it:ProGNOMmers/gtop .
require 'gtop'
module GTop
module GLib
extend FFI::Library
ffi_lib 'libglib2.0'
typedef :pointer, :gpointer
attach_function :g_free, [:gpointer], :void
end
end
On my pc libglib2.0.so is located inside /usr/lib/x86_64-linux-gnu/ , which should be found since it is inside the ld paths, which on my machine are
# Multiarch support
/lib/i386-linux-gnu
/usr/lib/i386-linux-gnu
/lib/i686-linux-gnu
/usr/lib/i686-linux-gnu
# libc default configuration
/usr/local/lib
/usr/lib/nvidia-settings
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/mesabut I get a LoadError:
Could not open library 'libglib2.0': libglib2.0: cannot open shared object file: No such file or directory.
Could not open library 'libglib2.0.so': libglib2.0.so: cannot open shared object file: No such file or directory
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/ffi-1.4.0/lib/ffi/ library.rb:123:in `block in ffi_lib'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/ffi-1.4.0/lib/ffi/ library.rb:90:in `map'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/ffi-1.4.0/lib/ffi/ library.rb:90:in `ffi_lib'
/home/user/github/me/gtop/lib/gtop/glib.rb:6:in `<module:GLib>'
/home/user/github/me/gtop/lib/gtop/glib.rb:4:in `<module:GTop>'
/home/user/github/me/gtop/lib/gtop/glib.rb:3:in `<top (required)>'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/site_ruby/2.0. 0/rubygems/core_ext/kernel_ require.rb:45:in `require'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/site_ruby/2.0. 0/rubygems/core_ext/kernel_ require.rb:45:in `require'
/home/user/github/me/gtop/lib/gtop.rb:7:in `<module:GTop>'
/home/user/github/me/gtop/lib/gtop.rb:3:in `<top (required)>'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/site_ruby/2.0. 0/rubygems/core_ext/kernel_ require.rb:45:in `require'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/site_ruby/2.0. 0/rubygems/core_ext/kernel_ require.rb:45:in `require'
/home/user/github/me/gtop/Rakefile:4:in `block in <top (required)>'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:228:in `call'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:228:in `block in execute'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:223:in `each'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:223:in `execute'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:166:in `block in invoke_with_call_chain'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/2.0.0/monitor. rb:211:in `mon_synchronize'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:159:in `invoke_with_call_chain'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ task.rb:152:in `invoke'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:143:in `invoke_task'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:101:in `block (2 levels) in top_level'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:101:in `each'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:101:in `block in top_level'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:110:in `run_with_threads'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:95:in `top_level'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:73:in `block in run'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:160:in `standard_exception_handling'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/lib/rake/ application.rb:70:in `run'
/home/user/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/ gems/rake-10.0.3/bin/rake:33: in `<top (required)>'
/home/user/.rbenv/versions/2.0.0-p0/bin/rake:23:in `load'
/home/user/.rbenv/versions/2.0.0-p0/bin/rake:23:in `<main>'
I tried to set LD_LIBRARY_PATH too, but without success.Oh, and I have another doubt: gpointer is the return value of `glibtop_get_proclist', and can be either `NULL' on error or a `unsigned *' list of pids.
I defined it as :pointer, it is correct? could the NULL value give problems? should I manage it?--
Maurizio De Santis2013/3/5 Wayne Meissner <wmei...@gmail.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.comYou 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/g ems/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/g ems/ffi-1.4.0/lib/ffi/struct.r b:316:in `find_type'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/g ems/ffi-1.4.0/lib/ffi/struct.r b:309:in `find_field_type'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/g ems/ffi-1.4.0/lib/ffi/struct.r b:351:in `array_layout'
from /home/izietto/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/g ems/ffi-1.4.0/lib/ffi/struct.r b: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+u...@googlegroups.com .