In Files

  • debug-1.4.0/lib/debug/server.rb

DEBUGGER__::UI_ServerBase

Constants

TRAP_SIGNAL

maybe Windows?

Attributes

reader_thread[R]

Public Class Methods

new() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 9
def initialize
  @sock = @sock_for_fork = nil
  @accept_m = Mutex.new
  @accept_cv = ConditionVariable.new
  @client_addr = nil
  @q_msg = nil
  @q_ans = nil
  @unsent_messages = []
  @width = 80
  @repl = true
  @session = nil
end
            

Public Instance Methods

accept() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 30
def accept
  if @sock_for_fork
    begin
      yield @sock_for_fork, already_connected: true
    ensure
      @sock_for_fork.close
      @sock_for_fork = nil
    end
  end
end
            
activate(session, on_fork: false) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 41
def activate session, on_fork: false
  @session = session
  @reader_thread = Thread.new do
    # An error on this thread should break the system.
    Thread.current.abort_on_exception = true
    Thread.current.name = 'DEBUGGER__::Server::reader'

    accept do |server, already_connected: false|
      DEBUGGER__.warn "Connected."

      @accept_m.synchronize{
        @sock = server
        greeting

        @accept_cv.signal

        # flush unsent messages
        @unsent_messages.each{|m|
          @sock.puts m
        } if @repl
        @unsent_messages.clear

        @q_msg = Queue.new
        @q_ans = Queue.new
      } unless already_connected

      setup_interrupt do
        pause unless already_connected
        process
      end

    rescue Terminate
      raise # should catch at outer scope
    rescue => e
      DEBUGGER__.warn "ReaderThreadError: #{e}"
      pp e.backtrace
    ensure
      cleanup_reader
    end # accept

  rescue Terminate
    # ignore
  end
end
            
after_fork_parent() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 325
def after_fork_parent
  # do nothing
end
            
ask(prompt) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 263
def ask prompt
  sock do |s|
    s.puts "ask #{Process.pid} #{prompt}"
    @q_ans.pop
  end
end
            
cleanup_reader() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 86
def cleanup_reader
  DEBUGGER__.warn "Disconnected."
  @sock = nil
  @q_msg.close
  @q_msg = nil
  @q_ans.close
  @q_ans = nil
end
            
deactivate() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 25
def deactivate
  @reader_thread.raise Terminate
  @reader_thread.join
end
            
greeting() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 95
def greeting
  case g = @sock.gets
  when /^version:\s+(.+)\s+width: (\d+) cookie:\s+(.*)$/
    v, w, c = $1, $2, $3
    # TODO: protocol version
    if v != VERSION
      raise "Incompatible version (#{VERSION} client:#{$1})"
    end

    cookie = CONFIG[:cookie]
    if cookie && cookie != c
      raise "Cookie mismatch (#{$2.inspect} was sent)"
    end

    @width = w.to_i

  when /^Content-Length: (\d+)/
    require_relative 'server_dap'

    raise unless @sock.read(2) == "\r\n"
    self.extend(UI_DAP)
    @repl = false
    dap_setup @sock.read($1.to_i)
  when /^GET \/ HTTP\/1.1/
    require_relative 'server_cdp'

    self.extend(UI_CDP)
    @repl = false
    CONFIG.set_config no_color: true

    @ws_server = UI_CDP::WebSocketServer.new(@sock)
    @ws_server.handshake
  else
    raise "Greeting message error: #{g}"
  end
end
            
pause() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 313
def pause
  # $stderr.puts "DEBUG: pause request"
  Process.kill(TRAP_SIGNAL, Process.pid)
end
            
process() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 132
def process
  while true
    DEBUGGER__.info "sleep IO.select"
    r = IO.select([@sock])
    DEBUGGER__.info "wakeup IO.select"

    line = @session.process_group.sync do
      unless IO.select([@sock], nil, nil, 0)
        DEBUGGER__.info "UI_Server can not read"
        break :can_not_read
      end
      @sock.gets&.chomp.tap{|line|
        DEBUGGER__.info "UI_Server received: #{line}"
      }
    end

    next if line == :can_not_read

    case line
    when /\Apause/
      pause
    when /\Acommand (\d+) (\d+) ?(.+)/
      raise "not in subsession, but received: #{line.inspect}" unless @session.in_subsession?

      if $1.to_i == Process.pid
        @width = $2.to_i
        @q_msg << $3
      else
        raise "pid:#{Process.pid} but get #{line}"
      end
    when /\Aanswer (\d+) (.*)/
      raise "not in subsession, but received: #{line.inspect}" unless @session.in_subsession?

      if $1.to_i == Process.pid
        @q_ans << $2
      else
        raise "pid:#{Process.pid} but get #{line}"
      end
    else
      STDERR.puts "unsupported: #{line}"
      exit!
    end
  end
end
            
puts(str = nil) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 270
def puts str = nil
  case str
  when Array
    enum = str.each
  when String
    enum = str.each_line
  when nil
    enum = [''].each
  end

  sock skip: true do |s|
    enum.each do |line|
      msg = "out #{line.chomp}"
      if s
        s.puts msg
      else
        @unsent_messages << msg
      end
    end
  end
end
            
quit(n) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 318
def quit n
  # ignore n
  sock do |s|
    s.puts "quit"
  end
end
            
readline(prompt) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 292
def readline prompt
  input = (sock do |s|
    if @repl
      raise "not in subsession, but received: #{line.inspect}" unless @session.in_subsession?
      line = "input #{Process.pid}"
      DEBUGGER__.info "send: #{line}"
      s.puts line
    end
    sleep 0.01 until @q_msg
    @q_msg.pop.tap{|msg|
      DEBUGGER__.info "readline: #{msg.inspect}"
    }
  end || 'continue')

  if input.is_a?(String)
    input.strip
  else
    input
  end
end
            
remote?() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 177
def remote?
  true
end
            
setup_interrupt() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 209
def setup_interrupt
  prev_handler = trap(TRAP_SIGNAL) do
    # $stderr.puts "trapped SIGINT"
    ThreadClient.current.on_trap TRAP_SIGNAL

    case prev_handler
    when Proc
      prev_handler.call
    else
      # ignore
    end
  end

  if sigurg_overridden?(prev_handler)
    DEBUGGER__.warn "SIGURG handler is overridden by the debugger."
  end
  yield
ensure
  trap(TRAP_SIGNAL, prev_handler)
end
            
sigurg_overridden?(prev_handler) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 185
def sigurg_overridden? prev_handler
  case prev_handler
  when "SYSTEM_DEFAULT", "DEFAULT"
    false
  when Proc
    if prev_handler.source_location[0] == __FILE__
      false
    else
      true
    end
  else
    true
  end
end
            
sock(skip: false) click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 234
def sock skip: false
  if s = @sock         # already connection
    # ok
  elsif skip == true   # skip process
    no_sock = true
    r = @accept_m.synchronize do
      if @sock
        no_sock = false
      else
        yield nil
      end
    end
    return r if no_sock
  else                 # wait for connection
    until s = @sock
      @accept_m.synchronize{
        unless @sock
          DEBUGGER__.warn "wait for debugger connection..."
          @accept_cv.wait(@accept_m)
        end
      }
    end
  end

  yield s
rescue Errno::EPIPE
  # ignore
end
            
width() click to toggle source
 
               # File debug-1.4.0/lib/debug/server.rb, line 181
def width
  @width
end