1
0
mirror of https://github.com/taigrr/go-fastping synced 2025-01-18 05:03:15 -08:00

Refactor run()

This commit is contained in:
Tatsushi Demachi 2014-08-03 10:31:58 +09:00
parent af91e84187
commit 8187842419

View File

@ -86,7 +86,7 @@ type Pinger struct {
seq int seq int
// key string is IPAddr.String() // key string is IPAddr.String()
addrs map[string]*net.IPAddr addrs map[string]*net.IPAddr
quit chan chan<- bool ctx *context
running bool running bool
// Number of (nano,milli)seconds of an idle timeout. Once it passed, // Number of (nano,milli)seconds of an idle timeout. Once it passed,
// the library calls an idle callback function. It is also used for an // the library calls an idle callback function. It is also used for an
@ -169,7 +169,9 @@ func (p *Pinger) AddHandler(event string, handler interface{}) error {
// an error value. It means it blocks until MaxRTT seconds passed. For the // an error value. It means it blocks until MaxRTT seconds passed. For the
// purpose of sending/receiving packets over and over, use RunLoop(). // purpose of sending/receiving packets over and over, use RunLoop().
func (p *Pinger) Run() error { func (p *Pinger) Run() error {
return p.run(true) p.ctx = newContext()
p.run(true)
return p.ctx.err
} }
// Invode send/receive procedure repeatedly. It sends packets to all hosts which // Invode send/receive procedure repeatedly. It sends packets to all hosts which
@ -194,34 +196,35 @@ func (p *Pinger) Run() error {
// //
// For more detail, please see "cmd/ping/ping.go". // For more detail, please see "cmd/ping/ping.go".
func (p *Pinger) RunLoop() <-chan error { func (p *Pinger) RunLoop() <-chan error {
p.quit = make(chan chan<- bool) p.ctx = newContext()
errch := make(chan error) errch := make(chan error)
go func(ch chan<- error) { go func(ch chan<- error) {
err := p.run(false) p.run(false)
if err != nil { if p.ctx.err != nil {
ch <- err ch <- p.ctx.err
} }
}(errch) }(errch)
return errch return errch
} }
func (p *Pinger) Stop() { func (p *Pinger) Stop() {
if p.running { p.debugln("Stop(): close(p.ctx.stop)")
wait := make(chan bool) close(p.ctx.stop)
p.quit <- wait p.debugln("Stop(): <-p.ctx.done")
<-wait <-p.ctx.done
}
} }
func (p *Pinger) run(once bool) error { func (p *Pinger) run(once bool) {
p.debugln("Run(): Start") p.debugln("Run(): Start")
conn, err := net.ListenIP("ip4:icmp", &net.IPAddr{IP: net.IPv4zero}) conn, err := net.ListenIP("ip4:icmp", &net.IPAddr{IP: net.IPv4zero})
if err != nil { if err != nil {
return err p.ctx.err = err
p.debugln("Run(): close(p.ctx.done)")
close(p.ctx.done)
return
} }
defer conn.Close() defer conn.Close()
var join chan<- bool
recv := make(chan *packet) recv := make(chan *packet)
recvCtx := newContext() recvCtx := newContext()
@ -232,13 +235,12 @@ func (p *Pinger) run(once bool) error {
queue, err := p.sendICMP4(conn) queue, err := p.sendICMP4(conn)
ticker := time.NewTicker(p.MaxRTT) ticker := time.NewTicker(p.MaxRTT)
p.running = true
mainloop: mainloop:
for { for {
select { select {
case join = <-p.quit: case <-p.ctx.stop:
p.debugln("Run(): <-p.quit") p.debugln("Run(): <-p.ctx.stop")
break mainloop break mainloop
case <-recvCtx.done: case <-recvCtx.done:
p.debugln("Run(): <-recvCtx.done") p.debugln("Run(): <-recvCtx.done")
@ -261,19 +263,16 @@ mainloop:
} }
} }
p.running = false
ticker.Stop() ticker.Stop()
p.debugln("Run(): close(recvCtx.stop)") p.debugln("Run(): close(recvCtx.stop)")
close(recvCtx.stop) close(recvCtx.stop)
p.debugln("Run(): <-recvCtx.done") p.debugln("Run(): <-recvCtx.done")
<-recvCtx.done <-recvCtx.done
if !once { p.ctx.err = err
p.debugln("Run(): join <- true") p.debugln("Run(): close(p.ctx.done)")
join <- true close(p.ctx.done)
}
p.debugln("Run(): End") p.debugln("Run(): End")
return err
} }
func (p *Pinger) sendICMP4(conn *net.IPConn) (map[string]*net.IPAddr, error) { func (p *Pinger) sendICMP4(conn *net.IPConn) (map[string]*net.IPAddr, error) {