bsp: Make bsp concurrent safe

Fixes #530. Finalizers can be called on different goroutines
This commit is contained in:
Hajime Hoshi 2018-03-04 02:33:05 +09:00
parent 8dbb11a23c
commit 7da65d64be

View File

@ -15,6 +15,10 @@
// Package bsp offers binary space partitioning algorithm. // Package bsp offers binary space partitioning algorithm.
package bsp package bsp
import (
"github.com/hajimehoshi/ebiten/internal/sync"
)
const ( const (
MaxSize = 2048 MaxSize = 2048
minSize = 1 minSize = 1
@ -22,13 +26,18 @@ const (
type Page struct { type Page struct {
root *Node root *Node
m sync.Mutex
} }
func (p *Page) IsEmpty() bool { func (p *Page) IsEmpty() bool {
p.m.Lock()
if p.root == nil { if p.root == nil {
p.m.Unlock()
return true return true
} }
return !p.root.used && p.root.child0 == nil && p.root.child1 == nil r := !p.root.used && p.root.child0 == nil && p.root.child1 == nil
p.m.Unlock()
return r
} }
type Node struct { type Node struct {
@ -130,6 +139,7 @@ func (n *Node) alloc(width, height int) *Node {
} }
func (p *Page) Alloc(width, height int) *Node { func (p *Page) Alloc(width, height int) *Node {
p.m.Lock()
if width <= 0 || height <= 0 { if width <= 0 || height <= 0 {
panic("bsp: width and height must > 0") panic("bsp: width and height must > 0")
} }
@ -145,10 +155,18 @@ func (p *Page) Alloc(width, height int) *Node {
if height < minSize { if height < minSize {
height = minSize height = minSize
} }
return p.root.alloc(width, height) n := p.root.alloc(width, height)
p.m.Unlock()
return n
} }
func (p *Page) Free(node *Node) { func (p *Page) Free(node *Node) {
p.m.Lock()
p.free(node)
p.m.Unlock()
}
func (p *Page) free(node *Node) {
if node.child0 != nil || node.child1 != nil { if node.child0 != nil || node.child1 != nil {
panic("bsp: can't free the node including children") panic("bsp: can't free the node including children")
} }
@ -162,6 +180,6 @@ func (p *Page) Free(node *Node) {
if node.parent.child0.canFree() && node.parent.child1.canFree() { if node.parent.child0.canFree() && node.parent.child1.canFree() {
node.parent.child0 = nil node.parent.child0 = nil
node.parent.child1 = nil node.parent.child1 = nil
p.Free(node.parent) p.free(node.parent)
} }
} }