mirror of
https://github.com/go-delve/delve.git
synced 2025-10-27 20:23:41 +08:00
cmd/dlv: add flag to make headless server accept multiple clients
This commit is contained in:
@ -32,6 +32,8 @@ var (
|
|||||||
Log bool
|
Log bool
|
||||||
// Headless is whether to run without terminal.
|
// Headless is whether to run without terminal.
|
||||||
Headless bool
|
Headless bool
|
||||||
|
// Allows multiple clients to connect to the same server
|
||||||
|
AcceptMulti bool
|
||||||
// Addr is the debugging server listen address.
|
// Addr is the debugging server listen address.
|
||||||
Addr string
|
Addr string
|
||||||
// InitFile is the path to initialization file.
|
// 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().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
|
||||||
rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
|
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(&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(&InitFile, "init", "", "Init file, executed by the terminal client.")
|
||||||
rootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", buildFlagsDefault, "Build flags, to be passed to the compiler.")
|
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,
|
Listener: listener,
|
||||||
ProcessArgs: processArgs,
|
ProcessArgs: processArgs,
|
||||||
AttachPid: attachPid,
|
AttachPid: attachPid,
|
||||||
|
AcceptMulti: AcceptMulti,
|
||||||
}, Log)
|
}, Log)
|
||||||
if err := server.Run(); err != nil {
|
if err := server.Run(); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
|||||||
@ -16,4 +16,7 @@ type Config struct {
|
|||||||
// AttachPid is the PID of an existing process to which the debugger should
|
// AttachPid is the PID of an existing process to which the debugger should
|
||||||
// attach.
|
// attach.
|
||||||
AttachPid int
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ type RPCServer struct {
|
|||||||
config *service.Config
|
config *service.Config
|
||||||
// listener is used to serve HTTP.
|
// listener is used to serve HTTP.
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
// stopChan is used to stop the listener goroutine
|
||||||
|
stopChan chan struct{}
|
||||||
// debugger is a debugger service.
|
// debugger is a debugger service.
|
||||||
debugger *debugger.Debugger
|
debugger *debugger.Debugger
|
||||||
}
|
}
|
||||||
@ -38,13 +40,22 @@ func NewServer(config *service.Config, logEnabled bool) *ServerImpl {
|
|||||||
&RPCServer{
|
&RPCServer{
|
||||||
config: config,
|
config: config,
|
||||||
listener: config.Listener,
|
listener: config.Listener,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop detaches from the debugger and waits for it to stop.
|
// Stop detaches from the debugger and waits for it to stop.
|
||||||
func (s *ServerImpl) Stop(kill bool) error {
|
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
|
// Run starts a debugger and exposes it with an HTTP server. The debugger
|
||||||
@ -60,16 +71,27 @@ func (s *ServerImpl) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
rpcs := grpc.NewServer()
|
||||||
c, err := s.s.listener.Accept()
|
rpcs.Register(s.s)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer s.s.listener.Close()
|
|
||||||
|
|
||||||
rpcs := grpc.NewServer()
|
go func() {
|
||||||
rpcs.Register(s.s)
|
defer s.s.listener.Close()
|
||||||
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user