Refactor: Use thread-locked goroutine for ptrace ops

Previously either the terminal client or the debugger service would
either lock main goroutine to a thread or provide a locked goroutine to
run _all_ DebuggedProcess functions in. This is unnecessary because only
ptrace functions need to be run from the same thread that originated the
PT_ATTACH request.

Here we use a specific thread-locked goroutine to service any ptrace
request. That goroutine is also responsible for the initial spawning /
attaching of the process, since it must be responsible for the PT_ATTACH
request.
This commit is contained in:
Derek Parker
2015-06-12 23:47:30 -05:00
parent fe23036035
commit e4fc5e32c2
15 changed files with 391 additions and 459 deletions

View File

@ -21,8 +21,6 @@ type RESTServer struct {
listener net.Listener
// debugger is a debugger service.
debugger *debugger.Debugger
// debuggerStopped is used to detect shutdown of the debugger service.
debuggerStopped chan error
}
// Config provides the configuration to start a Debugger and expose it with a
@ -49,9 +47,8 @@ func NewServer(config *Config, logEnabled bool) *RESTServer {
}
return &RESTServer{
config: config,
listener: config.Listener,
debuggerStopped: make(chan error),
config: config,
listener: config.Listener,
}
}
@ -59,22 +56,17 @@ func NewServer(config *Config, logEnabled bool) *RESTServer {
// itself can be stopped with the `detach` API. Run blocks until the HTTP
// server stops.
func (s *RESTServer) Run() error {
var err error
// Create and start the debugger
s.debugger = debugger.New(&debugger.Config{
if s.debugger, err = debugger.New(&debugger.Config{
ProcessArgs: s.config.ProcessArgs,
AttachPid: s.config.AttachPid,
})
go func() {
err := s.debugger.Run()
if err != nil {
log.Printf("debugger stopped with error: %s", err)
}
s.debuggerStopped <- err
}()
}); err != nil {
return err
}
// Set up the HTTP server
container := restful.NewContainer()
ws := new(restful.WebService)
ws.
Path("").
@ -108,11 +100,7 @@ func (s *RESTServer) Run() error {
// Stop detaches from the debugger and waits for it to stop.
func (s *RESTServer) Stop(kill bool) error {
err := s.debugger.Detach(kill)
if err != nil {
return err
}
return <-s.debuggerStopped
return s.debugger.Detach(kill)
}
// writeError writes a simple error response.