s/Thread/Goroutine/

R=rsc
APPROVED=rsc
DELTA=328  (112 added, 110 deleted, 106 changed)
OCL=34356
CL=34356
This commit is contained in:
Austin Clements 2009-09-03 17:41:25 -07:00
parent 920c6106ca
commit 05522cd51e
3 changed files with 110 additions and 108 deletions

View File

@ -54,7 +54,7 @@ type EventHook interface {
type Event interface { type Event interface {
Process() *Process; Process() *Process;
Thread() *Thread; Goroutine() *Goroutine;
String() string; String() string;
} }
@ -147,15 +147,15 @@ func (h *commonHook) handle(e Event) (EventAction, os.Error) {
type commonEvent struct { type commonEvent struct {
// The process of this event // The process of this event
p *Process; p *Process;
// The thread of this event. // The goroutine of this event.
t *Thread; t *Goroutine;
} }
func (e *commonEvent) Process() *Process { func (e *commonEvent) Process() *Process {
return e.p; return e.p;
} }
func (e *commonEvent) Thread() *Thread { func (e *commonEvent) Goroutine() *Goroutine {
return e.t; return e.t;
} }
@ -187,8 +187,8 @@ type breakpointHook struct {
} }
// A Breakpoint event occurs when a process reaches a particular // A Breakpoint event occurs when a process reaches a particular
// program counter. When this event is handled, the current thread // program counter. When this event is handled, the current goroutine
// will be the thread that reached the program counter. // will be the goroutine that reached the program counter.
type Breakpoint struct { type Breakpoint struct {
commonEvent; commonEvent;
osThread ptrace.Thread; osThread ptrace.Thread;
@ -234,38 +234,38 @@ func (b *Breakpoint) PC() ptrace.Word {
} }
func (b *Breakpoint) String() string { func (b *Breakpoint) String() string {
// TODO(austin) Include process name and thread // TODO(austin) Include process name and goroutine
// TODO(austin) Use line:pc or at least sym+%#x // TODO(austin) Use line:pc or at least sym+%#x
return fmt.Sprintf("breakpoint at %#x", b.pc); return fmt.Sprintf("breakpoint at %#x", b.pc);
} }
/* /*
* Thread create/exit * Goroutine create/exit
*/ */
type threadCreateHook struct { type goroutineCreateHook struct {
commonHook; commonHook;
} }
func (h *threadCreateHook) String() string { func (h *goroutineCreateHook) String() string {
return "thread create"; return "goroutine create";
} }
// A ThreadCreate event occurs when a process creates a new Go thread. // A GoroutineCreate event occurs when a process creates a new
// When this event is handled, the current thread will be the newly // goroutine. When this event is handled, the current goroutine will
// created thread. // be the newly created goroutine.
type ThreadCreate struct { type GoroutineCreate struct {
commonEvent; commonEvent;
parent *Thread; parent *Goroutine;
} }
// Parent returns the thread that created this thread. May be nil if // Parent returns the goroutine that created this goroutine. May be
// this event is the creation of the first thread. // nil if this event is the creation of the first goroutine.
func (e *ThreadCreate) Parent() *Thread { func (e *GoroutineCreate) Parent() *Goroutine {
return e.parent; return e.parent;
} }
func (e *ThreadCreate) String() string { func (e *GoroutineCreate) String() string {
// TODO(austin) Include process name // TODO(austin) Include process name
if e.parent == nil { if e.parent == nil {
return fmt.Sprintf("%v created", e.t); return fmt.Sprintf("%v created", e.t);
@ -273,22 +273,22 @@ func (e *ThreadCreate) String() string {
return fmt.Sprintf("%v created by %v", e.t, e.parent); return fmt.Sprintf("%v created by %v", e.t, e.parent);
} }
type threadExitHook struct { type goroutineExitHook struct {
commonHook; commonHook;
} }
func (h *threadExitHook) String() string { func (h *goroutineExitHook) String() string {
return "thread exit"; return "goroutine exit";
} }
// A ThreadExit event occurs when a Go thread exits. // A GoroutineExit event occurs when a Go goroutine exits.
type ThreadExit struct { type GoroutineExit struct {
commonEvent; commonEvent;
} }
func (e *ThreadExit) String() string { func (e *GoroutineExit) String() string {
// TODO(austin) Include process name // TODO(austin) Include process name
//return fmt.Sprintf("%v exited", e.t); //return fmt.Sprintf("%v exited", e.t);
// For debugging purposes // For debugging purposes
return fmt.Sprintf("thread %#x exited", e.t.g.addr().base); return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base);
} }

View File

@ -10,27 +10,28 @@ import (
"ptrace"; "ptrace";
) )
// A Thread represents a Go thread. // A Goroutine represents a goroutine in a remote process.
type Thread struct { type Goroutine struct {
g remoteStruct; g remoteStruct;
frame *Frame; frame *Frame;
dead bool; dead bool;
} }
func (t *Thread) String() string { func (t *Goroutine) String() string {
if t.dead { if t.dead {
return "<dead thread>"; return "<dead thread>";
} }
// TODO(austin) Give threads friendly ID's // TODO(austin) Give threads friendly ID's, possibly including
// the name of the entry function.
return fmt.Sprintf("thread %#x", t.g.addr().base); return fmt.Sprintf("thread %#x", t.g.addr().base);
} }
// isG0 returns true if this thread if the internal idle thread // isG0 returns true if this thread if the internal idle thread
func (t *Thread) isG0() bool { func (t *Goroutine) isG0() bool {
return t.g.addr().base == t.g.r.p.sys.g0.addr().base; return t.g.addr().base == t.g.r.p.sys.g0.addr().base;
} }
func (t *Thread) resetFrame() { func (t *Goroutine) resetFrame() {
// TODO(austin) NewFrame can abort // TODO(austin) NewFrame can abort
// TODO(austin) Reuse any live part of the current frame stack // TODO(austin) Reuse any live part of the current frame stack
// so existing references to Frame's keep working. // so existing references to Frame's keep working.
@ -38,7 +39,7 @@ func (t *Thread) resetFrame() {
} }
// Out selects the caller frame of the current frame. // Out selects the caller frame of the current frame.
func (t *Thread) Out() os.Error { func (t *Goroutine) Out() os.Error {
// TODO(austin) Outer can abort // TODO(austin) Outer can abort
f := t.frame.Outer(); f := t.frame.Outer();
if f != nil { if f != nil {
@ -48,7 +49,7 @@ func (t *Thread) Out() os.Error {
} }
// In selects the frame called by the current frame. // In selects the frame called by the current frame.
func (t *Thread) In() os.Error { func (t *Goroutine) In() os.Error {
f := t.frame.Inner(); f := t.frame.Inner();
if f != nil { if f != nil {
t.frame = f; t.frame = f;
@ -69,24 +70,24 @@ func readylockedBP(ev Event) (EventAction, os.Error) {
sp := regs.SP(); sp := regs.SP();
addr := sp + ptrace.Word(p.PtrSize()); addr := sp + ptrace.Word(p.PtrSize());
arg := remotePtr{remote{addr, p}, p.runtime.G}; arg := remotePtr{remote{addr, p}, p.runtime.G};
g := arg.Get(); gp := arg.Get();
if g == nil { if gp == nil {
return EAStop, UnknownThread{b.osThread, 0}; return EAStop, UnknownGoroutine{b.osThread, 0};
} }
gs := g.(remoteStruct); gs := gp.(remoteStruct);
t := &Thread{gs, nil, false}; g := &Goroutine{gs, nil, false};
p.threads[gs.addr().base] = t; p.goroutines[gs.addr().base] = g;
// Enqueue thread creation event // Enqueue goroutine creation event
parent := b.Thread(); parent := b.Goroutine();
if parent.isG0() { if parent.isG0() {
parent = nil; parent = nil;
} }
p.postEvent(&ThreadCreate{commonEvent{p, t}, parent}); p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent});
// If we don't have any thread selected, select this one // If we don't have any thread selected, select this one
if p.curThread == nil { if p.curGoroutine == nil {
p.curThread = t; p.curGoroutine = g;
} }
return EADefault, nil; return EADefault, nil;
@ -96,18 +97,18 @@ func goexitBP(ev Event) (EventAction, os.Error) {
b := ev.(*Breakpoint); b := ev.(*Breakpoint);
p := b.Process(); p := b.Process();
t := b.Thread(); g := b.Goroutine();
t.dead = true; g.dead = true;
addr := t.g.addr().base; addr := g.g.addr().base;
p.threads[addr] = nil, false; p.goroutines[addr] = nil, false;
// Enqueue thread exit event // Enqueue thread exit event
p.postEvent(&ThreadExit{commonEvent{p, t}}); p.postEvent(&GoroutineExit{commonEvent{p, g}});
// If we just exited our selected thread, selected another // If we just exited our selected goroutine, selected another
if p.curThread == t { if p.curGoroutine == g {
p.selectSomeThread(); p.selectSomeGoroutine();
} }
return EADefault, nil; return EADefault, nil;

View File

@ -39,23 +39,24 @@ func (e ProcessNotStopped) String() string {
return "process not stopped"; return "process not stopped";
} }
// An UnknownThread error is an internal error representing an // An UnknownGoroutine error is an internal error representing an
// unrecognized G structure pointer. // unrecognized G structure pointer.
type UnknownThread struct { type UnknownGoroutine struct {
OSThread ptrace.Thread; OSThread ptrace.Thread;
GoThread ptrace.Word; Goroutine ptrace.Word;
} }
func (e UnknownThread) String() string { func (e UnknownGoroutine) String() string {
return fmt.Sprintf("internal error: unknown thread (G %#x)", e.GoThread); return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine);
} }
// A NoCurrentThread error occurs when no thread is currently selected // A NoCurrentGoroutine error occurs when no goroutine is currently
// in a process (or when there are no threads in a process). // selected in a process (or when there are no goroutines in a
type NoCurrentThread struct {} // process).
type NoCurrentGoroutine struct {}
func (e NoCurrentThread) String() string { func (e NoCurrentGoroutine) String() string {
return "no current thread"; return "no current goroutine";
} }
// A Process represents a remote attached process. // A Process represents a remote attached process.
@ -92,14 +93,14 @@ type Process struct {
// Event hooks // Event hooks
breakpointHooks map[ptrace.Word] *breakpointHook; breakpointHooks map[ptrace.Word] *breakpointHook;
threadCreateHook *threadCreateHook; goroutineCreateHook *goroutineCreateHook;
threadExitHook *threadExitHook; goroutineExitHook *goroutineExitHook;
// Current thread, or nil if there are no threads // Current goroutine, or nil if there are no goroutines
curThread *Thread; curGoroutine *Goroutine;
// Threads by the address of their G structure // Goroutines by the address of their G structure
threads map[ptrace.Word] *Thread; goroutines map[ptrace.Word] *Goroutine;
} }
/* /*
@ -115,9 +116,9 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
syms: syms, syms: syms,
types: make(map[ptrace.Word] *remoteType), types: make(map[ptrace.Word] *remoteType),
breakpointHooks: make(map[ptrace.Word] *breakpointHook), breakpointHooks: make(map[ptrace.Word] *breakpointHook),
threadCreateHook: new(threadCreateHook), goroutineCreateHook: new(goroutineCreateHook),
threadExitHook: new(threadExitHook), goroutineExitHook: new(goroutineExitHook),
threads: make(map[ptrace.Word] *Thread), goroutines: make(map[ptrace.Word] *Goroutine),
}; };
// Fill in remote runtime // Fill in remote runtime
@ -134,18 +135,18 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
return nil, FormatError("failed to find runtime symbol 'sys.goexit'"); return nil, FormatError("failed to find runtime symbol 'sys.goexit'");
} }
// Get current threads // Get current goroutines
p.threads[p.sys.g0.addr().base] = &Thread{p.sys.g0, nil, false}; p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false};
g := p.sys.allg.Get(); g := p.sys.allg.Get();
for g != nil { for g != nil {
gs := g.(remoteStruct); gs := g.(remoteStruct);
fmt.Printf("*** Found thread at %#x\n", gs.addr().base); fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base);
p.threads[gs.addr().base] = &Thread{gs, nil, false}; p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false};
g = gs.Field(p.f.G.Alllink).(remotePtr).Get(); g = gs.Field(p.f.G.Alllink).(remotePtr).Get();
} }
p.selectSomeThread(); p.selectSomeGoroutine();
// Create internal breakpoints to catch new and exited threads // Create internal breakpoints to catch new and exited goroutines
p.OnBreakpoint(ptrace.Word(p.sys.newprocreadylocked.Entry())).(*breakpointHook).addHandler(readylockedBP, true); p.OnBreakpoint(ptrace.Word(p.sys.newprocreadylocked.Entry())).(*breakpointHook).addHandler(readylockedBP, true);
p.OnBreakpoint(ptrace.Word(p.sys.goexit.Entry())).(*breakpointHook).addHandler(goexitBP, true); p.OnBreakpoint(ptrace.Word(p.sys.goexit.Entry())).(*breakpointHook).addHandler(goexitBP, true);
@ -233,13 +234,13 @@ func (p *Process) bootstrap() {
} }
} }
func (p *Process) selectSomeThread() { func (p *Process) selectSomeGoroutine() {
// Once we have friendly thread ID's, there might be a more // Once we have friendly goroutine ID's, there might be a more
// reasonable behavior for this. // reasonable behavior for this.
p.curThread = nil; p.curGoroutine = nil;
for _, t := range p.threads { for _, t := range p.goroutines {
if !t.isG0() { if !t.isG0() {
p.curThread = t; p.curGoroutine = t;
return; return;
} }
} }
@ -299,26 +300,26 @@ func (p *Process) OnBreakpoint(pc ptrace.Word) EventHook {
return &breakpointHook{commonHook{nil, 0}, p, pc}; return &breakpointHook{commonHook{nil, 0}, p, pc};
} }
// OnThreadCreate returns the hook that is run when a Go thread is created. // OnGoroutineCreate returns the hook that is run when a goroutine is created.
func (p *Process) OnThreadCreate() EventHook { func (p *Process) OnGoroutineCreate() EventHook {
return p.threadCreateHook; return p.goroutineCreateHook;
} }
// OnThreadExit returns the hook // OnGoroutineExit returns the hook that is run when a goroutine exits.
func (p *Process) OnThreadExit() EventHook { func (p *Process) OnGoroutineExit() EventHook {
return p.threadExitHook; return p.goroutineExitHook;
} }
// osThreadToThread looks up the Go thread running on an OS thread. // osThreadToGoroutine looks up the goroutine running on an OS thread.
func (p *Process) osThreadToThread(t ptrace.Thread) (*Thread, os.Error) { func (p *Process) osThreadToGoroutine(t ptrace.Thread) (*Goroutine, os.Error) {
regs, err := t.Regs(); regs, err := t.Regs();
if err != nil { if err != nil {
return nil, err; return nil, err;
} }
g := p.G(regs); g := p.G(regs);
gt, ok := p.threads[g]; gt, ok := p.goroutines[g];
if !ok { if !ok {
return nil, UnknownThread{t, g}; return nil, UnknownGoroutine{t, g};
} }
return gt, nil; return gt, nil;
} }
@ -347,7 +348,7 @@ func (p *Process) causesToEvents() ([]Event, os.Error) {
if c, err := t.Stopped(); err == nil { if c, err := t.Stopped(); err == nil {
switch c := c.(type) { switch c := c.(type) {
case ptrace.Breakpoint: case ptrace.Breakpoint:
gt, err := p.osThreadToThread(t); gt, err := p.osThreadToGoroutine(t);
if err != nil { if err != nil {
return nil, err; return nil, err;
} }
@ -416,15 +417,15 @@ func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
if !ok { if !ok {
break; break;
} }
p.curThread = ev.Thread(); p.curGoroutine = ev.Goroutine();
action, err = hook.handle(ev); action, err = hook.handle(ev);
case *ThreadCreate: case *GoroutineCreate:
p.curThread = ev.Thread(); p.curGoroutine = ev.Goroutine();
action, err = p.threadCreateHook.handle(ev); action, err = p.goroutineCreateHook.handle(ev);
case *ThreadExit: case *GoroutineExit:
action, err = p.threadExitHook.handle(ev); action, err = p.goroutineExitHook.handle(ev);
default: default:
log.Crashf("Unknown event type %T in queue", p.event); log.Crashf("Unknown event type %T in queue", p.event);
@ -480,7 +481,7 @@ func (p *Process) ContWait() os.Error {
if err != nil { if err != nil {
return err; return err;
} }
for _, t := range p.threads { for _, t := range p.goroutines {
t.resetFrame(); t.resetFrame();
} }
p.pending, err = p.causesToEvents(); p.pending, err = p.causesToEvents();
@ -493,16 +494,16 @@ func (p *Process) ContWait() os.Error {
// Out selects the caller frame of the current frame. // Out selects the caller frame of the current frame.
func (p *Process) Out() os.Error { func (p *Process) Out() os.Error {
if p.curThread == nil { if p.curGoroutine == nil {
return NoCurrentThread{}; return NoCurrentGoroutine{};
} }
return p.curThread.Out(); return p.curGoroutine.Out();
} }
// In selects the frame called by the current frame. // In selects the frame called by the current frame.
func (p *Process) In() os.Error { func (p *Process) In() os.Error {
if p.curThread == nil { if p.curGoroutine == nil {
return NoCurrentThread{}; return NoCurrentGoroutine{};
} }
return p.curThread.In(); return p.curGoroutine.In();
} }