tatsushid/go-fastping — pull request #6 by mjibson (2014-11-18 00:13:48+00:00)
Title: Allow shutdown after timeout

If a timeout has occurred, the send to recv in recvICMP would block forever
because no goroutine was receiving on that channel anymore. This leaves
behind 2 goroutines for each timeout: 1 trying to send an recv, and another
waiting for the wait group. Instead, used a buffered channel so that the
sender can send even with no listener. This cleans up the goroutines and
collects the channel.

Test this yourself with the following program:

~~~
package main

import (
"fmt"
"log"
"net"
"net/http"
_ "net/http/pprof"
"os"
"time"

"github.com/tatsushid/go-fastping"
)

func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6611", nil))
}()
p := fastping.NewPinger()
ra, err := net.ResolveIPAddr("ip4:icmp", "localhost")
if err != nil {
fmt.Println(2, err)
os.Exit(1)
}
p.AddIPAddr(ra)
p.MaxRTT = 1
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
fmt.Printf("IP Addr: %s receive, RTT: %v\n", addr.String(), rtt)
}
p.OnIdle = func() {
fmt.Println("finish")
}
err = p.Run()
if err != nil {
fmt.Println(1, err)
}
select {}
}
~~~

Run it and hit [http://localhost:6611/debug/pprof/goroutine?debug=1](http://localhost:6611/debug/pprof/goroutine?debug=1) in your browser to see the left over go routines. Apply this patch and they are gone.