summaryrefslogtreecommitdiff
path: root/lib/ffi/library.rb
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 /lib/ffi/library.rb
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
Diffstat (limited to 'lib/ffi/library.rb')
-rw-r--r--lib/ffi/library.rb36
1 files changed, 24 insertions, 12 deletions
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