From c277b2715750a46153b2974f66eec84d438f669c Mon Sep 17 00:00:00 2001 From: aarzilli Date: Mon, 1 Feb 2016 11:05:26 +0100 Subject: [PATCH] cmd/dlv: add flag to make headless server accept multiple clients --- cmd/dlv/main.go | 4 ++++ service/config.go | 3 +++ service/rpc/server.go | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/cmd/dlv/main.go b/cmd/dlv/main.go index 0f3f95bf..44bb30ed 100644 --- a/cmd/dlv/main.go +++ b/cmd/dlv/main.go @@ -32,6 +32,8 @@ var ( Log bool // Headless is whether to run without terminal. Headless bool + // Allows multiple clients to connect to the same server + AcceptMulti bool // Addr is the debugging server listen address. Addr string // InitFile is the path to initialization file. @@ -74,6 +76,7 @@ func init() { rootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.") rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.") rootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.") + rootCommand.PersistentFlags().BoolVarP(&AcceptMulti, "accept-multiclient", "", false, "Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate") rootCommand.PersistentFlags().StringVar(&InitFile, "init", "", "Init file, executed by the terminal client.") rootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", buildFlagsDefault, "Build flags, to be passed to the compiler.") @@ -351,6 +354,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config) int { Listener: listener, ProcessArgs: processArgs, AttachPid: attachPid, + AcceptMulti: AcceptMulti, }, Log) if err := server.Run(); err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/service/config.go b/service/config.go index e90398d9..85747385 100644 --- a/service/config.go +++ b/service/config.go @@ -16,4 +16,7 @@ type Config struct { // AttachPid is the PID of an existing process to which the debugger should // attach. AttachPid int + // AcceptMulti configures the server to accept multiple connection + // Note that the server API is not reentrant and clients will have to coordinate + AcceptMulti bool } diff --git a/service/rpc/server.go b/service/rpc/server.go index 62c6399d..81022145 100644 --- a/service/rpc/server.go +++ b/service/rpc/server.go @@ -23,6 +23,8 @@ type RPCServer struct { config *service.Config // listener is used to serve HTTP. listener net.Listener + // stopChan is used to stop the listener goroutine + stopChan chan struct{} // debugger is a debugger service. debugger *debugger.Debugger } @@ -38,13 +40,22 @@ func NewServer(config *service.Config, logEnabled bool) *ServerImpl { &RPCServer{ config: config, listener: config.Listener, + stopChan: make(chan struct{}), }, } } // Stop detaches from the debugger and waits for it to stop. func (s *ServerImpl) Stop(kill bool) error { - return s.s.debugger.Detach(kill) + if s.s.config.AcceptMulti { + close(s.s.stopChan) + s.s.listener.Close() + } + err := s.s.debugger.Detach(kill) + if err != nil { + return err + } + return nil } // Run starts a debugger and exposes it with an HTTP server. The debugger @@ -60,16 +71,27 @@ func (s *ServerImpl) Run() error { return err } + rpcs := grpc.NewServer() + rpcs.Register(s.s) + go func() { - c, err := s.s.listener.Accept() - if err != nil { - panic(err) - } defer s.s.listener.Close() - - rpcs := grpc.NewServer() - rpcs.Register(s.s) - rpcs.ServeCodec(jsonrpc.NewServerCodec(c)) + for { + c, err := s.s.listener.Accept() + if err != nil { + select { + case <-s.s.stopChan: + // We were supposed to exit, do nothing and return + return + default: + panic(err) + } + } + go rpcs.ServeCodec(jsonrpc.NewServerCodec(c)) + if !s.s.config.AcceptMulti { + break + } + } }() return nil } -- GitLab