beam: more hooks for interactive debugging

This inserts low-level hooks for interactive step-by-step debugging.
Hooks are triggered by setting the *TEST* environment variable.

This is particularly useful for tracking down file descriptor leaks,
double-closing, or other issues which are difficult to debug with
the usual toolbox.

Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)
This commit is contained in:
Solomon Hykes 2014-03-25 10:00:23 -07:00
parent a14c83eca3
commit 3b5c1c4203

View file

@ -9,7 +9,9 @@ import (
) )
func debugCheckpoint(msg string, args ...interface{}) { func debugCheckpoint(msg string, args ...interface{}) {
return if os.Getenv("DEBUG") == "" {
return
}
os.Stdout.Sync() os.Stdout.Sync()
tty,_ := os.OpenFile("/dev/tty", os.O_RDWR, 0700) tty,_ := os.OpenFile("/dev/tty", os.O_RDWR, 0700)
fmt.Fprintf(tty, msg, args...) fmt.Fprintf(tty, msg, args...)
@ -103,6 +105,7 @@ func Receive(conn *net.UnixConn) (rdata []byte, rf *os.File, rerr error) {
// without complicating application code. // without complicating application code.
// //
func SendPipe(conn *net.UnixConn, data []byte) (endpoint *net.UnixConn, err error) { func SendPipe(conn *net.UnixConn, data []byte) (endpoint *net.UnixConn, err error) {
debugCheckpoint("===DEBUG=== SendPipe('%s'). Hit enter to confirm: ", data)
local, remote, err := SocketPair() local, remote, err := SocketPair()
if err != nil { if err != nil {
return nil, err return nil, err
@ -167,7 +170,20 @@ func socketpair() ([2]int, error) {
// not bound to the underlying filesystem. // not bound to the underlying filesystem.
// Messages sent on one end are received on the other, and vice-versa. // Messages sent on one end are received on the other, and vice-versa.
// It is the caller's responsibility to close both ends. // It is the caller's responsibility to close both ends.
func SocketPair() (*os.File, *os.File, error) { func SocketPair() (a *os.File, b *os.File, err error) {
defer func() {
var (
fdA int = -1
fdB int = -1
)
if a != nil {
fdA = int(a.Fd())
}
if b != nil {
fdB = int(b.Fd())
}
debugCheckpoint("===DEBUG=== SocketPair() = [%d-%d]. Hit enter to confirm: ", fdA, fdB)
}()
pair, err := socketpair() pair, err := socketpair()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -176,6 +192,8 @@ func SocketPair() (*os.File, *os.File, error) {
} }
func USocketPair() (*net.UnixConn, *net.UnixConn, error) { func USocketPair() (*net.UnixConn, *net.UnixConn, error) {
debugCheckpoint("===DEBUG=== USocketPair(). Hit enter to confirm: ")
defer debugCheckpoint ("===DEBUG=== USocketPair() returned. Hit enter to confirm ")
a, b, err := SocketPair() a, b, err := SocketPair()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -199,7 +217,10 @@ func USocketPair() (*net.UnixConn, *net.UnixConn, error) {
// returns an error if the file descriptor does not point to a unix socket. // returns an error if the file descriptor does not point to a unix socket.
// This creates a duplicate file descriptor. It's the caller's responsibility // This creates a duplicate file descriptor. It's the caller's responsibility
// to close both. // to close both.
func FdConn(fd int) (*net.UnixConn, error) { func FdConn(fd int) (n*net.UnixConn, err error) {
{
debugCheckpoint("===DEBUG=== FdConn([%d]) = (unknown fd). Hit enter to confirm: ", fd)
}
f := os.NewFile(uintptr(fd), fmt.Sprintf("%d", fd)) f := os.NewFile(uintptr(fd), fmt.Sprintf("%d", fd))
conn, err := net.FileConn(f) conn, err := net.FileConn(f)
if err != nil { if err != nil {