forked from headius/thread_safe
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor our synchronized delegator to work with MRI/JRuby 1.8 std-lib
this due delegator.rb library doing eval on `initialize` - thus `method_missing` is not actually called for __send__ delegation to the target. we avoid this by unpatching the work done by MRI as well as JRuby in 1.8 mode (which is slightly different since it tries to pre-generate a module that it includes based on target's class do not do that much eval). changed tests due a bug in delegator.rb that affects 1.8 - we've been expecting a delegated Array#each (with a block) which won't work since the block is not passed to the target ...
- Loading branch information
Showing
2 changed files
with
116 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,75 @@ | ||
require 'delegate' | ||
|
||
# This class provides a trivial way to synchronize all calls to a given object | ||
# by wrapping it with a Delegator that performs Mutex#lock/unlock calls around | ||
# the delegated #send. Example: | ||
# by wrapping it with a `Delegator` that performs `Mutex#lock/unlock` calls | ||
# around the delegated `#send`. Example: | ||
# | ||
# array = [] # not thread-safe on many impls | ||
# array = MutexedDelegator.new(array) # thread-safe | ||
# array = SynchronizedDelegator.new([]) # thread-safe | ||
# | ||
# A simple Mutex provides a very coarse-grained way to synchronize a given | ||
# A simple `Mutex` provides a very coarse-grained way to synchronize a given | ||
# object, in that it will cause synchronization for methods that have no | ||
# need for it, but this is a trivial way to get thread-safety where none may | ||
# exist currently on some implementations. | ||
# | ||
# This class is currently being considered for inclusion into stdlib, via | ||
# https://bugs.ruby-lang.org/issues/8556 | ||
class SynchronizedDelegator < SimpleDelegator | ||
|
||
require 'delegate' | ||
def initialize(obj) | ||
super # __setobj__(obj) | ||
@mutex = Mutex.new | ||
undef_cached_methods! | ||
end | ||
|
||
unless defined?(SynchronizedDelegator) | ||
class SynchronizedDelegator < SimpleDelegator | ||
def initialize(*) | ||
def method_missing(method, *args, &block) | ||
mutex = @mutex | ||
begin | ||
mutex.lock | ||
super | ||
@mutex = Mutex.new | ||
ensure | ||
mutex.unlock | ||
end | ||
end | ||
|
||
private | ||
|
||
if RUBY_VERSION[0, 3] == '1.8' | ||
|
||
def method_missing(m, *args, &block) | ||
begin | ||
mutex = @mutex | ||
mutex.lock | ||
super | ||
ensure | ||
mutex.unlock | ||
def singleton_class | ||
class << self; self end | ||
end unless respond_to?(:singleton_class) | ||
|
||
# The 1.8 delegator library does (instance) "eval" all methods | ||
# delegated on {#initialize}. | ||
# @see http://rubydoc.info/stdlib/delegate/1.8.7/Delegator | ||
# @private | ||
def undef_cached_methods! | ||
self_class = singleton_class | ||
for method in self_class.instance_methods(false) | ||
self_class.send :undef_method, method | ||
end | ||
end | ||
|
||
# JRuby 1.8 mode stdlib internals - caching generated modules | ||
# methods under `Delegator::DelegatorModules` based on class. | ||
# @private | ||
def undef_cached_methods! | ||
gen_mod = DelegatorModules[[__getobj__.class, self.class]] | ||
if gen_mod && singleton_class.include?(gen_mod) | ||
self_class = singleton_class | ||
for method in gen_mod.instance_methods(false) | ||
self_class.send :undef_method, method | ||
end | ||
end | ||
end if constants.include?('DelegatorModules') | ||
|
||
else | ||
|
||
# Nothing to do since 1.9 {#method_missing} will get called. | ||
# @private | ||
def undef_cached_methods!; end | ||
|
||
end | ||
end | ||
|
||
end unless defined?(SynchronizedDelegator) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters