Skip to content
This repository was archived by the owner on Mar 15, 2022. It is now read-only.

Commit 755b811

Browse files
author
Brian Durand
committed
make library thread save by replacing autoloads with requires
add support for ruby 2.0 Add handling for BasicObject in ruby 1.8/1.9 implementation
1 parent 55c34ce commit 755b811

File tree

7 files changed

+54
-21
lines changed

7 files changed

+54
-21
lines changed

HISTORY.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
1.0.3
2+
3+
- Support Ruby 2.0 WeakRef implementation
4+
- Replace autoload with require to make library thread safe
5+
16
1.0.2
27

38
- Fix mock object used for testing (Burgestrand)

MIT_LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2011 Brian Durand
1+
Copyright (c) 2013 Brian Durand
22

33
Permission is hereby granted, free of charge, to any person obtaining
44
a copy of this software and associated documentation files (the

README.rdoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ Ruby does come with the WeakRef class in the standard library. However, there ar
3333
2. YARV 1.9 - WeakRef is unsafe to use because the garbage collector can run in a different system thread than a thread allocating memory. This exposes a bug where a WeakRef may end up pointing to a completely different object than it originally referenced.
3434
3. Jruby and IronRuby - Jruby and IronRuby using the Ruby 1.8 libraries suffers from the same performance issue with the Delegator class. Furthermore, these VM's don't implement the method used to load an object from the heap using an object id and so cannot use a pure Ruby method to implement weak references.
3535
4. Rubinius - Rubinius implements WeakRef with a lighter weight version of delegation and works very well.
36+
5. MRI Ruby 2.0 has a good implementation of WeakRef.
37+
38+
= BasicObject
39+
40+
Not that weak references will not work with MRI/REE 1.8 or YARV 1.9. References will be created, but the objects will never be stored so the reference object will always treat the object as if it is always garbage collected. BasicObject does not implement the necessary methods to maintain the reference.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.2
1+
1.0.3

lib/ref.rb

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
module Ref
2-
autoload :AbstractReferenceValueMap, File.join(File.dirname(__FILE__), "ref", "abstract_reference_value_map.rb")
3-
autoload :AbstractReferenceKeyMap, File.join(File.dirname(__FILE__), "ref", "abstract_reference_key_map.rb")
4-
autoload :Mock, File.join(File.dirname(__FILE__), "ref", "mock.rb")
5-
autoload :Reference, File.join(File.dirname(__FILE__), "ref", "reference.rb")
6-
autoload :ReferenceQueue, File.join(File.dirname(__FILE__), "ref", "reference_queue.rb")
7-
autoload :SafeMonitor, File.join(File.dirname(__FILE__), "ref", "safe_monitor.rb")
8-
autoload :SoftKeyMap, File.join(File.dirname(__FILE__), "ref", "soft_key_map.rb")
9-
autoload :SoftValueMap, File.join(File.dirname(__FILE__), "ref", "soft_value_map.rb")
10-
autoload :StrongReference, File.join(File.dirname(__FILE__), "ref", "strong_reference.rb")
11-
autoload :WeakKeyMap, File.join(File.dirname(__FILE__), "ref", "weak_key_map.rb")
12-
autoload :WeakValueMap, File.join(File.dirname(__FILE__), "ref", "weak_value_map.rb")
2+
require File.join(File.dirname(__FILE__), "ref", "abstract_reference_value_map.rb")
3+
require File.join(File.dirname(__FILE__), "ref", "abstract_reference_key_map.rb")
4+
require File.join(File.dirname(__FILE__), "ref", "reference.rb")
5+
require File.join(File.dirname(__FILE__), "ref", "reference_queue.rb")
6+
require File.join(File.dirname(__FILE__), "ref", "safe_monitor.rb")
137

148
# Set the best implementation for weak references based on the runtime.
159
if defined?(RUBY_PLATFORM) && RUBY_PLATFORM == 'java'
@@ -21,19 +15,31 @@ module Ref
2115
$LOAD_PATH.shift if $LOAD_PATH.first == File.dirname(__FILE__)
2216
end
2317
else
24-
autoload :SoftReference, File.join(File.dirname(__FILE__), "ref", "soft_reference.rb")
18+
require File.join(File.dirname(__FILE__), "ref", "soft_reference.rb")
2519
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby'
2620
# IronRuby has it's own implementation of weak references.
27-
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "iron_ruby.rb")
21+
require File.join(File.dirname(__FILE__), "ref", "weak_reference", "iron_ruby.rb")
2822
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
2923
# If using Rubinius set the implementation to use WeakRef since it is very efficient and using finalizers is not.
30-
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
31-
elsif defined?(ObjectSpace._id2ref)
24+
require File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
25+
elsif defined?(::ObjectSpace::WeakMap)
26+
# Ruby 2.0 has a working implementation of weakref.rb backed by the new ObjectSpace::WeakMap
27+
require File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
28+
elsif defined?(::ObjectSpace._id2ref)
3229
# If ObjectSpace can lookup objects from their object_id, then use the pure ruby implementation.
33-
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "pure_ruby.rb")
30+
require File.join(File.dirname(__FILE__), "ref", "weak_reference", "pure_ruby.rb")
3431
else
3532
# Otherwise, wrap the standard library WeakRef class
36-
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
33+
require File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
3734
end
3835
end
36+
37+
require File.join(File.dirname(__FILE__), "ref", "soft_key_map.rb")
38+
require File.join(File.dirname(__FILE__), "ref", "soft_value_map.rb")
39+
require File.join(File.dirname(__FILE__), "ref", "strong_reference.rb")
40+
require File.join(File.dirname(__FILE__), "ref", "weak_key_map.rb")
41+
require File.join(File.dirname(__FILE__), "ref", "weak_value_map.rb")
42+
43+
# Used for testing
44+
autoload :Mock, File.join(File.dirname(__FILE__), "ref", "mock.rb")
3945
end

lib/ref/weak_reference/pure_ruby.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
module Ref
22
# This is a pure ruby implementation of a weak reference. It is much more
3-
# efficient than the bundled WeakRef implementation because it does not
3+
# efficient than the WeakRef implementation bundled in MRI 1.8 and 1.9
44
# subclass Delegator which is very heavy to instantiate and utilizes a
5-
# fair amount of memory under Ruby 1.8.
5+
# because it does not fair amount of memory under Ruby 1.8.
66
class WeakReference < Reference
77

88
class ReferencePointer
@@ -26,12 +26,14 @@ def object
2626
private
2727
# Verify that the object is the same one originally set for the weak reference.
2828
def verify_backreferences(obj) #:nodoc:
29+
return nil unless supports_backreference?(obj)
2930
backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__)
3031
backreferences && backreferences.include?(object_id)
3132
end
3233

3334
# Add a backreference to the object.
3435
def add_backreference(obj) #:nodoc:
36+
return unless supports_backreference?(obj)
3537
backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__)
3638
unless backreferences
3739
backreferences = []
@@ -42,12 +44,17 @@ def add_backreference(obj) #:nodoc:
4244

4345
# Remove backreferences from the object.
4446
def remove_backreference(obj) #:nodoc:
47+
return unless supports_backreference?(obj)
4548
backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__)
4649
if backreferences
4750
backreferences.dup.delete(object_id)
4851
obj.send(:remove_instance_variable, :@__weak_backreferences__) if backreferences.empty?
4952
end
5053
end
54+
55+
def supports_backreference?(obj)
56+
obj.respond_to?(:instance_variable_get) && obj.respond_to?(:instance_variable_defined?)
57+
end
5158
end
5259

5360
@@weak_references = {}

test/weak_reference_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,14 @@ def test_inspect
4343
GC.start
4444
assert ref.inspect
4545
end
46+
47+
class TestBasicObject < Object
48+
undef_method(:instance_variable_defined?)
49+
undef_method(:instance_variable_get)
50+
end
51+
52+
def test_basic_object_does_not_throw_exception
53+
obj = TestBasicObject.new
54+
Ref::WeakReference.new(obj)
55+
end
4656
end

0 commit comments

Comments
 (0)