13c13 < require 'thread' --- > require 'monitor' 22,25c22,26 < @@mutex = Mutex.new < @@final = lambda {|id| < @@mutex.synchronize { < rids = @@id_map[id] --- > @@monitor = Monitor.new > > @@object_finalizer = lambda do |id| > @@monitor.synchronize do > rids = @@id_map.delete(id) 27,30c28,30 < for rid in rids < @@id_rev_map.delete(rid) < end < @@id_map.delete(id) --- > rids.each do |rid| > @@id_rev_map.delete(rid) > end 32c32,37 < rid = @@id_rev_map[id] --- > end > end > > @@reference_finalizer = lambda do |id| > @@monitor.synchronize do > rid = @@id_rev_map.delete(id) 34,36c39,51 < @@id_rev_map.delete(id) < @@id_map[rid].delete(id) < @@id_map.delete(rid) if @@id_map[rid].empty? --- > obj = ObjectSpace._id2ref(referenced_object_id) rescue nil > if obj > backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__) > if backreferences > backreferences.delete(object_id) > obj.send(:remove_instance_variable, :@__weak_backreferences__) if backreferences.empty? > end > end > refs = @@id_map[rid] > if refs > refs.delete(id) > @@id_map.delete(rid) if refs.empty? > end 38,39c53,54 < } < } --- > end > end 42,45c57,60 < @__id = orig.object_id < ObjectSpace.define_finalizer orig, @@final < ObjectSpace.define_finalizer self, @@final < @@mutex.synchronize { --- > @__id = orig.__id__ > ObjectSpace.define_finalizer orig, @@object_finalizer > ObjectSpace.define_finalizer self, @@reference_finalizer > @@monitor.synchronize do 47,49c62,65 < } < @@id_map[@__id].push self.object_id < @@id_rev_map[self.object_id] = @__id --- > @@id_map[@__id].push self.__id__ > @@id_rev_map[__id__] = @__id > __add_weakref_backreference__(orig) > end 54,56c70 < unless @@id_rev_map[self.object_id] == @__id < Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) < end --- > obj = nil 58c72,75 < ObjectSpace._id2ref(@__id) --- > if @@id_rev_map[self.__id__] == @__id > obj = ObjectSpace._id2ref(@__id) > obj = nil unless __verify_weakref_backreference__(obj) > end 60c77 < Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) --- > # Object has been garbage collected. 61a79,80 > Kernel::raise(RefError, "Invalid Reference - probably recycled", Kernel::caller(1)) unless obj > obj 62a82 > 67c87,94 < @@id_rev_map[self.object_id] == @__id --- > if @@id_rev_map[self.__id__] == @__id > obj = ObjectSpace._id2ref(@__id) > __verify_weakref_backreference__(obj) > else > false > end > rescue RangeError > false 68a96,117 > > private > > # Add a backreference to the weakref object id in the referenced object to protect > # against the object id being recycled before the finalizers have a chance to run. > def __add_weakref_backreference__(obj) > backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__) > unless backreferences > backreferences = [] > obj.instance_variable_set(:@__weak_backreferences__, backreferences) > end > backreferences << object_id > end > > # Verify that the object is the one the weakref thinks it is. On runtimes where > # object ids are recycled after garbage collection and reallocated to new objects, > # there is a chance that the reference could find an object at the specified > # location in the ObjectSpace that is not the one it originally referenced. > def __verify_weakref_backreference__(obj) > backreferences = obj.instance_variable_get(:@__weak_backreferences__) if obj.instance_variable_defined?(:@__weak_backreferences__) > backreferences && backreferences.include?(self.__id__) > end 72c121 < # require 'thread' --- > # require 'thread'