diff --git a/pkg/emulator/libretro/nanoarch/naemulator.go b/pkg/emulator/libretro/nanoarch/naemulator.go index 4513c8e5..ce470e18 100644 --- a/pkg/emulator/libretro/nanoarch/naemulator.go +++ b/pkg/emulator/libretro/nanoarch/naemulator.go @@ -3,6 +3,7 @@ package nanoarch import ( "image" "log" + "sync" "time" "github.com/giongto35/cloud-game/pkg/config" @@ -59,6 +60,9 @@ type naEmulator struct { keys []bool done chan struct{} + + // lock to lock uninteruptable operation + lock *sync.Mutex } var NAEmulator *naEmulator @@ -78,6 +82,7 @@ func NewNAEmulator(etype string, roomID string, inputChannel <-chan int) (*naEmu keys: make([]bool, joypadNumKeys), roomID: roomID, done: make(chan struct{}, 1), + lock: &sync.Mutex{}, }, imageChannel, audioChannel } diff --git a/pkg/emulator/libretro/nanoarch/savestates.go b/pkg/emulator/libretro/nanoarch/savestates.go index 50c0219c..c70e62cf 100644 --- a/pkg/emulator/libretro/nanoarch/savestates.go +++ b/pkg/emulator/libretro/nanoarch/savestates.go @@ -18,20 +18,16 @@ import "C" import ( "io/ioutil" - "sync" ) -var saveLock int32 -var m sync.Mutex - func (na *naEmulator) GetLock() { - //atomic.CompareAndSwapInt32(&saveLock, 0, 1) - m.Lock() + //atomic.CompareAndSwapInt32(&na.saveLock, 0, 1) + na.lock.Lock() } func (na *naEmulator) ReleaseLock() { - //atomic.CompareAndSwapInt32(&saveLock, 1, 0) - m.Unlock() + //atomic.CompareAndSwapInt32(&na.saveLock, 1, 0) + na.lock.Unlock() } // Save the current state to the filesystem. name is the name of the diff --git a/pkg/worker/room/room.go b/pkg/worker/room/room.go index 1fe56b0f..cd52b56c 100644 --- a/pkg/worker/room/room.go +++ b/pkg/worker/room/room.go @@ -199,6 +199,7 @@ func (r *Room) startWebRTCSession(peerconnection *webrtc.WebRTC, playerIndex int } }() + // bug: when inputchannel here = nil , skip and finish for input := range peerconnection.InputChannel { // NOTE: when room is no longer running. InputChannel needs to have extra event to go inside the loop if peerconnection.Done || !peerconnection.IsConnected() || !r.IsRunning { @@ -258,9 +259,16 @@ func (r *Room) Close() { // Save game before quit. Only save for game which was previous saved to avoid flooding database if r.isRoomExisted() { log.Println("Saved Game before closing room") - r.SaveGame() + // use goroutine here because SaveGame attempt to acquire a emulator lock. + // the lock is holding before coming to close, so it will cause deadlock if SaveGame is synchronous + go func() { + // Save before close, so save can have correct state (Not sure) may again cause deadlock + r.SaveGame() + r.director.Close() + }() + } else { + r.director.Close() } - r.director.Close() log.Println("Closing input of room ", r.ID) close(r.inputChannel) close(r.Done)