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

Simplify RunLoop() call and add Stop()

This commit is contained in:
Tatsushi Demachi 2014-08-03 00:00:15 +09:00
parent a97a44952e
commit 88c0127fe9
3 changed files with 47 additions and 50 deletions

View File

@ -40,20 +40,18 @@ func main() {
}) })
p.MaxRTT = time.Second p.MaxRTT = time.Second
quit, errch := p.RunLoop() errch := p.RunLoop()
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM) signal.Notify(c, syscall.SIGTERM)
wait := make(chan bool)
loop: loop:
for { for {
select { select {
case <-c: case <-c:
fmt.Println("get interrupted") fmt.Println("get interrupted")
signal.Stop(c) break loop
quit <- wait
case res := <-onRecv: case res := <-onRecv:
if _, ok := results[res.addr.String()]; ok { if _, ok := results[res.addr.String()]; ok {
results[res.addr.String()] = res results[res.addr.String()] = res
@ -69,10 +67,9 @@ loop:
} }
case err := <-errch: case err := <-errch:
fmt.Println("Ping failed: %v", err) fmt.Println("Ping failed: %v", err)
break loop
}
}
signal.Stop(c) signal.Stop(c)
quit <- wait p.Stop()
case <-wait:
break loop;
}
}
} }

View File

@ -72,6 +72,8 @@ 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
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
// interval time of RunLoop() method // interval time of RunLoop() method
@ -88,6 +90,7 @@ func NewPinger() *Pinger {
id: rand.Intn(0xffff), id: rand.Intn(0xffff),
seq: rand.Intn(0xffff), seq: rand.Intn(0xffff),
addrs: make(map[string]*net.IPAddr), addrs: make(map[string]*net.IPAddr),
running: false,
MaxRTT: time.Second, MaxRTT: time.Second,
handlers: make(map[string]interface{}), handlers: make(map[string]interface{}),
Debug: false, Debug: false,
@ -152,7 +155,7 @@ 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, make(chan chan<- bool)) return p.run(true)
} }
// Invode send/receive procedure repeatedly. It sends packets to all hosts which // Invode send/receive procedure repeatedly. It sends packets to all hosts which
@ -161,40 +164,42 @@ func (p *Pinger) Run() error {
// After MaxRTT seconds, it calls "idle" handler, resend packets and wait those // After MaxRTT seconds, it calls "idle" handler, resend packets and wait those
// response. MaxRTT works as an interval time. // response. MaxRTT works as an interval time.
// //
// This is a non-blocking method so immediately returns with channel values. // This is a non-blocking method so immediately returns with channel value.
// If you want to stop sending packets, send a channel value of bool type to it // If you want to stop sending packets, use Stop(). For example,
// and wait for graceful shutdown. For example,
// //
// wait := make(chan bool) // errch := p.RunLoop()
// quit, errch := p.RunLoop()
// ticker := time.NewTicker(time.Millisecond * 250) // ticker := time.NewTicker(time.Millisecond * 250)
// loop:
// for {
// select { // select {
// case err := <-errch: // case err := <-errch:
// log.Fatalf("Ping failed: %v", err) // log.Fatalf("Ping failed: %v", err)
// case <-ticker.C: // case <-ticker.C:
// break
// }
// ticker.Stop() // ticker.Stop()
// quit <- wait // p.Stop()
// case <-wait:
// break loop
// }
// }
// //
// For more detail, please see "cmd/ping/ping.go". // For more detail, please see "cmd/ping/ping.go".
func (p *Pinger) RunLoop() (chan<- chan<- bool, <-chan error) { func (p *Pinger) RunLoop() <-chan error {
quit := make(chan chan<- bool) p.quit = make(chan chan<- bool)
errch := make(chan error) errch := make(chan error)
go func(ch chan<- error) { go func(ch chan<- error) {
err := p.run(false, quit) err := p.run(false)
if err != nil { if err != nil {
ch <- err ch <- err
} }
}(errch) }(errch)
return quit, errch return errch
} }
func (p *Pinger) run(once bool, quit <-chan chan<- bool) error { func (p *Pinger) Stop() {
if p.running {
wait := make(chan bool)
p.quit <- wait
<-wait
}
}
func (p *Pinger) run(once bool) error {
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 {
@ -212,14 +217,13 @@ func (p *Pinger) run(once bool, quit <-chan chan<- 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 = <-quit: case join = <-p.quit:
p.debugln("Run(): <-quit") p.debugln("Run(): <-p.quit")
p.debugln("Run(): stoprecv <- waitjoin")
stoprecv <- waitjoin
break mainloop break mainloop
case <-ticker.C: case <-ticker.C:
if handler, ok := p.handlers["idle"]; ok && handler != nil { if handler, ok := p.handlers["idle"]; ok && handler != nil {
@ -228,8 +232,6 @@ mainloop:
} }
} }
if once || err != nil { if once || err != nil {
p.debugln("Run(): stoprecv <- waitjoin")
stoprecv <- waitjoin
break mainloop break mainloop
} }
p.debugln("Run(): call sendICMP4()") p.debugln("Run(): call sendICMP4()")
@ -240,8 +242,11 @@ mainloop:
} }
} }
p.running = false
ticker.Stop() ticker.Stop()
p.debugln("Run(): stoprecv <- waitjoin")
stoprecv <- waitjoin
p.debugln("Run(): <-waitjoin") p.debugln("Run(): <-waitjoin")
<-waitjoin <-waitjoin
if !once { if !once {

View File

@ -199,21 +199,16 @@ func TestRunLoop(t *testing.T) {
t.Fatalf("Failed to add idle handler: %v", err) t.Fatalf("Failed to add idle handler: %v", err)
} }
wait := make(chan bool) errch := p.RunLoop()
quit, errch := p.RunLoop()
ticker := time.NewTicker(time.Millisecond * 250) ticker := time.NewTicker(time.Millisecond * 250)
loop:
for {
select { select {
case err := <-errch: case err := <-errch:
t.Fatalf("Pinger returns error %v", err) t.Fatalf("Pinger returns error %v", err)
case <-ticker.C: case <-ticker.C:
break
}
ticker.Stop() ticker.Stop()
quit <- wait p.Stop()
case <-wait:
break loop
}
}
if recvCount < 2 { if recvCount < 2 {
t.Fatalf("Pinger receive count less than 2") t.Fatalf("Pinger receive count less than 2")