cmd/dlv: print out message with stack trace when breakpoint is hit but has no waiting client (#3632)

* Print out message and dump stack on pause

* Fix test

* Move the logic to debugger layer

* Remove unused fields

* Do not use defer to get state

* move channel to connection

* remove lock on isClosed

* Use mutex

* Remove unwanted changes
This commit is contained in:
Fata Nugraha
2024-06-13 02:31:46 +07:00
committed by GitHub
parent 2ec2e831d6
commit 15a9f9d353
8 changed files with 136 additions and 21 deletions

View File

@ -181,14 +181,23 @@ type Config struct {
}
type connection struct {
mu sync.Mutex
closed bool
mu sync.Mutex
closed bool
closedChan chan struct{}
io.ReadWriteCloser
}
func newConnection(conn io.ReadWriteCloser) *connection {
return &connection{ReadWriteCloser: conn, closedChan: make(chan struct{})}
}
func (c *connection) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if !c.closed {
close(c.closedChan)
}
c.closed = true
return c.ReadWriteCloser.Close()
}
@ -335,7 +344,7 @@ func NewSession(conn io.ReadWriteCloser, config *Config, debugger *debugger.Debu
return &Session{
config: config,
id: sessionCount,
conn: &connection{ReadWriteCloser: conn},
conn: newConnection(conn),
stackFrameHandles: newHandlesMap(),
variableHandles: newVariablesHandlesMap(),
args: defaultArgs,
@ -1366,7 +1375,7 @@ func (s *Session) halt() (*api.DebuggerState, error) {
s.config.log.Debug("halting")
// Only send a halt request if the debuggee is running.
if s.debugger.IsRunning() {
return s.debugger.Command(&api.DebuggerCommand{Name: api.Halt}, nil)
return s.debugger.Command(&api.DebuggerCommand{Name: api.Halt}, nil, nil)
}
s.config.log.Debug("process not running")
return s.debugger.State(false)
@ -2048,7 +2057,7 @@ func (s *Session) stoppedOnBreakpointGoroutineID(state *api.DebuggerState) (int6
// due to an error, so the server is ready to receive new requests.
func (s *Session) stepUntilStopAndNotify(command string, threadId int, granularity dap.SteppingGranularity, allowNextStateChange *syncflag) {
defer allowNextStateChange.raise()
_, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: int64(threadId)}, nil)
_, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: int64(threadId)}, nil, s.conn.closedChan)
if err != nil {
s.config.log.Errorf("Error switching goroutines while stepping: %v", err)
// If we encounter an error, we will have to send a stopped event
@ -2914,7 +2923,7 @@ func (s *Session) doCall(goid, frame int, expr string) (*api.DebuggerState, []*p
Expr: expr,
UnsafeCall: false,
GoroutineID: int64(goid),
}, nil)
}, nil, s.conn.closedChan)
if processExited(state, err) {
s.preTerminatedWG.Wait()
e := &dap.TerminatedEvent{Event: *newEvent("terminated")}
@ -3645,7 +3654,7 @@ func (s *Session) resumeOnce(command string, allowNextStateChange *syncflag) (bo
state, err := s.debugger.State(false)
return false, state, err
}
state, err := s.debugger.Command(&api.DebuggerCommand{Name: command}, asyncSetupDone)
state, err := s.debugger.Command(&api.DebuggerCommand{Name: command}, asyncSetupDone, s.conn.closedChan)
return true, state, err
}