audio/internal/readerplayer: Bug fix: Potential deadlock when waveOutWrite failed (Windows)

This commit is contained in:
Hajime Hoshi 2021-05-28 05:17:32 +09:00
parent f334eee1e4
commit 6c3c3533fb

View File

@ -97,6 +97,7 @@ type players struct {
context *context context *context
players map[*playerImpl]struct{} players map[*playerImpl]struct{}
buf []byte buf []byte
err error
waveOut uintptr waveOut uintptr
headers []*header headers []*header
@ -114,6 +115,10 @@ func (p *players) add(player *playerImpl) error {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
if p.err != nil {
return p.err
}
if p.players == nil { if p.players == nil {
p.players = map[*playerImpl]struct{}{} p.players = map[*playerImpl]struct{}{}
} }
@ -164,6 +169,13 @@ func (p *players) add(player *playerImpl) error {
func (p *players) remove(player *playerImpl) error { func (p *players) remove(player *playerImpl) error {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
return p.removeImpl(player)
}
func (p *players) removeImpl(player *playerImpl) error {
if p.err != nil {
return p.err
}
delete(p.players, player) delete(p.players, player)
if len(p.players) > 0 { if len(p.players) > 0 {
@ -221,10 +233,19 @@ func (p *players) loop() {
if !p.wait() { if !p.wait() {
return return
} }
p.readAndWriteBuffers() if err := p.readAndWriteBuffers(); err != nil {
p.setError(err)
break
}
} }
} }
func (p *players) setError(err error) {
p.cond.L.Lock()
defer p.cond.L.Unlock()
p.err = err
}
func (p *players) suspend() error { func (p *players) suspend() error {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
@ -261,13 +282,13 @@ var waveOutOpenCallback = windows.NewCallbackCDecl(func(hwo, uMsg, dwInstance, d
return 0 return 0
}) })
func (p *players) readAndWriteBuffers() { func (p *players) readAndWriteBuffers() error {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
p.readAndWriteBuffersImpl() return p.readAndWriteBuffersImpl()
} }
func (p *players) readAndWriteBuffersImpl() { func (p *players) readAndWriteBuffersImpl() error {
headerNum := 0 headerNum := 0
for _, h := range p.headers { for _, h := range p.headers {
if h.IsQueued() { if h.IsQueued() {
@ -276,7 +297,7 @@ func (p *players) readAndWriteBuffersImpl() {
headerNum++ headerNum++
} }
if headerNum == 0 { if headerNum == 0 {
return return nil
} }
if n := headerBufferSize*headerNum - len(p.buf); n > 0 { if n := headerBufferSize*headerNum - len(p.buf); n > 0 {
@ -360,13 +381,12 @@ func (p *players) readAndWriteBuffersImpl() {
if werr := err.(*winmmError); werr.fname == "waveOutWrite" && werr.errno == errorNotFound { if werr := err.(*winmmError); werr.fname == "waveOutWrite" && werr.errno == errorNotFound {
// TODO: Retry later. // TODO: Retry later.
} }
for pl := range p.players { return err
pl.setError(err)
}
return
} }
p.buf = p.buf[headerBufferSize:] p.buf = p.buf[headerBufferSize:]
} }
return nil
} }
var thePlayers = players{ var thePlayers = players{