Files
weave-scope/experimental/tracer/ptrace/process.go

100 lines
1.6 KiB
Go

package ptrace
import (
"fmt"
"io/ioutil"
"log"
"strconv"
"sync"
)
type process struct {
sync.Mutex
pid int
detaching bool
detached chan struct{}
tracer *PTracer
threads map[int]*thread
fds map[int]*Fd
}
func newProcess(pid int, tracer *PTracer) *process {
return &process{
pid: pid,
tracer: tracer,
threads: make(map[int]*thread),
fds: make(map[int]*Fd),
detached: make(chan struct{}),
}
}
func (p *process) trace() {
go p.loop()
}
// This doesn't actually guarantees we follow all the threads. Oops.
func (p *process) loop() {
var (
attached int
)
log.Printf("Tracing process %d", p.pid)
for {
ps, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", p.pid))
if err != nil {
log.Printf("ReadDir failed, pid=%d, err=%v", p.pid, err)
return
}
attached = 0
for _, file := range ps {
pid, err := strconv.Atoi(file.Name())
if err != nil {
log.Printf("'%s' is not a pid: %v", file.Name(), err)
attached++
continue
}
p.Lock()
t, ok := p.threads[pid]
if !ok {
t = p.tracer.traceThread(pid, p)
p.threads[pid] = t
}
p.Unlock()
if !t.attached {
continue
}
attached++
}
// When we successfully attach to all threads
// we can be sure to catch new clones, so we
// can quit.
if attached == len(ps) {
break
}
}
log.Printf("Successfully attached to %d threads", attached)
}
func (p *process) newThread(thread *thread) {
p.Lock()
defer p.Unlock()
p.threads[thread.tid] = thread
}
func (p *process) newFd(fd *Fd) error {
_, ok := p.fds[fd.fd]
if ok {
return fmt.Errorf("New fd %d, alread exists!", fd.fd)
}
p.fds[fd.fd] = fd
return nil
}