aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/exp/ogle/event.go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2010-12-03 04:34:57 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2010-12-03 04:34:57 +0000
commit7a9389330e91acc3ed05deac2d198af25d13cf3c (patch)
tree38fe54a4f38ede5d949c915d66191f24a6fe5153 /libgo/go/exp/ogle/event.go
parent1aa6700378e5188a853c018256113ce6e1fb5c05 (diff)
downloadgcc-7a9389330e91acc3ed05deac2d198af25d13cf3c.zip
gcc-7a9389330e91acc3ed05deac2d198af25d13cf3c.tar.gz
gcc-7a9389330e91acc3ed05deac2d198af25d13cf3c.tar.bz2
Add Go frontend, libgo library, and Go testsuite.
gcc/: * gcc.c (default_compilers): Add entry for ".go". * common.opt: Add -static-libgo as a driver option. * doc/install.texi (Configuration): Mention libgo as an option for --enable-shared. Mention go as an option for --enable-languages. * doc/invoke.texi (Overall Options): Mention .go as a file name suffix. Mention go as a -x option. * doc/frontends.texi (G++ and GCC): Mention Go as a supported language. * doc/sourcebuild.texi (Top Level): Mention libgo. * doc/standards.texi (Standards): Add section on Go language. Move references for other languages into their own section. * doc/contrib.texi (Contributors): Mention that I contributed the Go frontend. gcc/testsuite/: * lib/go.exp: New file. * lib/go-dg.exp: New file. * lib/go-torture.exp: New file. * lib/target-supports.exp (check_compile): Match // Go. From-SVN: r167407
Diffstat (limited to 'libgo/go/exp/ogle/event.go')
-rw-r--r--libgo/go/exp/ogle/event.go280
1 files changed, 280 insertions, 0 deletions
diff --git a/libgo/go/exp/ogle/event.go b/libgo/go/exp/ogle/event.go
new file mode 100644
index 0000000..d7092de
--- /dev/null
+++ b/libgo/go/exp/ogle/event.go
@@ -0,0 +1,280 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+ "debug/proc"
+ "fmt"
+ "os"
+)
+
+/*
+ * Hooks and events
+ */
+
+// An EventHandler is a function that takes an event and returns a
+// response to that event and possibly an error. If an event handler
+// returns an error, the process stops and no other handlers for that
+// event are executed.
+type EventHandler func(e Event) (EventAction, os.Error)
+
+// An EventAction is an event handler's response to an event. If all
+// of an event's handlers execute without returning errors, their
+// results are combined as follows: If any handler returned
+// EAContinue, then the process resumes (without returning from
+// WaitStop); otherwise, if any handler returned EAStop, the process
+// remains stopped; otherwise, if all handlers returned EADefault, the
+// process resumes. A handler may return EARemoveSelf bit-wise or'd
+// with any other action to indicate that the handler should be
+// removed from the hook.
+type EventAction int
+
+const (
+ EARemoveSelf EventAction = 0x100
+ EADefault EventAction = iota
+ EAStop
+ EAContinue
+)
+
+// A EventHook allows event handlers to be added and removed.
+type EventHook interface {
+ AddHandler(EventHandler)
+ RemoveHandler(EventHandler)
+ NumHandler() int
+ handle(e Event) (EventAction, os.Error)
+ String() string
+}
+
+// EventHook is almost, but not quite, suitable for user-defined
+// events. If we want user-defined events, make EventHook a struct,
+// special-case adding and removing handlers in breakpoint hooks, and
+// provide a public interface for posting events to hooks.
+
+type Event interface {
+ Process() *Process
+ Goroutine() *Goroutine
+ String() string
+}
+
+type commonHook struct {
+ // Head of handler chain
+ head *handler
+ // Number of non-internal handlers
+ len int
+}
+
+type handler struct {
+ eh EventHandler
+ // True if this handler must be run before user-defined
+ // handlers in order to ensure correctness.
+ internal bool
+ // True if this handler has been removed from the chain.
+ removed bool
+ next *handler
+}
+
+func (h *commonHook) AddHandler(eh EventHandler) {
+ h.addHandler(eh, false)
+}
+
+func (h *commonHook) addHandler(eh EventHandler, internal bool) {
+ // Ensure uniqueness of handlers
+ h.RemoveHandler(eh)
+
+ if !internal {
+ h.len++
+ }
+ // Add internal handlers to the beginning
+ if internal || h.head == nil {
+ h.head = &handler{eh, internal, false, h.head}
+ return
+ }
+ // Add handler after internal handlers
+ // TODO(austin) This should probably go on the end instead
+ prev := h.head
+ for prev.next != nil && prev.internal {
+ prev = prev.next
+ }
+ prev.next = &handler{eh, internal, false, prev.next}
+}
+
+func (h *commonHook) RemoveHandler(eh EventHandler) {
+ plink := &h.head
+ for l := *plink; l != nil; plink, l = &l.next, l.next {
+ if l.eh == eh {
+ if !l.internal {
+ h.len--
+ }
+ l.removed = true
+ *plink = l.next
+ break
+ }
+ }
+}
+
+func (h *commonHook) NumHandler() int { return h.len }
+
+func (h *commonHook) handle(e Event) (EventAction, os.Error) {
+ action := EADefault
+ plink := &h.head
+ for l := *plink; l != nil; plink, l = &l.next, l.next {
+ if l.removed {
+ continue
+ }
+ a, err := l.eh(e)
+ if a&EARemoveSelf == EARemoveSelf {
+ if !l.internal {
+ h.len--
+ }
+ l.removed = true
+ *plink = l.next
+ a &^= EARemoveSelf
+ }
+ if err != nil {
+ return EAStop, err
+ }
+ if a > action {
+ action = a
+ }
+ }
+ return action, nil
+}
+
+type commonEvent struct {
+ // The process of this event
+ p *Process
+ // The goroutine of this event.
+ t *Goroutine
+}
+
+func (e *commonEvent) Process() *Process { return e.p }
+
+func (e *commonEvent) Goroutine() *Goroutine { return e.t }
+
+/*
+ * Standard event handlers
+ */
+
+// EventPrint is a standard event handler that prints events as they
+// occur. It will not cause the process to stop.
+func EventPrint(ev Event) (EventAction, os.Error) {
+ // TODO(austin) Include process name here?
+ fmt.Fprintf(os.Stderr, "*** %v\n", ev.String())
+ return EADefault, nil
+}
+
+// EventStop is a standard event handler that causes the process to stop.
+func EventStop(ev Event) (EventAction, os.Error) {
+ return EAStop, nil
+}
+
+/*
+ * Breakpoints
+ */
+
+type breakpointHook struct {
+ commonHook
+ p *Process
+ pc proc.Word
+}
+
+// A Breakpoint event occurs when a process reaches a particular
+// program counter. When this event is handled, the current goroutine
+// will be the goroutine that reached the program counter.
+type Breakpoint struct {
+ commonEvent
+ osThread proc.Thread
+ pc proc.Word
+}
+
+func (h *breakpointHook) AddHandler(eh EventHandler) {
+ h.addHandler(eh, false)
+}
+
+func (h *breakpointHook) addHandler(eh EventHandler, internal bool) {
+ // We register breakpoint events lazily to avoid holding
+ // references to breakpoints without handlers. Be sure to use
+ // the "canonical" breakpoint if there is one.
+ if cur, ok := h.p.breakpointHooks[h.pc]; ok {
+ h = cur
+ }
+ oldhead := h.head
+ h.commonHook.addHandler(eh, internal)
+ if oldhead == nil && h.head != nil {
+ h.p.proc.AddBreakpoint(h.pc)
+ h.p.breakpointHooks[h.pc] = h
+ }
+}
+
+func (h *breakpointHook) RemoveHandler(eh EventHandler) {
+ oldhead := h.head
+ h.commonHook.RemoveHandler(eh)
+ if oldhead != nil && h.head == nil {
+ h.p.proc.RemoveBreakpoint(h.pc)
+ h.p.breakpointHooks[h.pc] = nil, false
+ }
+}
+
+func (h *breakpointHook) String() string {
+ // TODO(austin) Include process name?
+ // TODO(austin) Use line:pc or at least sym+%#x
+ return fmt.Sprintf("breakpoint at %#x", h.pc)
+}
+
+func (b *Breakpoint) PC() proc.Word { return b.pc }
+
+func (b *Breakpoint) String() string {
+ // TODO(austin) Include process name and goroutine
+ // TODO(austin) Use line:pc or at least sym+%#x
+ return fmt.Sprintf("breakpoint at %#x", b.pc)
+}
+
+/*
+ * Goroutine create/exit
+ */
+
+type goroutineCreateHook struct {
+ commonHook
+}
+
+func (h *goroutineCreateHook) String() string { return "goroutine create" }
+
+// A GoroutineCreate event occurs when a process creates a new
+// goroutine. When this event is handled, the current goroutine will
+// be the newly created goroutine.
+type GoroutineCreate struct {
+ commonEvent
+ parent *Goroutine
+}
+
+// Parent returns the goroutine that created this goroutine. May be
+// nil if this event is the creation of the first goroutine.
+func (e *GoroutineCreate) Parent() *Goroutine { return e.parent }
+
+func (e *GoroutineCreate) String() string {
+ // TODO(austin) Include process name
+ if e.parent == nil {
+ return fmt.Sprintf("%v created", e.t)
+ }
+ return fmt.Sprintf("%v created by %v", e.t, e.parent)
+}
+
+type goroutineExitHook struct {
+ commonHook
+}
+
+func (h *goroutineExitHook) String() string { return "goroutine exit" }
+
+// A GoroutineExit event occurs when a Go goroutine exits.
+type GoroutineExit struct {
+ commonEvent
+}
+
+func (e *GoroutineExit) String() string {
+ // TODO(austin) Include process name
+ //return fmt.Sprintf("%v exited", e.t);
+ // For debugging purposes
+ return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base)
+}