Class: Thread

Inherits:
Object
  • Object
show all
Defined in:
lib/rubinius/kernel/common/thread.rb

Overview

– Be very careful about calling raise in here! Thread has its own raise which, if you’re calling raise, you probably don’t want. Use Kernel.raise to call the proper raise. ++

Defined Under Namespace

Classes: InnerRecursionDetected

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#recursive_objectsObject (readonly)

Returns the value of attribute recursive_objects.



9
10
11
# File 'lib/rubinius/kernel/common/thread.rb', line 9

def recursive_objects
  @recursive_objects
end

Class Method Details

.detect_outermost_recursion(obj, paired_obj = undefined, &block) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rubinius/kernel/common/thread.rb', line 93

def self.detect_outermost_recursion(obj, paired_obj=undefined, &block)
  rec = current.recursive_objects

  if rec[:__detect_outermost_recursion__]
    if detect_recursion(obj, paired_obj, &block)
      raise InnerRecursionDetected.new
    end
    false
  else
    begin
      rec[:__detect_outermost_recursion__] = true

      begin
        detect_recursion(obj, paired_obj, &block)
      rescue InnerRecursionDetected
        return true
      end

      return nil
    ensure
      rec.delete :__detect_outermost_recursion__
    end
  end
end

.detect_recursion(obj, paired_obj = undefined) ⇒ Object

detect_recursion will return if there’s a recursion on obj (or the pair obj+paired_obj). If there is one, it returns true. Otherwise, it will yield once and return false.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rubinius/kernel/common/thread.rb', line 39

def self.detect_recursion(obj, paired_obj=undefined)
  id = obj.object_id
  pair_id = paired_obj.object_id
  objects = current.recursive_objects

  case objects[id]

    # Default case, we haven't seen +obj+ yet, so we add it and run the block.
  when nil
    objects[id] = pair_id
    begin
      yield
    ensure
      objects.delete id
    end

    # We've seen +obj+ before and it's got multiple paired objects associated
    # with it, so check the pair and yield if there is no recursion.
  when Rubinius::LookupTable
    return true if objects[id][pair_id]
    objects[id][pair_id] = true

    begin
      yield
    ensure
      objects[id].delete pair_id
    end

    # We've seen +obj+ with one paired object, so check the stored one for
    # recursion.
    #
    # This promotes the value to a LookupTable since there is another new paired
    # object.
  else
    previous = objects[id]
    return true if previous == pair_id

    objects[id] = Rubinius::LookupTable.new(previous => true, pair_id => true)

    begin
      yield
    ensure
      objects[id] = previous
    end
  end

  false
end

.guarding?(obj) ⇒ Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/rubinius/kernel/common/thread.rb', line 30

def self.guarding?(obj)
  current.recursive_objects[obj.object_id]
end

.recursion_guard(obj) ⇒ Object

Implementation note: ideally, the recursive_objects lookup table would be different per method call. Currently it doesn’t cause problems, but if ever a method :foo calls a method :bar which could recurse back to :foo, it could require making the tables independant.



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rubinius/kernel/common/thread.rb', line 18

def self.recursion_guard(obj)
  id = obj.object_id
  objects = current.recursive_objects
  objects[id] = true

  begin
    yield
  ensure
    objects.delete id
  end
end