Skip to content

Commit 117d3b9

Browse files
committed
core: fix deadlock caused by multiple calls to Parser.Cancel() (#276)
- upgrade to [email protected] so we can use Dispatcher.UnregisterAllHandlers()
1 parent d7cf75d commit 117d3b9

File tree

5 files changed

+23
-16
lines changed

5 files changed

+23
-16
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/llgcode/draw2d v0.0.0-20200930101115-bfaf5d914d1e
88
github.com/markus-wa/go-unassert v0.1.2
99
github.com/markus-wa/gobitread v0.2.2
10-
github.com/markus-wa/godispatch v1.3.0
10+
github.com/markus-wa/godispatch v1.4.1
1111
github.com/markus-wa/quickhull-go/v2 v2.1.0
1212
github.com/stretchr/testify v1.6.1
1313
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ github.com/markus-wa/godispatch v1.2.1 h1:Bj6blK4xJ/72pDi0rprVYluOGW9CV55FUDFPAp
4343
github.com/markus-wa/godispatch v1.2.1/go.mod h1:GNzV7xdnZ9+VBi0z+hma9oUQrJmtqRrqyAuGKTTTcKY=
4444
github.com/markus-wa/godispatch v1.3.0 h1:eHT5Xm8ZEwilj9b/Tu7gyMfmtSau+yC0qpM7NRR+CQk=
4545
github.com/markus-wa/godispatch v1.3.0/go.mod h1:GNzV7xdnZ9+VBi0z+hma9oUQrJmtqRrqyAuGKTTTcKY=
46+
github.com/markus-wa/godispatch v1.4.0 h1:cSRg6/jvLjpi2616rJAbgXMfl8gV+6RfEAUe+8qVfYE=
47+
github.com/markus-wa/godispatch v1.4.0/go.mod h1:oz4Bh/xA+T/tMR5jXShPQ3fhkL5ba6VsVg9hLZzpEbw=
48+
github.com/markus-wa/godispatch v1.4.1 h1:Cdff5x33ShuX3sDmUbYWejk7tOuoHErFYMhUc2h7sLc=
49+
github.com/markus-wa/godispatch v1.4.1/go.mod h1:tk8L0yzLO4oAcFwM2sABMge0HRDJMdE8E7xm4gK/+xM=
4650
github.com/markus-wa/quickhull-go/v2 v2.1.0 h1:DA2pzEzH0k5CEnlUsouRqNdD+jzNFb4DBhrX4Hpa5So=
4751
github.com/markus-wa/quickhull-go/v2 v2.1.0/go.mod h1:bOlBUpIzGSMMhHX0f9N8CQs0VZD4nnPeta0OocH7m4o=
4852
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

pkg/demoinfocs/parser.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ type parser struct {
5959
header *common.DemoHeader // Pointer so we can check for nil
6060
gameState *gameState
6161
demoInfoProvider demoInfoProvider // Provides demo infos to other packages that the core package depends on
62-
cancelled bool // Indicates if Parser.Cancel() has been called
6362
err error // Contains a error that occurred during parsing if any
6463
errLock sync.Mutex // Used to sync up error mutations between parsing & handling go-routines
6564

@@ -250,12 +249,20 @@ func (p *parser) error() error {
250249
}
251250

252251
func (p *parser) setError(err error) {
253-
if err == nil || p.err != nil {
252+
if err == nil {
254253
return
255254
}
256255

257256
p.errLock.Lock()
257+
258+
if p.err != nil {
259+
p.errLock.Unlock()
260+
261+
return
262+
}
263+
258264
p.err = err
265+
259266
p.errLock.Unlock()
260267
}
261268

pkg/demoinfocs/parser_interface.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ type Parser interface {
112112
//
113113
// See also: ParseNextFrame() for other possible errors.
114114
ParseToEnd() (err error)
115-
// Cancel aborts ParseToEnd().
116-
// All information that was already read up to this point may still be used (and new events may still be sent out).
115+
// Cancel aborts ParseToEnd() and drains the internal event queues.
116+
// No further events will be sent to event or message handlers after this.
117117
Cancel()
118118
/*
119119
ParseNextFrame attempts to parse the next frame / demo-tick (not ingame tick).

pkg/demoinfocs/parsing.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,8 @@ func (p *parser) ParseToEnd() (err error) {
111111
}
112112

113113
for {
114-
select {
115-
case <-p.cancelChan:
116-
return ErrCancelled
117-
118-
default:
119-
if !p.parseFrame() {
120-
return p.error()
121-
}
114+
if !p.parseFrame() {
115+
return p.error()
122116
}
123117

124118
if err = p.error(); err != nil {
@@ -145,10 +139,12 @@ func recoverFromUnexpectedEOF(r interface{}) error {
145139
}
146140
}
147141

148-
// Cancel aborts ParseToEnd().
149-
// All information that was already read up to this point may still be used (and new events may still be sent out).
142+
// Cancel aborts ParseToEnd() and drains the internal event queues.
143+
// No further events will be sent to event or message handlers after this.
150144
func (p *parser) Cancel() {
151-
p.cancelChan <- struct{}{}
145+
p.setError(ErrCancelled)
146+
p.eventDispatcher.UnregisterAllHandlers()
147+
p.msgDispatcher.UnregisterAllHandlers()
152148
}
153149

154150
/*

0 commit comments

Comments
 (0)