ui: Bug fix: assigning a run context was not goroutine-safe

This commit is contained in:
Hajime Hoshi 2016-03-26 19:16:57 +09:00
parent fc3dcd4a6b
commit a3b5b283e4

46
run.go
View File

@ -22,6 +22,7 @@ import (
) )
type runContext struct { type runContext struct {
isRunning bool
fps float64 fps float64
newScreenWidth int newScreenWidth int
newScreenHeight int newScreenHeight int
@ -30,15 +31,27 @@ type runContext struct {
m sync.RWMutex m sync.RWMutex
} }
var currentRunContext *runContext var currentRunContext runContext
func (c *runContext) startRunning() {
c.m.Lock()
defer c.m.Unlock()
c.isRunning = true
}
func (c *runContext) endRunning() {
c.m.Lock()
defer c.m.Unlock()
c.isRunning = false
}
func (c *runContext) FPS() float64 { func (c *runContext) FPS() float64 {
if c == nil { c.m.RLock()
defer c.m.RUnlock()
if !c.isRunning {
// TODO: Should panic here? // TODO: Should panic here?
return 0 return 0
} }
c.m.RLock()
defer c.m.RUnlock()
return c.fps return c.fps
} }
@ -49,12 +62,12 @@ func (c *runContext) updateFPS(fps float64) {
} }
func (c *runContext) IsRunningSlowly() bool { func (c *runContext) IsRunningSlowly() bool {
if c == nil { c.m.RLock()
defer c.m.RUnlock()
if !c.isRunning {
// TODO: Should panic here? // TODO: Should panic here?
return false return false
} }
c.m.RLock()
defer c.m.RUnlock()
return c.isRunningSlowly return c.isRunningSlowly
} }
@ -92,11 +105,11 @@ func (c *runContext) updateScreenSize(g *graphicsContext) error {
} }
func (c *runContext) SetScreenSize(width, height int) { func (c *runContext) SetScreenSize(width, height int) {
if c == nil {
panic("ebiten: SetScreenSize must be called during Run")
}
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
if !c.isRunning {
panic("ebiten: SetScreenSize must be called during Run")
}
if width <= 0 || height <= 0 { if width <= 0 || height <= 0 {
panic("ebiten: width and height must be positive") panic("ebiten: width and height must be positive")
} }
@ -105,11 +118,11 @@ func (c *runContext) SetScreenSize(width, height int) {
} }
func (c *runContext) SetScreenScale(scale int) { func (c *runContext) SetScreenScale(scale int) {
if c == nil {
panic("ebiten: SetScreenScale must be called during Run")
}
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
if !c.isRunning {
panic("ebiten: SetScreenScale must be called during Run")
}
if scale <= 0 { if scale <= 0 {
panic("ebiten: scale must be positive") panic("ebiten: scale must be positive")
} }
@ -151,11 +164,8 @@ func IsRunningSlowly() bool {
// even if a rendering frame is skipped. // even if a rendering frame is skipped.
// f is not called when the screen is not shown. // f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error { func Run(f func(*Image) error, width, height, scale int, title string) error {
// TODO: This assignment does not look goroutine-safe. currentRunContext.startRunning()
currentRunContext = &runContext{} defer currentRunContext.endRunning()
defer func() {
currentRunContext = nil
}()
if err := ui.CurrentUI().Start(width, height, scale, title); err != nil { if err := ui.CurrentUI().Start(width, height, scale, title); err != nil {
return err return err