Close channel to signal goroutines to quit and waitgroup to confirm that they have

This commit is contained in:
alsm 2014-05-02 23:20:51 +01:00
parent 50d8ba24ee
commit f27b0b53e2
2 changed files with 28 additions and 40 deletions

35
irc.go
View File

@ -37,12 +37,12 @@ const (
// Read data from a connection. To be used as a goroutine. // Read data from a connection. To be used as a goroutine.
func (irc *Connection) readLoop() { func (irc *Connection) readLoop() {
defer irc.Done()
br := bufio.NewReaderSize(irc.socket, 512) br := bufio.NewReaderSize(irc.socket, 512)
for { for {
select { select {
case <-irc.endread: case <-irc.end:
irc.readerExit <- true
return return
default: default:
// Set a read deadline based on the combined timeout and ping frequency // Set a read deadline based on the combined timeout and ping frequency
@ -97,21 +97,19 @@ func (irc *Connection) readLoop() {
irc.RunCallbacks(event) irc.RunCallbacks(event)
} }
} }
return
irc.readerExit <- true
} }
// Loop to write to a connection. To be used as a goroutine. // Loop to write to a connection. To be used as a goroutine.
func (irc *Connection) writeLoop() { func (irc *Connection) writeLoop() {
defer irc.Done()
for { for {
select { select {
case <-irc.endwrite: case <-irc.end:
irc.writerExit <- true
return return
default: default:
b, ok := <-irc.pwrite b, ok := <-irc.pwrite
if !ok || b == "" || irc.socket == nil { if !ok || b == "" || irc.socket == nil {
irc.writerExit <- true
return return
} }
@ -130,17 +128,17 @@ func (irc *Connection) writeLoop() {
if err != nil { if err != nil {
irc.Error <- err irc.Error <- err
irc.writerExit <- true
return return
} }
} }
} }
irc.writerExit <- true return
} }
// Pings the server if we have not received any messages for 5 minutes // Pings the server if we have not received any messages for 5 minutes
// to keep the connection alive. To be used as a goroutine. // to keep the connection alive. To be used as a goroutine.
func (irc *Connection) pingLoop() { func (irc *Connection) pingLoop() {
defer irc.Done()
ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring
ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency. ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency.
for { for {
@ -158,10 +156,9 @@ func (irc *Connection) pingLoop() {
irc.nickcurrent = irc.nick irc.nickcurrent = irc.nick
irc.SendRawf("NICK %s", irc.nick) irc.SendRawf("NICK %s", irc.nick)
} }
case <-irc.endping: case <-irc.end:
ticker.Stop() ticker.Stop()
ticker2.Stop() ticker2.Stop()
irc.pingerExit <- true
return return
} }
} }
@ -284,15 +281,11 @@ func (irc *Connection) Mode(target string, modestring ...string) {
// A disconnect sends all buffered messages (if possible), // A disconnect sends all buffered messages (if possible),
// stops all goroutines and then closes the socket. // stops all goroutines and then closes the socket.
func (irc *Connection) Disconnect() { func (irc *Connection) Disconnect() {
irc.endping <- true close(irc.end)
irc.endwrite <- true
irc.endread <- true
close(irc.pwrite) close(irc.pwrite)
close(irc.pread) close(irc.pread)
<-irc.readerExit irc.Wait()
<-irc.writerExit
<-irc.pingerExit
irc.socket.Close() irc.socket.Close()
irc.socket = nil irc.socket = nil
if irc.netsock != nil { if irc.netsock != nil {
@ -362,6 +355,7 @@ func (irc *Connection) Connect(server string) error {
irc.pwrite = make(chan string, 10) irc.pwrite = make(chan string, 10)
irc.Error = make(chan error, 2) irc.Error = make(chan error, 2)
irc.Add(3)
go irc.readLoop() go irc.readLoop()
go irc.writeLoop() go irc.writeLoop()
go irc.pingLoop() go irc.pingLoop()
@ -390,12 +384,7 @@ func IRC(nick, user string) *Connection {
nick: nick, nick: nick,
user: user, user: user,
Log: log.New(os.Stdout, "", log.LstdFlags), Log: log.New(os.Stdout, "", log.LstdFlags),
readerExit: make(chan bool), end: make(chan struct{}),
writerExit: make(chan bool),
pingerExit: make(chan bool),
endping: make(chan bool),
endread: make(chan bool),
endwrite: make(chan bool),
Version: VERSION, Version: VERSION,
KeepAlive: 4 * time.Minute, KeepAlive: 4 * time.Minute,
Timeout: 1 * time.Minute, Timeout: 1 * time.Minute,

View File

@ -8,10 +8,12 @@ import (
"crypto/tls" "crypto/tls"
"log" "log"
"net" "net"
"sync"
"time" "time"
) )
type Connection struct { type Connection struct {
sync.WaitGroup
Debug bool Debug bool
Error chan error Error chan error
Password string Password string
@ -25,8 +27,7 @@ type Connection struct {
socket net.Conn socket net.Conn
netsock net.Conn netsock net.Conn
pread, pwrite chan string pread, pwrite chan string
readerExit, writerExit, pingerExit chan bool end chan struct{}
endping, endread, endwrite chan bool
nick string //The nickname we want. nick string //The nickname we want.
nickcurrent string //The nickname we currently have. nickcurrent string //The nickname we currently have.
@ -43,7 +44,6 @@ type Connection struct {
stopped bool stopped bool
} }
// A struct to represent an event. // A struct to represent an event.
type Event struct { type Event struct {
Code string Code string
@ -55,7 +55,6 @@ type Event struct {
Arguments []string Arguments []string
} }
// Retrieve the last message from Event arguments. // Retrieve the last message from Event arguments.
// This function leaves the arguments untouched and // This function leaves the arguments untouched and
// returns an empty string if there are none. // returns an empty string if there are none.