Class: ThreadWeaver::ControllableThread
- Inherits:
-
Thread
- Object
- Thread
- ThreadWeaver::ControllableThread
- Extended by:
- T::Sig
- Defined in:
- lib/thread_weaver/controllable_thread.rb
Instance Attribute Summary collapse
-
#last_trace_point_summary ⇒ Object
readonly
Returns the value of attribute last_trace_point_summary.
Instance Method Summary collapse
- #handle_trace_point(tp) ⇒ Object
-
#initialize(context, name:, &blk) ⇒ ControllableThread
constructor
A new instance of ControllableThread.
- #join ⇒ Object
- #next ⇒ Object
- #release ⇒ Object
- #set_and_wait_for_next_instruction(instruction) ⇒ Object
- #set_next_instruction(instruction) ⇒ Object
- #wait_until_next_instruction_complete ⇒ Object
Constructor Details
#initialize(context, name:, &blk) ⇒ ControllableThread
Returns a new instance of ControllableThread.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/thread_weaver/controllable_thread.rb', line 15 def initialize(context, name:, &blk) @waiting = T.let(false, T::Boolean) @execution_counter = T.let(-1, Integer) @last_trace_point_summary = T.let("<no traces detected>", String) @line_counts_by_class = T.let({}, T::Hash[Module, Integer]) @current_instruction = T.let(PauseAtThreadStart.new, ThreadInstruction) self.name = name self.report_on_exception = false super do tracer = TracePoint.new(:line, :call, :return, :b_call, :b_return, :thread_begin, :thread_end, :c_call, :c_return) { |tp| current_thread = Thread.current if current_thread == self current_thread.handle_trace_point(tp) end } handle_thread_start tracer.enable blk.call(context) handle_thread_end ensure tracer&.disable end wait_until_next_instruction_complete end |
Instance Attribute Details
#last_trace_point_summary ⇒ Object (readonly)
Returns the value of attribute last_trace_point_summary.
10 11 12 |
# File 'lib/thread_weaver/controllable_thread.rb', line 10 def last_trace_point_summary @last_trace_point_summary end |
Instance Method Details
#handle_trace_point(tp) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/thread_weaver/controllable_thread.rb', line 85 def handle_trace_point(tp) event = T.let(tp.event, Symbol) klass = T.let(tp.defined_class, T.nilable(Module)) path = T.let(tp.path, T.nilable(String)) line = T.let(tp.lineno, T.nilable(Integer)) method_name = T.let(tp.method_id, T.nilable(Symbol)) @last_trace_point_summary = "#{event} #{klass}##{method_name} #{path}#L#{line}" if klass current_count = @line_counts_by_class.fetch(klass, 0) @line_counts_by_class[klass] = (current_count + 1) end case @current_instruction when PauseAtThreadStart if event == :thread_begin wait_until_released end when ContinueToThreadEnd # do nothing when PauseWhenLineCount current_count = @current_instruction.target_classes.map { |klass| @line_counts_by_class.fetch(klass, 0) }.sum required_count = @current_instruction.count if required_count == current_count wait_until_released end when PauseAtMethodCall if @current_instruction.klass == klass && @current_instruction.method_name == method_name wait_until_released end when PauseAtMethodReturn if @current_instruction.klass == klass && @current_instruction.method_name == method_name wait_until_released end when PauseAtSourceLine if path&.end_with?(@current_instruction.path_suffix) && @current_instruction.line == line wait_until_released end else T.absurd(@current_instruction) end end |
#join ⇒ Object
130 131 132 133 134 135 136 |
# File 'lib/thread_weaver/controllable_thread.rb', line 130 def join while alive? release do_nothing end super() end |
#next ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/thread_weaver/controllable_thread.rb', line 58 def next assert_self_is_not_current_thread case @current_instruction when PauseWhenLineCount, PauseAtSourceLine set_next_instruction( @current_instruction.next ) else raise "Next is only supported when paused on a #{PauseWhenLineCount.name} or a #{PauseAtSourceLine} instruction " end end |
#release ⇒ Object
51 52 53 54 55 |
# File 'lib/thread_weaver/controllable_thread.rb', line 51 def release assert_self_is_not_current_thread @waiting = false end |
#set_and_wait_for_next_instruction(instruction) ⇒ Object
79 80 81 82 |
# File 'lib/thread_weaver/controllable_thread.rb', line 79 def set_and_wait_for_next_instruction(instruction) set_next_instruction(instruction) wait_until_next_instruction_complete end |
#set_next_instruction(instruction) ⇒ Object
72 73 74 75 76 |
# File 'lib/thread_weaver/controllable_thread.rb', line 72 def set_next_instruction(instruction) assert_self_is_not_current_thread @current_instruction = instruction release end |
#wait_until_next_instruction_complete ⇒ Object
44 45 46 47 48 |
# File 'lib/thread_weaver/controllable_thread.rb', line 44 def wait_until_next_instruction_complete assert_self_is_not_current_thread do_nothing while alive? && !@waiting end |