Skip to content

Commit

Permalink
Fixed FFI::MemoryPointer#autorelease= and added #autorelease?
Browse files Browse the repository at this point in the history
autorelease= false was previously a noop, leaving the finalizer in place.
Fixes #3260
  • Loading branch information
jemc committed Dec 30, 2014
1 parent eec1ad3 commit 010342a
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
7 changes: 7 additions & 0 deletions kernel/platform/pointer.rb
Expand Up @@ -379,6 +379,13 @@ def autorelease=(val)
raise PrimitiveFailure, "FFI::MemoryPointer#autorelease= primitive failed"
end

##
# Returns true if autorelease is enabled, otherwise false.
def autorelease?
Rubinius.primitive :pointer_autorelease_p
raise PrimitiveFailure, "FFI::MemoryPointer#pointer_autorelease_p primitive failed"
end

end

class DynamicLibrary::Symbol < Pointer
Expand Down
30 changes: 28 additions & 2 deletions spec/core/ffi/memorypointer/autorelease_spec.rb
@@ -1,6 +1,32 @@
require File.expand_path('../../../../spec_helper', __FILE__)
require 'rubinius/ffi'

describe "FFI::MemoryPointer#autorelease=" do
it "needs to be reviewed for spec completeness"
describe "FFI::MemoryPointer#autorelease" do
before :all do
@libc = Module.new
@libc.extend Rubinius::FFI::Library
@libc.ffi_lib Rubinius::FFI::Library::LIBC
@libc.attach_function :free, [:pointer], :void
end

it "starts as enabled" do
ptr = Rubinius::FFI::MemoryPointer.new :int
ptr.autorelease?.should == true
end

it "can be disabled (and the pointer freed explicitly)" do
ptr = Rubinius::FFI::MemoryPointer.new :int
ptr.autorelease = false
ptr.autorelease?.should == false
@libc.free ptr
end

it "can be disabled and reenabled" do
ptr = Rubinius::FFI::MemoryPointer.new :int
ptr.autorelease?.should == true
ptr.autorelease = false
ptr.autorelease?.should == false
ptr.autorelease = true
ptr.autorelease?.should == true
end
end
19 changes: 15 additions & 4 deletions vm/builtin/ffi_pointer.cpp
Expand Up @@ -106,13 +106,24 @@ namespace rubinius {
return Pointer::create(state, (char*)pointer + amount->to_native());
}

Object* Pointer::autorelease_p(STATE) {
return set_finalizer ? cTrue : cFalse;
}

Object* Pointer::set_autorelease(STATE, Object* val) {
autorelease = val->true_p() ? true : false;

if(autorelease && !set_finalizer) {
state->memory()->needs_finalization(this,
(FinalizerFunction)&Pointer::finalize);
set_finalizer = true;
if(autorelease) {
if(!set_finalizer) {
state->memory()->needs_finalization(this,
(FinalizerFunction)&Pointer::finalize);
set_finalizer = true;
}
} else {
if(set_finalizer) {
state->memory()->set_ruby_finalizer(this, cNil);
set_finalizer = false;
}
}

return val;
Expand Down
3 changes: 3 additions & 0 deletions vm/builtin/ffi_pointer.hpp
Expand Up @@ -37,6 +37,9 @@ namespace rubinius {
// Rubinius.primitive :pointer_free
Object* free(STATE);

// Rubinius.primitive :pointer_autorelease_p
Object* autorelease_p(STATE);

// Rubinius.primitive :pointer_set_autorelease
Object* set_autorelease(STATE, Object* val);

Expand Down

0 comments on commit 010342a

Please sign in to comment.