Skip to content

Commit

Permalink
fix race problem
Browse files Browse the repository at this point in the history
  • Loading branch information
zyxkad committed Dec 4, 2023
1 parent 62d5652 commit 906ddd6
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 25 deletions.
9 changes: 9 additions & 0 deletions box.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ func NewCube(pos, size Vec3) (b *Cube) {
}
}

func NewCubeFromCenter(size Vec3) (b *Cube) {
pos := size
pos.ScaleN(-0.5)
return &Cube{
P: pos,
S: size,
}
}

func (b *Cube) String() string {
return "Cube(pos=" + b.P.String() + ", size=" + b.S.String() + ")"
}
Expand Down
34 changes: 24 additions & 10 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ func (e *Engine) GetObject(id uuid.UUID) *Object {
return e.objects[id]
}

func (e *Engine) ForeachObject(cb func(o *Object)) {
e.RLock()
defer e.RUnlock()

for _, o := range e.objects {
cb(o)
}
}

func (e *Engine) Events() []eventWave {
return e.events
}
Expand Down Expand Up @@ -128,15 +137,18 @@ func (e *Engine) tickLocked(wg *sync.WaitGroup, dt float64) {
e.RLock()
defer e.RUnlock()

wg.Add(len(e.objects))
for _, o := range e.objects {
go func(o *Object) {
defer wg.Done()
o.tick(dt)
}(o)
if o.IsReady() {
wg.Add(1)
go func(o *Object) {
defer wg.Done()
o.tick(dt)
}(o)
}
}
for _, event := range e.events {
if event.Heavy() {
wg.Add(1)
go func(event eventWave) {
defer wg.Done()
event.Tick(dt, e)
Expand All @@ -151,12 +163,14 @@ func (e *Engine) saveStatusLocked(wg *sync.WaitGroup) {
e.Lock()
defer e.Unlock()

wg.Add(len(e.objects))
for _, o := range e.objects {
go func(o *Object) {
defer wg.Done()
o.saveStatus()
}(o)
if o.IsReady() {
wg.Add(1)
go func(o *Object) {
defer wg.Done()
o.saveStatus()
}(o)
}
}
for i := 0; i < len(e.events); {
event := e.events[i]
Expand Down
4 changes: 2 additions & 2 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (e *Engine) newGravityWave(sender *Object, center Vec3, f *GravityField, ti
g.f = *f
g.pos = center
g.gone = false
g.c = 1
g.c.Store(1)
maxRadius := -1.0
if e.cfg.MinAccel > 0 {
maxRadius = math.Sqrt(G / e.cfg.MinAccel * f.Mass())
Expand All @@ -181,7 +181,7 @@ func (e *Engine) newGravityWave(sender *Object, center Vec3, f *GravityField, ti
}
g.count()
r.passedGravity[sender] = g
}, false)
}, true)
w.onRemove = g.release
w.onBeforeTick = func(e *eventWaveFn) bool {
switch {
Expand Down
17 changes: 10 additions & 7 deletions force.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package molecular
import (
"math"
"sync"
"sync/atomic"
)

const (
Expand Down Expand Up @@ -61,7 +62,7 @@ type gravityStatus struct {
pos Vec3

gone bool
c int
c atomic.Int32
}

var gravityStatusPool = sync.Pool{
Expand All @@ -76,21 +77,23 @@ func (s *gravityStatus) FieldAt(pos Vec3) Vec3 {

func (s *gravityStatus) clone() (g *gravityStatus) {
g = gravityStatusPool.Get().(*gravityStatus)
*g = *s
g.c = 1
g.f = s.f
g.pos = s.pos
g.gone = false
g.c.Store(1)
return
}

func (s *gravityStatus) count() {
s.c++
s.c.Add(1)
}

func (s *gravityStatus) release() {
s.c--
if s.c < 0 {
c := s.c.Add(-1)
if c < 0 {
panic("gravityStatus.count become less than one")
}
if s.c == 0 {
if c == 0 {
gravityStatusPool.Put(s)
}
}
Expand Down
44 changes: 38 additions & 6 deletions object.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"math"
"sync"
"sync/atomic"

"github.com/google/uuid"
)
Expand Down Expand Up @@ -57,8 +58,10 @@ func (s *objStatus) from(a *objStatus) {
for k, v := range a.passedGravity {
g := s.passedGravity[k]
if g != nil {
*g = *v
g.c = 1
g.f = v.f
g.pos = v.pos
g.gone = false
g.c.Store(1)
} else {
s.passedGravity[k] = v.clone()
}
Expand Down Expand Up @@ -97,13 +100,14 @@ func (s *objStatus) clone() (a objStatus) {
// Object represents an object in the physics engine.
type Object struct {
sync.RWMutex
ready atomic.Bool
e *Engine
id uuid.UUID // a v7 UUID
typ ObjType
blocks []Block
objStatus

// lastStatus should only be read during a tick
lastMux sync.RWMutex
lastStatus objStatus

gtick uint16
Expand Down Expand Up @@ -148,6 +152,16 @@ func (o *Object) Engine() *Engine {
return o.e
}

// IsReady returns true when the object is ready to tick
func (o *Object) IsReady() bool {
return o.ready.Load()
}

// Ready makes the IsReady returns true
func (o *Object) Ready() {
o.ready.Store(true)
}

// Anchor returns this object's anchor object
// If Anchor returns nil, the object is the main anchor
func (o *Object) Anchor() *Object {
Expand Down Expand Up @@ -191,6 +205,9 @@ func (o *Object) SetHeadingVel(v Vec3) {
// The new position will be calculated at the same time.
// AttachTo must be called inside the object's tick
func (o *Object) AttachTo(anchor *Object) {
o.lastMux.RLock()
defer o.lastMux.RUnlock()

if anchor == nil {
panic("molecular.Object: new anchor cannot be nil")
}
Expand Down Expand Up @@ -220,7 +237,6 @@ func (o *Object) AttachTo(anchor *Object) {
ScaleN(o.e.ReLorentzFactorSq(a.lastStatus.velocity.SqLen())).
Add(a.lastStatus.velocity)
})
hneg := o.lastStatus.heading.Negated()
v.Sub(v2)
o.anchor = anchor
o.pos = p
Expand All @@ -232,12 +248,20 @@ func (o *Object) forEachAnchor(cb func(*Object)) {
if o.lastStatus.anchor == nil {
return
}
cb(o.lastStatus.anchor)
o.lastStatus.anchor.forEachAnchor(cb)
a := o.lastStatus.anchor

a.lastMux.RLock()
defer a.lastMux.RUnlock()

cb(a)
a.forEachAnchor(cb)
}

// AbsPos returns the position relative to the main anchor
func (o *Object) AbsPos() (p Vec3) {
o.lastMux.RLock()
defer o.lastMux.RUnlock()

p = o.lastStatus.pos
o.forEachAnchor(func(a *Object) {
p.Add(a.lastStatus.pos)
Expand All @@ -246,6 +270,9 @@ func (o *Object) AbsPos() (p Vec3) {
}

func (o *Object) RotatePos(p *Vec3) *Vec3 {
o.lastMux.RLock()
defer o.lastMux.RUnlock()

if o.anchor != nil {
p.
Sub(o.lastStatus.gcenter).
Expand All @@ -264,6 +291,9 @@ func (o *Object) SetVelocity(velocity Vec3) {
}

func (o *Object) AbsVelocity() (v Vec3) {
o.lastMux.RLock()
defer o.lastMux.RUnlock()

v = o.lastStatus.velocity
o.forEachAnchor(func(a *Object) {
v.
Expand Down Expand Up @@ -424,6 +454,8 @@ func (o *Object) tick(dt float64) {
func (o *Object) saveStatus() {
o.RLock()
defer o.RUnlock()
o.lastMux.Lock()
defer o.lastMux.Unlock()

o.lastStatus.from(&o.objStatus)
}

0 comments on commit 906ddd6

Please sign in to comment.