[ruby/fiddle] Define Fiddle.last_error family and Fiddle.dlopen

statically
(https://github.com/ruby/fiddle/pull/172)

`RUBY_ENGINE` and `Fiddle::WINDOWS` should not change in a process, no
need to be checked inside the methods.

Also, `win32_last_error` and `win32_last_socket_error` are equal to
`last_error` on JRuby.

https://github.com/ruby/fiddle/commit/50ac00ed53
This commit is contained in:
Nobuyoshi Nakada 2025-02-01 05:58:54 +09:00 committed by Hiroshi SHIBATA
parent 56c814a8d3
commit b5b5097663

View File

@ -10,98 +10,72 @@ require 'fiddle/function'
require 'fiddle/version' require 'fiddle/version'
module Fiddle module Fiddle
if WINDOWS case RUBY_ENGINE
# Returns the last win32 +Error+ of the current executing +Thread+ or nil when 'jruby'
# if none def self.last_error
def self.win32_last_error FFI.errno.nonzero?
if RUBY_ENGINE == 'jruby' end
errno = FFI.errno
errno == 0 ? nil : errno def self.last_error= error
else FFI.errno = error || 0
end
if WINDOWS
class << self
alias win32_last_error last_error
alias win32_last_error= last_error=
alias win32_last_socket_error last_error
alias win32_last_socket_error= last_error=
end
end
else
# Returns the last +Error+ of the current executing +Thread+ or nil if none
def self.last_error
Thread.current[:__FIDDLE_LAST_ERROR__]
end
# Sets the last +Error+ of the current executing +Thread+ to +error+
def self.last_error= error
Thread.current[:__DL2_LAST_ERROR__] = error
Thread.current[:__FIDDLE_LAST_ERROR__] = error
end
if WINDOWS
# Returns the last win32 +Error+ of the current executing +Thread+ or nil
# if none
def self.win32_last_error
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
end end
end
# Sets the last win32 +Error+ of the current executing +Thread+ to +error+ # Sets the last win32 +Error+ of the current executing +Thread+ to +error+
def self.win32_last_error= error def self.win32_last_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
end end
end
# Returns the last win32 socket +Error+ of the current executing # Returns the last win32 socket +Error+ of the current executing
# +Thread+ or nil if none # +Thread+ or nil if none
def self.win32_last_socket_error def self.win32_last_socket_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
end end
end
# Sets the last win32 socket +Error+ of the current executing # Sets the last win32 socket +Error+ of the current executing
# +Thread+ to +error+ # +Thread+ to +error+
def self.win32_last_socket_error= error def self.win32_last_socket_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
end end
end end
end end
# Returns the last +Error+ of the current executing +Thread+ or nil if none case RUBY_PLATFORM
def self.last_error when /linux/
if RUBY_ENGINE == 'jruby' def dlopen library
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_LAST_ERROR__]
end
end
# Sets the last +Error+ of the current executing +Thread+ to +error+
def self.last_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__DL2_LAST_ERROR__] = error
Thread.current[:__FIDDLE_LAST_ERROR__] = error
end
end
# call-seq: dlopen(library) => Fiddle::Handle
#
# Creates a new handler that opens +library+, and returns an instance of
# Fiddle::Handle.
#
# If +nil+ is given for the +library+, Fiddle::Handle::DEFAULT is used, which
# is the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
#
# lib = Fiddle.dlopen(nil)
#
# The default is dependent on OS, and provide a handle for all libraries
# already loaded. For example, in most cases you can use this to access
# +libc+ functions, or ruby functions like +rb_str_new+.
#
# See Fiddle::Handle.new for more.
def dlopen library
begin
Fiddle::Handle.new(library) Fiddle::Handle.new(library)
rescue DLError => error rescue DLError => error
case RUBY_PLATFORM case error.message
when /linux/ when /\A(\/.+?): (?:invalid ELF header|file too short)/
case error.message # This may be a linker script:
when /\A(\/.+?): (?:invalid ELF header|file too short)/ # https://sourceware.org/binutils/docs/ld.html#Scripts
# This may be a linker script: path = $1
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
else else
raise raise
end end
@ -123,6 +97,25 @@ module Fiddle
# Not found # Not found
raise raise
end end
else
# call-seq: dlopen(library) => Fiddle::Handle
#
# Creates a new handler that opens +library+, and returns an instance of
# Fiddle::Handle.
#
# If +nil+ is given for the +library+, Fiddle::Handle::DEFAULT is used, which
# is the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
#
# lib = Fiddle.dlopen(nil)
#
# The default is dependent on OS, and provide a handle for all libraries
# already loaded. For example, in most cases you can use this to access
# +libc+ functions, or ruby functions like +rb_str_new+.
#
# See Fiddle::Handle.new for more.
def dlopen library
Fiddle::Handle.new(library)
end
end end
module_function :dlopen module_function :dlopen