Skip to content

Commit

Permalink
Define Fiddle.last_error family and Fiddle.dlopen statically (#172)
Browse files Browse the repository at this point in the history
`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.
  • Loading branch information
nobu authored Jan 31, 2025
1 parent d5fd917 commit 50ac00e
Showing 1 changed file with 69 additions and 76 deletions.
145 changes: 69 additions & 76 deletions lib/fiddle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,98 +10,72 @@
require 'fiddle/version'

module Fiddle
if WINDOWS
# Returns the last win32 +Error+ of the current executing +Thread+ or nil
# if none
def self.win32_last_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
end
case RUBY_ENGINE
when 'jruby'
def self.last_error
FFI.errno.nonzero?
end

# Sets the last win32 +Error+ of the current executing +Thread+ to +error+
def self.win32_last_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
end
end

# Returns the last win32 socket +Error+ of the current executing
# +Thread+ or nil if none
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__]
end
def self.last_error= error
FFI.errno = error || 0
end

# Sets the last win32 socket +Error+ of the current executing
# +Thread+ to +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
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
end

# Returns the last +Error+ of the current executing +Thread+ or nil if none
def self.last_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
else
# Returns the last +Error+ of the current executing +Thread+ or nil if none
def self.last_error
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
# 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__]
end

# Sets the last win32 +Error+ of the current executing +Thread+ to +error+
def self.win32_last_error= error
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
end

# Returns the last win32 socket +Error+ of the current executing
# +Thread+ or nil if none
def self.win32_last_socket_error
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
end

# Sets the last win32 socket +Error+ of the current executing
# +Thread+ to +error+
def self.win32_last_socket_error= error
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
end
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
case RUBY_PLATFORM
when /linux/
def dlopen library
Fiddle::Handle.new(library)
rescue DLError => error
case RUBY_PLATFORM
when /linux/
case error.message
when /\A(\/.+?): (?:invalid ELF header|file too short)/
# This may be a linker script:
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
case error.message
when /\A(\/.+?): (?:invalid ELF header|file too short)/
# This may be a linker script:
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
Expand All @@ -123,6 +97,25 @@ def dlopen library
# Not found
raise
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
module_function :dlopen

Expand Down

0 comments on commit 50ac00e

Please sign in to comment.