Class: PuppetDebugServer::DebugSession::FlowControl

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet-debugserver/debug_session/flow_control.rb

Overview

Manages the flags used to control the flow of puppet and Debugger during a debug session.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(debug_session) ⇒ FlowControl

Returns a new instance of FlowControl.

Parameters:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 13

def initialize(debug_session)
  @debug_session = debug_session

  @flag_mutex = Mutex.new
  @flags = {
    start_puppet: false,
    puppet_started: false,
    session_paused: false,
    client_completed_configuration: false,
    session_setup: false,
    terminate: false,
    suppress_log_messages: false
  }

  @run_mode = PuppetDebugServer::DebugSession::PuppetSessionRunMode.new
end

Instance Attribute Details

#run_modePuppetDebugServer::DebugSession::PuppetSessionRunMode (readonly)

What mode the debug session is running in



10
11
12
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 10

def run_mode
  @run_mode
end

Instance Method Details

#assert_flag(flag_name) ⇒ Object

Asserts a flag is set

Parameters:

  • flag_name (Symbol)

    The name of the flag



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 54

def assert_flag(flag_name)
  @flag_mutex.synchronize do
    @flags[flag_name] = true
    PuppetDebugServer.log_message(:debug, "Asserting flag #{flag_name} is true")
    # Any custom logic for when flags are asserted
    # rubocop:disable Style/MultipleComparison, Style/SoleNestedConditional This is faster and doesn't require creation of an array
    if flag_name == :client_completed_configuration || flag_name == :session_setup
      # If the client_completed_configuration and session_setup flag are asserted but the session isn't active yet
      # assert the flag start_puppet so puppet can start in the main thread.
      if !@flags[:puppet_started] && @flags[:client_completed_configuration] && @flags[:session_setup]
        PuppetDebugServer.log_message(:debug, 'Asserting flag start_puppet is true')
        @flags[:start_puppet] = true
      end
    end
    @terminate_flag = true if flag_name == :terminate
  end
end

#continue!Object

Continues a paused debug session



133
134
135
136
137
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 133

def continue!
  run_mode.run!
  @debug_session.puppet_session_state.saved.clear!
  unassert_flag(:session_paused)
end

#flag?(flag_name) ⇒ Boolean

Returns which flags are set.

Available flags :start_puppet Indicates the main thread can start running Puppet and begin the debug session :puppet_started Indicates the main thread has started running puppet and debug session is now active :session_paused Indicates that the debug session has hit a breakpoint and is currently paused :client_completed_configuration The debug client has completed it’s configuration :session_setup This debug session has been setup ready to start :terminate Indicates that all threads and wait processes should terminate :suppress_log_messages Indicates that Puppet log messages should not be sent to the client

Parameters:

  • flag_name (Symbol)

    The name of the flag

Returns:

  • (Boolean)

    Whether the flag is set



43
44
45
46
47
48
49
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 43

def flag?(flag_name)
  result = false
  @flag_mutex.synchronize do
    result = @flags[flag_name]
  end
  result.nil? ? false : result
end

#next!Object

Next steps through a paused debug session



140
141
142
143
144
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 140

def next!
  run_mode.next!(@debug_session.puppet_session_state.saved.pops_depth_level)
  @debug_session.puppet_session_state.saved.clear!
  unassert_flag(:session_paused)
end

#raise_stopped_event_and_wait(reason, description, text, session_state) ⇒ Object

Raises a stopped event to the Debug Client and waits for the debug session to continue.

Parameters:

  • reason (String)

    The reason for the event. Values: ‘step’, ‘breakpoint’, ‘exception’, ‘pause’, ‘entry’, ‘goto’, ‘function breakpoint’, ‘data breakpoint’.

  • description (String)

    The full reason for the event, e.g. ‘Paused on exception’. This string is shown in the UI as is and must be translated.

  • text (String)

    Additional information. E.g. if reason is ‘exception’, text contains the exception name. This string is shown in the UI.

  • session_state (Hash)

    Additional information about the puppet state when the event is raised. See PuppetSessionState::Saved.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 113

def raise_stopped_event_and_wait(reason, description, text, session_state)
  # Signal a stop event
  assert_flag(:session_paused)

  # Save the state so when the client queries us, we can respond.
  @debug_session.puppet_session_state.saved.update!(session_state)

  @debug_session.send_stopped_event(
    reason,
    'description' => description,
    'text' => text,
    'threadId' => @debug_session.puppet_thread_id
  )

  # Spin-wait for the session to be unpaused...
  # TODO - Could be better. Semaphore maybe?
  sleep(0.5) while flag?(:session_paused) && !terminate?
end

#session_active?Boolean

Whether the debug session has started.

Returns:

  • (Boolean)

    Returns true if the debug session has started.



96
97
98
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 96

def session_active?
  flag?(:puppet_started)
end

#session_paused?Boolean

Whether the debug session is paused due to breakpoints.

Returns:

  • (Boolean)

    Returns true if the debug session is paused.



103
104
105
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 103

def session_paused?
  flag?(:session_paused)
end

#step_in!Object

Steps into a paused debug session



147
148
149
150
151
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 147

def step_in!
  run_mode.step_in!
  @debug_session.puppet_session_state.saved.clear!
  unassert_flag(:session_paused)
end

#step_out!Object

Steps out of a paused debug session



154
155
156
157
158
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 154

def step_out!
  run_mode.step_out!(@debug_session.puppet_session_state.saved.pops_depth_level)
  @debug_session.puppet_session_state.saved.clear!
  unassert_flag(:session_paused)
end

#terminate?Boolean

The terminate flag will be queried quite often during spin-wait cycles and it’s basically immutable (i.e. Once set it can not be unset). So to help speed up access just treat it as a normal boolean. This can also stop any deadlocks.

Returns:

  • (Boolean)

    Whether the debug session should be terminating.



89
90
91
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 89

def terminate?
  @terminate_flag
end

#unassert_flag(flag_name) ⇒ Object

Removes/unasserts a flag

Parameters:

  • flag_name (Symbol)

    The name of the flag



76
77
78
79
80
81
82
83
# File 'lib/puppet-debugserver/debug_session/flow_control.rb', line 76

def unassert_flag(flag_name)
  return if flag_name == :terminate # Can never unset the terminate flag

  @flag_mutex.synchronize do
    @flags[flag_name] = false
    PuppetDebugServer.log_message(:debug, "Unasserting flag #{flag_name} is true")
  end
end