Added eventsMutex and wrap all events calls with it.

Due to some "golangish" code this library have possibility to
run into data race when application is working with callbacks.
This commit adds eventsMutex (which is a sync.Mutex), removed
all "golangish" ifs-map reads, and wrap events map read with
sync.Mutex to avoid data races.
This commit is contained in:
Stanislav N. aka pztrn 2017-10-03 02:03:43 +05:00
parent 1b0acb5f2f
commit e39cceace6
2 changed files with 30 additions and 7 deletions

View File

@ -13,13 +13,17 @@ import (
func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) int { func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) int {
eventcode = strings.ToUpper(eventcode) eventcode = strings.ToUpper(eventcode)
id := 0 id := 0
if _, ok := irc.events[eventcode]; !ok {
irc.eventsMutex.Lock()
_, ok := irc.events[eventcode]
if !ok {
irc.events[eventcode] = make(map[int]func(*Event)) irc.events[eventcode] = make(map[int]func(*Event))
id = 0 id = 0
} else { } else {
id = len(irc.events[eventcode]) id = len(irc.events[eventcode])
} }
irc.events[eventcode][id] = callback irc.events[eventcode][id] = callback
irc.eventsMutex.Unlock()
return id return id
} }
@ -28,15 +32,20 @@ func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) int
func (irc *Connection) RemoveCallback(eventcode string, i int) bool { func (irc *Connection) RemoveCallback(eventcode string, i int) bool {
eventcode = strings.ToUpper(eventcode) eventcode = strings.ToUpper(eventcode)
if event, ok := irc.events[eventcode]; ok { irc.eventsMutex.Lock()
event, ok := irc.events[eventcode]
if ok {
if _, ok := event[i]; ok { if _, ok := event[i]; ok {
delete(irc.events[eventcode], i) delete(irc.events[eventcode], i)
irc.eventsMutex.Unlock()
return true return true
} }
irc.Log.Printf("Event found, but no callback found at id %d\n", i) irc.Log.Printf("Event found, but no callback found at id %d\n", i)
irc.eventsMutex.Unlock()
return false return false
} }
irc.eventsMutex.Unlock()
irc.Log.Println("Event not found") irc.Log.Println("Event not found")
return false return false
} }
@ -46,10 +55,14 @@ func (irc *Connection) RemoveCallback(eventcode string, i int) bool {
func (irc *Connection) ClearCallback(eventcode string) bool { func (irc *Connection) ClearCallback(eventcode string) bool {
eventcode = strings.ToUpper(eventcode) eventcode = strings.ToUpper(eventcode)
if _, ok := irc.events[eventcode]; ok { irc.eventsMutex.Lock()
_, ok := irc.events[eventcode]
if ok {
irc.events[eventcode] = make(map[int]func(*Event)) irc.events[eventcode] = make(map[int]func(*Event))
irc.eventsMutex.Unlock()
return true return true
} }
irc.eventsMutex.Unlock()
irc.Log.Println("Event not found") irc.Log.Println("Event not found")
return false return false
@ -59,7 +72,10 @@ func (irc *Connection) ClearCallback(eventcode string) bool {
func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) { func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) {
eventcode = strings.ToUpper(eventcode) eventcode = strings.ToUpper(eventcode)
if event, ok := irc.events[eventcode]; ok { irc.eventsMutex.Lock()
event, ok := irc.events[eventcode]
irc.eventsMutex.Unlock()
if ok {
if _, ok := event[i]; ok { if _, ok := event[i]; ok {
event[i] = callback event[i] = callback
return return
@ -109,7 +125,10 @@ func (irc *Connection) RunCallbacks(event *Event) {
event.Arguments[len(event.Arguments)-1] = msg event.Arguments[len(event.Arguments)-1] = msg
} }
if callbacks, ok := irc.events[event.Code]; ok { irc.eventsMutex.Lock()
callbacks, ok := irc.events[event.Code]
irc.eventsMutex.Unlock()
if ok {
if irc.VerboseCallbackHandler { if irc.VerboseCallbackHandler {
irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event) irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event)
} }
@ -121,12 +140,15 @@ func (irc *Connection) RunCallbacks(event *Event) {
irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) irc.Log.Printf("%v (0) >> %#v\n", event.Code, event)
} }
if callbacks, ok := irc.events["*"]; ok { irc.eventsMutex.Lock()
allcallbacks, ok := irc.events["*"]
irc.eventsMutex.Unlock()
if ok {
if irc.VerboseCallbackHandler { if irc.VerboseCallbackHandler {
irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) irc.Log.Printf("%v (0) >> %#v\n", event.Code, event)
} }
for _, callback := range callbacks { for _, callback := range allcallbacks {
callback(event) callback(event)
} }
} }

View File

@ -39,6 +39,7 @@ type Connection struct {
user string user string
registered bool registered bool
events map[string]map[int]func(*Event) events map[string]map[int]func(*Event)
eventsMutex sync.Mutex
QuitMessage string QuitMessage string
lastMessage time.Time lastMessage time.Time