Skip to content

Commit 49343df

Browse files
committed
Bugfix: Deadlock in CI mode
1 parent 50fc62d commit 49343df

File tree

7 files changed

+34
-28
lines changed

7 files changed

+34
-28
lines changed

internal/app/api/server.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ func (a *Server) WsHandler(w http.ResponseWriter, r *http.Request) {
7070
}
7171

7272
func (s *ServerConnection) publish() {
73-
hook := make(chan engine.HookOut)
74-
s.gcEngine.RegisterHook(hook)
73+
hook := make(chan engine.HookOut, 10)
74+
s.gcEngine.RegisterHook("apiServer", hook)
7575
defer func() {
76-
s.gcEngine.UnregisterHook(hook)
76+
s.gcEngine.UnregisterHook("apiServer")
7777
close(hook)
7878
}()
7979

internal/app/ci/ci.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ func (s *Server) serve(conn net.Conn) {
8383
s.latestTime = time.Unix(sec, nSec)
8484
s.mutex.Unlock()
8585
select {
86-
case s.tickChan <- time.Now():
87-
default:
86+
case s.tickChan <- s.latestTime:
87+
case <-time.After(1 * time.Second):
88+
log.Printf("tickChan unresponsive! Failed to sent %v", s.latestTime)
8889
}
8990
}
9091
}

internal/app/engine/engine.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type Engine struct {
2323
currentState *state.State
2424
stateMachine *statemachine.StateMachine
2525
queue chan *statemachine.Change
26-
hooks []chan HookOut
26+
hooks map[string]chan HookOut
2727
timeProvider timer.TimeProvider
2828
lastTimeUpdate time.Time
2929
gcState *GcState
@@ -40,7 +40,7 @@ func NewEngine(gameConfig config.Game) (e *Engine) {
4040
e.stateStore = store.NewStore(gameConfig.StateStoreFile)
4141
e.stateMachine = statemachine.NewStateMachine(gameConfig)
4242
e.queue = make(chan *statemachine.Change, 100)
43-
e.hooks = []chan HookOut{}
43+
e.hooks = map[string]chan HookOut{}
4444
e.SetTimeProvider(func() time.Time { return time.Now() })
4545
e.gcState = new(GcState)
4646
e.gcState.TeamState = map[string]*GcStateTeam{
@@ -241,10 +241,12 @@ func (e *Engine) processChange(change *statemachine.Change) {
241241
log.Println("Could not add new state to store: ", err)
242242
}
243243
stateCopy := e.currentState.Clone()
244-
for _, hook := range e.hooks {
244+
hookOut := HookOut{Change: entry.Change, State: stateCopy}
245+
for name, hook := range e.hooks {
245246
select {
246-
case hook <- HookOut{Change: entry.Change, State: stateCopy}:
247-
default:
247+
case hook <- hookOut:
248+
case <-time.After(1 * time.Second):
249+
log.Printf("Hook %v unresponsive! Failed to sent %v", name, hookOut)
248250
}
249251
}
250252

internal/app/engine/engine_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func Test_Engine(t *testing.T) {
2626
gameConfig.StateStoreFile = tmpDir + "/store.json.stream"
2727
engine := NewEngine(gameConfig)
2828
hook := make(chan HookOut)
29-
engine.RegisterHook(hook)
29+
engine.RegisterHook("engineTest", hook)
3030
if err := engine.Start(); err != nil {
3131
t.Fatal("Could not start engine")
3232
}
@@ -41,7 +41,7 @@ func Test_Engine(t *testing.T) {
4141
})
4242
// wait for the changes to be processed
4343
<-hook
44-
engine.UnregisterHook(hook)
44+
engine.UnregisterHook("engineTest")
4545
engine.Stop()
4646

4747
wantNewState.Command = state.NewCommandNeutral(state.Command_HALT)

internal/app/engine/hook.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package engine
33
import (
44
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
55
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/statemachine"
6+
"log"
67
)
78

89
type HookOut struct {
@@ -11,25 +12,24 @@ type HookOut struct {
1112
}
1213

1314
// RegisterHook registers given hook for post processing after each change
14-
func (e *Engine) RegisterHook(hook chan HookOut) {
15+
func (e *Engine) RegisterHook(name string, hook chan HookOut) {
1516
e.mutex.Lock()
1617
defer e.mutex.Unlock()
17-
e.hooks = append(e.hooks, hook)
18+
if _, ok := e.hooks[name]; ok {
19+
log.Printf("Hook %v already registered!", name)
20+
}
21+
e.hooks[name] = hook
1822
}
1923

2024
// UnregisterHook unregisters hooks that were registered before
21-
func (e *Engine) UnregisterHook(hook chan HookOut) bool {
25+
func (e *Engine) UnregisterHook(name string) {
2226
e.mutex.Lock()
2327
defer e.mutex.Unlock()
24-
for i, h := range e.hooks {
25-
if h == hook {
26-
e.hooks = append(e.hooks[:i], e.hooks[i+1:]...)
27-
select {
28-
case <-hook:
29-
default:
30-
}
31-
return true
28+
if hook, ok := e.hooks[name]; ok {
29+
select {
30+
case <-hook:
31+
default:
3232
}
3333
}
34-
return false
34+
delete(e.hooks, name)
3535
}

internal/app/engine/process_tick.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
55
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/statemachine"
66
"github.com/golang/protobuf/ptypes"
7+
"log"
78
"time"
89
)
910

@@ -63,10 +64,12 @@ func (e *Engine) processTick() {
6364
e.processPenalty()
6465

6566
stateCopy := e.currentState.Clone()
67+
hookOut := HookOut{State: stateCopy}
6668
for _, hook := range e.hooks {
6769
select {
68-
case hook <- HookOut{State: stateCopy}:
69-
default:
70+
case hook <- hookOut:
71+
case <-time.After(1 * time.Second):
72+
log.Printf("processTick: Hook unresponsive! Failed to sent %v", hookOut)
7073
}
7174
}
7275
}

internal/app/gc/gc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (c *GameController) Start() {
7171
c.ciServer.Start()
7272
}
7373

74-
c.gcEngine.RegisterHook(c.messageGenerator.EngineHook)
74+
c.gcEngine.RegisterHook("messageGen", c.messageGenerator.EngineHook)
7575
c.messageGenerator.Start()
7676
c.autoRefServer.Server.Start()
7777
c.autoRefServerTls.Server.Start()
@@ -86,7 +86,7 @@ func (c *GameController) Start() {
8686
// Stop stops all go routines
8787
func (c *GameController) Stop() {
8888
// Note: Stopping is not (yet) implemented correctly by all servers.
89-
c.gcEngine.UnregisterHook(c.messageGenerator.EngineHook)
89+
c.gcEngine.UnregisterHook("messageGen")
9090
c.messageGenerator.Stop()
9191
c.ciServer.Stop()
9292
c.trackerReceiver.Stop()

0 commit comments

Comments
 (0)