UI_Base
# File debug-1.4.0/lib/debug/server.rb, line 29
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
# File debug-1.4.0/lib/debug/server.rb, line 40
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
# File debug-1.4.0/lib/debug/server.rb, line 324
def after_fork_parent
# do nothing
end
# File debug-1.4.0/lib/debug/server.rb, line 262
def ask prompt
sock do |s|
s.puts "ask #{Process.pid} #{prompt}"
@q_ans.pop
end
end
# File debug-1.4.0/lib/debug/server.rb, line 85
def cleanup_reader
DEBUGGER__.warn "Disconnected."
@sock = nil
@q_msg.close
@q_msg = nil
@q_ans.close
@q_ans = nil
end
# File debug-1.4.0/lib/debug/server.rb, line 24
def deactivate
@reader_thread.raise Terminate
@reader_thread.join
end
# File debug-1.4.0/lib/debug/server.rb, line 94
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
# File debug-1.4.0/lib/debug/server.rb, line 312
def pause
# $stderr.puts "DEBUG: pause request"
Process.kill(TRAP_SIGNAL, Process.pid)
end
# File debug-1.4.0/lib/debug/server.rb, line 131
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
# File debug-1.4.0/lib/debug/server.rb, line 269
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
# File debug-1.4.0/lib/debug/server.rb, line 317
def quit n
# ignore n
sock do |s|
s.puts "quit"
end
end
# File debug-1.4.0/lib/debug/server.rb, line 291
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
# File debug-1.4.0/lib/debug/server.rb, line 176
def remote?
true
end
# File debug-1.4.0/lib/debug/server.rb, line 208
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
# File debug-1.4.0/lib/debug/server.rb, line 184
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
# File debug-1.4.0/lib/debug/server.rb, line 233
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