From: "Kent S." Date: 2004-03-12T02:54:44+09:00 Subject: Re: A few questions about Ruby/DL Josh Huber wrote: > I've had quite good luck using Ruby/DL to wrap a shared library, but > the lack of documentation in english is possibly preventing me from > using it in the best way. > > I have a few questions: > > 1. Memory management -- how do I free memory? When do I need to free > memory? I can't seem to find any free's in the examples, but > there are references to setting a freeing function in the PtrData > class documentation (ext/dl/doc/dl.txt) You don't have to free memory yourself. With Ruby/DL you are dealing with DL::PtrData objects that basically represent a memory pointer. When there are no references to a PtrData object left, GC will collect this object and invoke its free routine, which takes care of the allocated memory. Take a look at PtrData#free attribute. BTW, if you know that your library function returns a pointer to some kind of static buffer and you don't want a PtrData object release this buffer, just set its free attribute to nil. > > 2. What's the best way to handle pointer outputs which allocate > memory? I've done things like the following, but I'm not sure > that it's the best way: > > # say the C interface has a prototype like > > # int get_data(char **data, int *len); > > # on success, memory is allocated for a string and the pointer is > # assigned to the data parameter. The length of the string is > # written into the len parameter. > > data = DL::malloc(DL::sizeof("P")) > len = DL::malloc(DL::sizeof("L")) > len.struct!("L", "val") > > ret = LIB.get_data(data, len) > > if ret == LIB::STATUS_OK > puts "got a string of length #{len[:val]}: #{data.ptr}" > else > puts "failed to get data: #{LIB::strerror(ret)}" > end I would do it like that: $ cat test.c #include int get_data(char** data, int* len) { int i; *len = 30; *data = (char*)malloc(sizeof(char)*(*len)); sprintf(*data, "string of size %d", *len); return (*len); } $ cc -dynamic -bundle -o test.bundle test.c $ irb irb(main):001:0> require 'dl/import' => true irb(main):002:0> module TestDLL irb(main):003:1> extend DL::Importable irb(main):004:1> dlload 'test.bundle' irb(main):005:1> extern "int get_data(char**, int*)" irb(main):006:1> end => # irb(main):007:0> data = DL::PtrData.new(0) => # irb(main):008:0> data.free = DL::FREE => # irb(main):009:0> len = DL::PtrData.malloc(DL.sizeof('I')) => # irb(main):010:0> len.struct!('I', 'val') => nil irb(main):011:0> TestDLL.get_data(data.ref, len) => 30 irb(main):012:0> len['val'] => 30 irb(main):013:0> data.to_s => "string of size 30" irb(main):014:0> /kent