13c13 < require 'thread' --- > require 'monitor' 22,30c22,42 < @@mutex = Mutex.new < @@final = lambda {|id| < @@mutex.synchronize { < rids = @@id_map[id] < if rids < for rid in rids < @@id_rev_map.delete(rid) < end < @@id_map.delete(id) --- > @@monitor = Monitor.new > > @@object_finalizer = lambda do |id| > rids = @@id_map.delete(id) > if rids > rids.each do |rid| > @@id_rev_map.delete(rid) > end > end > end > > @@reference_finalizer = lambda do |id| > rid = @@id_rev_map.delete(id) > if rid > 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 32,36c44,47 < rid = @@id_rev_map[id] < if rid < @@id_rev_map.delete(id) < @@id_map[rid].delete(id) < @@id_map.delete(rid) if @@id_map[rid].empty? --- > refs = @@id_map[rid] > if refs > refs.delete(id) > @@id_map.delete(rid) if refs.empty? 38,39c49,50 < } < } --- > end > end 42,45c53,56 < @__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,49c58,61 < } < @@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,56c66 < unless @@id_rev_map[self.object_id] == @__id < Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) < end --- > obj = nil 58c68,71 < ObjectSpace._id2ref(@__id) --- > if @@id_rev_map[self.__id__] == @__id > obj = ObjectSpace._id2ref(@__id) > obj = nil unless __verify_weakref_backreference__(obj) > end 60c73 < Kernel::raise RefError, "Invalid Reference - probably recycled", Kernel::caller(2) --- > # Object has been garbage collected. 61a75,76 > Kernel::raise(RefError, "Invalid Reference - probably recycled", Kernel::caller(1)) unless obj > obj 62a78 > 67c83,90 < @@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 68a92,113 > > 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 72c117 < # require 'thread' --- > # require 'thread'