From c981f8f5680c85268c75c68e4945abc55ba70de0 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Tue, 25 Jul 2017 20:28:24 +0100 Subject: [PATCH] Avoid holding hSet lock while executing handlers. Fixes #102. --- client/dispatch.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/client/dispatch.go b/client/dispatch.go index dc38a33..4a5deb9 100644 --- a/client/dispatch.go +++ b/client/dispatch.go @@ -1,10 +1,11 @@ package client import ( - "github.com/fluffle/goirc/logging" "runtime" "strings" "sync" + + "github.com/fluffle/goirc/logging" ) // Handlers are triggered on incoming Lines from the server, with the handler @@ -128,16 +129,25 @@ func (hs *hSet) remove(hn *hNode) { } } -func (hs *hSet) dispatch(conn *Conn, line *Line) { +func (hs *hSet) getHandlers(ev string) []*hNode { hs.RLock() defer hs.RUnlock() - ev := strings.ToLower(line.Cmd) list, ok := hs.set[ev] if !ok { - return + return nil } - wg := &sync.WaitGroup{} + // Copy current list of handlers to a temporary slice under the lock. + handlers := make([]*hNode, 0) for hn := list.start; hn != nil; hn = hn.next { + handlers = append(handlers, hn) + } + return handlers +} + +func (hs *hSet) dispatch(conn *Conn, line *Line) { + ev := strings.ToLower(line.Cmd) + wg := &sync.WaitGroup{} + for _, hn := range hs.getHandlers(ev) { wg.Add(1) go func(hn *hNode) { hn.Handle(conn, line.Copy())