summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2023-05-05 23:56:47 +0200
committerLars Kanis <lars@greiz-reinsdorf.de>2023-05-07 21:12:42 +0200
commitfe556f176d8239887fb583db2f3bb78f92a8cec2 (patch)
tree9a7eb9ed2d872ab6328a32e0a8c3f88c69bbd628
parent23e88be86d5031649c4df71f75b17f33ab0a4934 (diff)
downloadffi-fe556f176d8239887fb583db2f3bb78f92a8cec2.tar.gz
Freeze immutable objects and add explicit make_shareable to make library definitions Ractor usable
Freeze objects which are immutable from the start are now freezed. This allows these objects to be used by Ractor without make_shareable. This partially reverts commit 4fc6a8c5ec8a9a720330946af9d1103015c62942 in such a way, that functions are stored in a module variable @ffi_functions. Enums are implemented per FFI::Library not per attached function. To make them shareable they would have to be copied and freezed per function. This would increase memory footprint for the sake of Ractor support. IMHO it's better to mark the module explicit as finished by .freeze to allow its use in a Ractor. This also enables querying the enum definitions from a Ractor. Using a Hash instead of per-function variables allow to use foo! and bar? methods as wished in #971. Fixes #971
-rw-r--r--ext/ffi_c/DynamicLibrary.c7
-rw-r--r--ext/ffi_c/Function.c12
-rw-r--r--ext/ffi_c/FunctionInfo.c2
-rw-r--r--ext/ffi_c/MappedType.c2
-rw-r--r--ext/ffi_c/StructLayout.c7
-rw-r--r--ext/ffi_c/Type.c4
-rw-r--r--ext/ffi_c/Variadic.c5
-rw-r--r--ext/ffi_c/rbffi.h2
-rw-r--r--lib/ffi/library.rb36
-rw-r--r--lib/ffi/struct.rb2
-rw-r--r--lib/ffi/struct_layout.rb2
-rw-r--r--lib/ffi/struct_layout_builder.rb4
-rw-r--r--lib/ffi/variadic.rb7
-rw-r--r--spec/ffi/dynamic_library_spec.rb6
-rw-r--r--spec/ffi/enum_spec.rb24
-rw-r--r--spec/ffi/function_spec.rb2
-rw-r--r--spec/ffi/library_spec.rb57
-rw-r--r--spec/ffi/struct_by_ref_spec.rb2
-rw-r--r--spec/ffi/struct_spec.rb16
-rw-r--r--spec/ffi/type_spec.rb35
-rw-r--r--spec/ffi/variadic_spec.rb2
21 files changed, 175 insertions, 61 deletions
diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c
index 9abafc7..1d83940 100644
--- a/ext/ffi_c/DynamicLibrary.c
+++ b/ext/ffi_c/DynamicLibrary.c
@@ -161,7 +161,9 @@ library_initialize(VALUE self, VALUE libname, VALUE libflags)
library->handle = RTLD_DEFAULT;
}
#endif
- rb_iv_set(self, "@name", libname != Qnil ? libname : rb_str_new2("[current process]"));
+ rb_iv_set(self, "@name", libname != Qnil ? rb_str_new_frozen(libname) : rb_str_new2("[current process]"));
+
+ rb_obj_freeze(self);
return self;
}
@@ -266,8 +268,9 @@ symbol_new(VALUE library, void* address, VALUE name)
sym->base.memory.typeSize = 1;
sym->base.memory.flags = MEM_RD | MEM_WR;
RB_OBJ_WRITE(obj, &sym->base.rbParent, library);
- RB_OBJ_WRITE(obj, &sym->name, name);
+ RB_OBJ_WRITE(obj, &sym->name, rb_str_new_frozen(name));
+ rb_obj_freeze(obj);
return obj;
}
diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c
index 9da6b37..d0b65fb 100644
--- a/ext/ffi_c/Function.c
+++ b/ext/ffi_c/Function.c
@@ -492,7 +492,7 @@ static VALUE
function_attach(VALUE self, VALUE module, VALUE name)
{
Function* fn;
- char var[1024];
+ VALUE funcs;
StringValue(name);
TypedData_Get_Struct(self, Function, &function_data_type, fn);
@@ -514,9 +514,13 @@ function_attach(VALUE self, VALUE module, VALUE name)
/*
* Stash the Function in a module variable so it does not get garbage collected and can be inspected by attached_functions
*/
- snprintf(var, sizeof(var), "@ffi_function_%s", StringValueCStr(name));
- rb_ractor_make_shareable(self);
- rb_iv_set(module, var, self);
+
+ funcs = rb_iv_get(module, "@ffi_functions");
+ if (RB_NIL_P(funcs)) {
+ funcs = rb_hash_new();
+ rb_iv_set(module, "@ffi_functions", funcs);
+ }
+ rb_hash_aset(funcs, rb_str_intern(name), self);
rb_define_singleton_method(module, StringValueCStr(name),
rbffi_MethodHandle_CodeAddress(fn->methodHandle), -1);
diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c
index 7495215..b5150d8 100644
--- a/ext/ffi_c/FunctionInfo.c
+++ b/ext/ffi_c/FunctionInfo.c
@@ -251,6 +251,8 @@ fntype_initialize(int argc, VALUE* argv, VALUE self)
fnInfo->invoke = rbffi_GetInvoker(fnInfo);
+ rb_obj_freeze(fnInfo->rbParameterTypes);
+ rb_obj_freeze(self);
return self;
}
diff --git a/ext/ffi_c/MappedType.c b/ext/ffi_c/MappedType.c
index 20b14e9..2e506f2 100644
--- a/ext/ffi_c/MappedType.c
+++ b/ext/ffi_c/MappedType.c
@@ -110,6 +110,8 @@ mapped_initialize(VALUE self, VALUE rbConverter)
TypedData_Get_Struct(m->rbType, Type, &rbffi_type_data_type, m->type);
m->base.ffiType = m->type->ffiType;
+ rb_obj_freeze(self);
+
return self;
}
diff --git a/ext/ffi_c/StructLayout.c b/ext/ffi_c/StructLayout.c
index 613394a..a56d48f 100644
--- a/ext/ffi_c/StructLayout.c
+++ b/ext/ffi_c/StructLayout.c
@@ -181,6 +181,8 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
break;
}
+ rb_obj_freeze(self);
+
return self;
}
@@ -538,6 +540,11 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
rb_raise(rb_eRuntimeError, "Struct size is zero");
}
+ rb_obj_freeze(layout->rbFieldMap);
+ rb_obj_freeze(layout->rbFields);
+ rb_obj_freeze(layout->rbFieldNames);
+ rb_obj_freeze(self);
+
return self;
}
diff --git a/ext/ffi_c/Type.c b/ext/ffi_c/Type.c
index 9bf5681..a94c009 100644
--- a/ext/ffi_c/Type.c
+++ b/ext/ffi_c/Type.c
@@ -128,6 +128,8 @@ type_initialize(VALUE self, VALUE value)
rb_raise(rb_eArgError, "wrong type");
}
+ rb_obj_freeze(self);
+
return self;
}
@@ -192,6 +194,8 @@ builtin_type_new(VALUE klass, int nativeType, ffi_type* ffiType, const char* nam
type->type.nativeType = nativeType;
type->type.ffiType = ffiType;
+ rb_obj_freeze(obj);
+
return obj;
}
diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c
index 0f321d9..09d7ce8 100644
--- a/ext/ffi_c/Variadic.c
+++ b/ext/ffi_c/Variadic.c
@@ -183,9 +183,8 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE
/*
* @fixed and @type_map are used by the parameter mangling ruby code
*/
- rb_iv_set(self, "@fixed", fixed);
- rb_iv_set(self, "@type_map", rb_obj_dup(rb_hash_aref(options, ID2SYM(rb_intern("type_map")))));
- rb_ractor_make_shareable(self);
+ rb_iv_set(self, "@fixed", rb_obj_freeze(fixed));
+ rb_iv_set(self, "@type_map", rb_hash_aref(options, ID2SYM(rb_intern("type_map"))));
return retval;
}
diff --git a/ext/ffi_c/rbffi.h b/ext/ffi_c/rbffi.h
index 89b3e32..0e4e91a 100644
--- a/ext/ffi_c/rbffi.h
+++ b/ext/ffi_c/rbffi.h
@@ -39,7 +39,7 @@ extern "C" {
#define MAX_PARAMETERS (32)
extern VALUE rbffi_FFIModule;
-
+
extern void rbffi_Type_Init(VALUE ffiModule);
extern void rbffi_Buffer_Init(VALUE ffiModule);
extern void rbffi_Invoker_Init(VALUE ffiModule);
diff --git a/lib/ffi/library.rb b/lib/ffi/library.rb
index e681b3e..8af457d 100644
--- a/lib/ffi/library.rb
+++ b/lib/ffi/library.rb
@@ -295,9 +295,10 @@ module FFI
# If it is a global struct, just attach directly to the pointer
s = s = type.new(address) # Assigning twice to suppress unused variable warning
self.module_eval <<-code, __FILE__, __LINE__
- @ffi_gsvar_#{mname} = s
+ @ffi_gsvars = {} unless defined?(@ffi_gsvars)
+ @ffi_gsvars[#{mname.inspect}] = s
def self.#{mname}
- @ffi_gsvar_#{mname}
+ @ffi_gsvars[#{mname.inspect}]
end
code
@@ -309,12 +310,13 @@ module FFI
# Attach to this module as mname/mname=
#
self.module_eval <<-code, __FILE__, __LINE__
- @ffi_gvar_#{mname} = s
+ @ffi_gvars = {} unless defined?(@ffi_gvars)
+ @ffi_gvars[#{mname.inspect}] = s
def self.#{mname}
- @ffi_gvar_#{mname}[:gvar]
+ @ffi_gvars[#{mname.inspect}][:gvar]
end
def self.#{mname}=(value)
- @ffi_gvar_#{mname}[:gvar] = value
+ @ffi_gvars[#{mname.inspect}][:gvar] = value
end
code
@@ -541,20 +543,30 @@ module FFI
end
def attached_functions
- instance_variables.grep(/\A@ffi_function_(.*)/) do |m|
- [$1, instance_variable_get(m)]
- end.to_h
+ @ffi_functions || {}
end
def attached_variables
(
- instance_variables.grep(/\A@ffi_gsvar_(.*)/) do |m|
- [$1, instance_variable_get(m).class]
+ (@ffi_gsvars || {}).map do |name, gvar|
+ [name, gvar.class]
end +
- instance_variables.grep(/\A@ffi_gvar_(.*)/) do |m|
- [$1, instance_variable_get(m).layout[:gvar].type]
+ (@ffi_gvars || {}).map do |name, gvar|
+ [name, gvar.layout[:gvar].type]
end
).to_h
end
+
+ # Freeze all definitions of the module
+ #
+ # This freezes the module's definitions, so that it can be used in a Ractor.
+ # No further methods or variables can be attached and no further enums or typedefs can be created in this module afterwards.
+ def freeze
+ instance_variables.each do |name|
+ var = instance_variable_get(name)
+ FFI.make_shareable(var)
+ end
+ nil
+ end
end
end
diff --git a/lib/ffi/struct.rb b/lib/ffi/struct.rb
index 1283d63..725b9cb 100644
--- a/lib/ffi/struct.rb
+++ b/lib/ffi/struct.rb
@@ -219,7 +219,7 @@ module FFI
end
builder.size = @size if defined?(@size) && @size > builder.size
cspec = builder.build
- @layout = FFI.make_shareable(cspec) unless self == Struct
+ @layout = cspec unless self == Struct
@size = cspec.size
return cspec
end
diff --git a/lib/ffi/struct_layout.rb b/lib/ffi/struct_layout.rb
index d5a78a7..3fd68cb 100644
--- a/lib/ffi/struct_layout.rb
+++ b/lib/ffi/struct_layout.rb
@@ -80,8 +80,8 @@ module FFI
class Mapped < Field
def initialize(name, offset, type, orig_field)
- super(name, offset, type)
@orig_field = orig_field
+ super(name, offset, type)
end
def get(ptr)
diff --git a/lib/ffi/struct_layout_builder.rb b/lib/ffi/struct_layout_builder.rb
index 5488033..d7d26a2 100644
--- a/lib/ffi/struct_layout_builder.rb
+++ b/lib/ffi/struct_layout_builder.rb
@@ -97,7 +97,7 @@ module FFI
# List of number types
- NUMBER_TYPES = FFI.make_shareable([
+ NUMBER_TYPES = [
Type::INT8,
Type::UINT8,
Type::INT16,
@@ -112,7 +112,7 @@ module FFI
Type::FLOAT64,
Type::LONGDOUBLE,
Type::BOOL,
- ])
+ ].freeze
# @param [String, Symbol] name name of the field
# @param [Array, DataConverter, Struct, StructLayout::Field, Symbol, Type] type type of the field
diff --git a/lib/ffi/variadic.rb b/lib/ffi/variadic.rb
index 800d121..246b52f 100644
--- a/lib/ffi/variadic.rb
+++ b/lib/ffi/variadic.rb
@@ -54,11 +54,12 @@ module FFI
invoker = self
params = "*args"
call = "call"
- mod.module_eval <<-code
- @ffi_function_#{mname} = invoker
+ mod.module_eval <<-code, __FILE__, __LINE__
+ @ffi_functions = {} unless defined?(@ffi_functions)
+ @ffi_functions[#{mname.inspect}] = invoker
def self.#{mname}(#{params})
- @ffi_function_#{mname}.#{call}(#{params})
+ @ffi_functions[#{mname.inspect}].#{call}(#{params})
end
define_method(#{mname.inspect}, &method(:#{mname}))
diff --git a/spec/ffi/dynamic_library_spec.rb b/spec/ffi/dynamic_library_spec.rb
index a6ea2a9..088a822 100644
--- a/spec/ffi/dynamic_library_spec.rb
+++ b/spec/ffi/dynamic_library_spec.rb
@@ -9,7 +9,6 @@ describe FFI::DynamicLibrary do
it "should be shareable for Ractor", :ractor do
libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
- Ractor.make_shareable(libtest)
res = Ractor.new(libtest) do |libtest2|
libtest2.find_symbol("testClosureVrV").address
@@ -52,5 +51,10 @@ describe FFI::DynamicLibrary do
size = ObjectSpace.memsize_of(symbol)
expect(size).to be > base_size
end
+
+ it "should be shareable for Ractor", :ractor do
+ symbol = @libtest.find_symbol("gvar_gstruct_set")
+ expect(Ractor.shareable?(symbol)).to be true
+ end
end
end
diff --git a/spec/ffi/enum_spec.rb b/spec/ffi/enum_spec.rb
index 1fba2cb..7a55b07 100644
--- a/spec/ffi/enum_spec.rb
+++ b/spec/ffi/enum_spec.rb
@@ -26,14 +26,18 @@ module TestEnum3
ffi_lib TestLibrary::PATH
enum :enum_type1, [:c1, :c2, :c3, :c4]
- enum :enum_type2, [:c5, 42, :c6, :c7, :c8]
- enum :enum_type3, [:c9, 42, :c10, :c11, 4242, :c12]
- enum :enum_type4, [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
-
attach_function :test_tagged_typedef_enum1, [:enum_type1], :enum_type1
+
+ enum :enum_type2, [:c5, 42, :c6, :c7, :c8]
attach_function :test_tagged_typedef_enum2, [:enum_type2], :enum_type2
+
+ enum :enum_type3, [:c9, 42, :c10, :c11, 4242, :c12]
attach_function :test_tagged_typedef_enum3, [:enum_type3], :enum_type3
+
+ enum :enum_type4, [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
attach_function :test_tagged_typedef_enum4, [:enum_type4], :enum_type4
+
+ freeze
end
module TestEnum4
@@ -44,18 +48,22 @@ module TestEnum4
enum :enum_type1, [:c5, 0x42, :c6, :c7, :c8]
enum :enum_type2, [:c9, 0x42, :c10, :c11, 0x4242, :c12]
enum :enum_type3, [:c13, 0x42, :c14, 0x4242, :c15, 0x42424242, :c16, 0x4242424242424242]
- enum FFI::Type::UINT16, :enum_type4, [:c17, 0x42, :c18, :c19, :c20]
- enum FFI::Type::UINT32, :enum_type5, [:c21, 0x42, :c22, :c23, 0x4242, :c24]
- enum FFI::Type::UINT64, :enum_type6, [:c25, 0x42, :c26, 0x4242, :c27, 0x42424242, :c28, 0x4242424242424242]
- enum FFI::Type::UINT64, [:c29, 0x4242424242424242, :c30, :c31, :c32]
attach_function :test_untagged_nonint_enum, [:uint8], :uint8
attach_function :test_tagged_nonint_enum1, [:uint16], :uint16
attach_function :test_tagged_nonint_enum2, [:uint32], :uint32
attach_function :test_tagged_nonint_enum3, [:uint64], :uint64
+
+ enum FFI::Type::UINT16, :enum_type4, [:c17, 0x42, :c18, :c19, :c20]
+ enum FFI::Type::UINT32, :enum_type5, [:c21, 0x42, :c22, :c23, 0x4242, :c24]
+ enum FFI::Type::UINT64, :enum_type6, [:c25, 0x42, :c26, 0x4242, :c27, 0x42424242, :c28, 0x4242424242424242]
+ enum FFI::Type::UINT64, [:c29, 0x4242424242424242, :c30, :c31, :c32]
+
attach_function :test_tagged_nonint_enum4, :test_tagged_nonint_enum1, [:enum_type4], :enum_type4
attach_function :test_tagged_nonint_enum5, :test_tagged_nonint_enum2, [:enum_type5], :enum_type5
attach_function :test_tagged_nonint_enum6, :test_tagged_nonint_enum3, [:enum_type6], :enum_type6
+
+ freeze
end
describe "A library with no enum defined" do
diff --git a/spec/ffi/function_spec.rb b/spec/ffi/function_spec.rb
index badd240..77d09d8 100644
--- a/spec/ffi/function_spec.rb
+++ b/spec/ffi/function_spec.rb
@@ -52,7 +52,7 @@ describe FFI::Function do
a + b
end
- it "should be shareable for Ractor", :ractor do
+ it "can be made shareable for Ractor", :ractor do
add = FFI::Function.new(:int, [:int, :int], &method(:adder))
Ractor.make_shareable(add)
diff --git a/spec/ffi/library_spec.rb b/spec/ffi/library_spec.rb
index 52a961f..1b8e8c1 100644
--- a/spec/ffi/library_spec.rb
+++ b/spec/ffi/library_spec.rb
@@ -8,6 +8,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
module TestEnumValueRactor
extend FFI::Library
enum :something, [:one, :two]
+ freeze
end
describe "Library" do
@@ -197,28 +198,46 @@ describe "Library" do
end.getpid).to eq(Process.pid)
}.to raise_error(LoadError)
end
+ end
- it "attach_function :bool_return_true from [ File.expand_path(#{TestLibrary::PATH.inspect}) ]" do
- mod = Module.new do |m|
- m.extend FFI::Library
- ffi_lib File.expand_path(TestLibrary::PATH)
- attach_function :bool_return_true, [ ], :bool
- end
- expect(mod.bool_return_true).to be true
+ it "attach_function :bool_return_true from [ File.expand_path(#{TestLibrary::PATH.inspect}) ]" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :bool_return_true, [ ], :bool
end
+ expect(mod.bool_return_true).to be true
+ end
- it "can reveal the function type" do
- mod = Module.new do |m|
- m.extend FFI::Library
- ffi_lib File.expand_path(TestLibrary::PATH)
- attach_function :bool_return_true, [ :string ], :bool
- end
+ it "can define a foo! function" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :foo!, :bool_return_true, [], :bool
+ end
+ expect(mod.foo!).to be true
+ end
+
+ it "can define a foo? function" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :foo?, :bool_return_true, [], :bool
+ end
+ expect(mod.foo?).to be true
+ end
- fun = mod.attached_functions
- expect(fun.keys).to eq(["bool_return_true"])
- expect(fun["bool_return_true"].param_types).to eq([FFI::Type::STRING])
- expect(fun["bool_return_true"].return_type).to eq(FFI::Type::BOOL)
+ it "can reveal the function type" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :bool_return_true, [ :string ], :bool
end
+
+ fun = mod.attached_functions
+ expect(fun.keys).to eq([:bool_return_true])
+ expect(fun[:bool_return_true].param_types).to eq([FFI::Type::STRING])
+ expect(fun[:bool_return_true].return_type).to eq(FFI::Type::BOOL)
end
def gvar_lib(name, type)
@@ -355,7 +374,7 @@ describe "Library" do
ffi_lib TestLibrary::PATH
attach_variable :gvari, "gvar_gstruct", GlobalStruct
end
- expect(lib.attached_variables).to eq({ "gvari" => GlobalStruct })
+ expect(lib.attached_variables).to eq({ gvari: GlobalStruct })
end
it "can reveal its attached global variables" do
@@ -364,7 +383,7 @@ describe "Library" do
ffi_lib TestLibrary::PATH
attach_variable :gvaro, "gvar_u32", :uint32
end
- expect(lib.attached_variables).to eq({ "gvaro" => FFI::Type::UINT32 })
+ expect(lib.attached_variables).to eq({ gvaro: FFI::Type::UINT32 })
end
it "should have shareable constants for Ractor", :ractor do
diff --git a/spec/ffi/struct_by_ref_spec.rb b/spec/ffi/struct_by_ref_spec.rb
index 0c01137..f664937 100644
--- a/spec/ffi/struct_by_ref_spec.rb
+++ b/spec/ffi/struct_by_ref_spec.rb
@@ -41,7 +41,7 @@ describe FFI::Struct, ' by_ref' do
end
it "can reveal the mapped type converter" do
- param_type = @api.attached_functions["struct_test"].param_types[0]
+ param_type = @api.attached_functions[:struct_test].param_types[0]
expect(param_type).to be_a(FFI::Type::Mapped)
expect(param_type.converter).to be_a(FFI::StructByReference)
end
diff --git a/spec/ffi/struct_spec.rb b/spec/ffi/struct_spec.rb
index d09b7b6..ab62da1 100644
--- a/spec/ffi/struct_spec.rb
+++ b/spec/ffi/struct_spec.rb
@@ -545,7 +545,7 @@ module StructSpecsStructTests
expect(b.members).to eq([:a, :b])
end
- it "should be shareable for Ractor", :ractor do
+ it "can be made shareable for Ractor", :ractor do
a = Class.new(FFI::Struct) do
layout :a, :char
end.new
@@ -1109,6 +1109,20 @@ describe "Struct memsize functions", skip: RUBY_ENGINE != "ruby" do
size = ObjectSpace.memsize_of(layout[:pointer])
expect(size).to be > base_size
end
+
+ it "StructLayout should be shareable with Ractor", :ractor do
+ kl = Class.new(FFI::Struct) do
+ layout :ptr, :pointer
+ end
+ expect(Ractor.shareable?(kl.layout)).to eq(true)
+ end
+
+ it "StructField should be shareable with Ractor", :ractor do
+ kl = Class.new(FFI::Struct) do
+ layout :ptr, :pointer
+ end
+ expect(Ractor.shareable?(kl.layout[:ptr])).to eq(true)
+ end
end
diff --git a/spec/ffi/type_spec.rb b/spec/ffi/type_spec.rb
index eb48a43..e880c83 100644
--- a/spec/ffi/type_spec.rb
+++ b/spec/ffi/type_spec.rb
@@ -5,7 +5,7 @@
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
-describe "FFI::Type" do
+describe FFI::Type do
it 'has a memsize function', skip: RUBY_ENGINE != "ruby" do
base_size = ObjectSpace.memsize_of(Object.new)
@@ -40,4 +40,37 @@ describe "FFI::Type" do
size = ObjectSpace.memsize_of(FFI::Type::Builtin::CHAR)
expect(size).to be > base_size
end
+
+ it "should be shareable with Ractor", :ractor do
+ expect(Ractor.shareable?(FFI::Type.new(5))).to eq(true)
+ end
+
+ describe :Builtin do
+ it "should be shareable with Ractor", :ractor do
+ expect(Ractor.shareable?(FFI::Type::INT32)).to eq(true)
+ end
+ end
+
+ describe :Mapped do
+ it "should be shareable with Ractor", :ractor do
+ converter = Module.new do
+ extend FFI::DataConverter
+
+ def self.native_type
+ FFI::Type::INT32
+ end
+
+ def self.to_native(val, ctx)
+ ToNativeMap[val]
+ end
+
+ def self.from_native(val, ctx)
+ FromNativeMap[val]
+ end
+ end
+ expect(Ractor.shareable?(converter)).to eq(true)
+ type = FFI::Type::Mapped.new(converter)
+ expect(Ractor.shareable?(type)).to eq(true)
+ end
+ end
end
diff --git a/spec/ffi/variadic_spec.rb b/spec/ffi/variadic_spec.rb
index 917212a..21a803f 100644
--- a/spec/ffi/variadic_spec.rb
+++ b/spec/ffi/variadic_spec.rb
@@ -23,6 +23,8 @@ describe "Function with variadic arguments" do
attach_function :testBlockingClose, [ :pointer ], :void
attach_function :testCallbackVrDva, :testClosureVrDva, [ :double, :varargs ], :double
attach_function :testCallbackVrILva, :testClosureVrILva, [ :int, :long, :varargs ], :long
+
+ freeze
end
it "takes enum arguments" do