Netplay: Fixed some potential multithreading issues

This commit is contained in:
Souryo 2017-11-14 00:00:00 -05:00
parent 72f0d961db
commit 13103551cf
13 changed files with 113 additions and 98 deletions

View file

@ -31,6 +31,7 @@ double EmulationSettings::_stereoAngle = 0;
double EmulationSettings::_reverbStrength = 0; double EmulationSettings::_reverbStrength = 0;
double EmulationSettings::_reverbDelay = 0; double EmulationSettings::_reverbDelay = 0;
uint32_t EmulationSettings::_crossFeedRatio = 0; uint32_t EmulationSettings::_crossFeedRatio = 0;
SimpleLock EmulationSettings::_equalizerLock;
NesModel EmulationSettings::_model = NesModel::Auto; NesModel EmulationSettings::_model = NesModel::Auto;
PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C02; PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C02;
@ -115,28 +116,6 @@ uint8_t EmulationSettings::_paletteLut[11][64] = {
/* 2C05-05 */ { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 }, /* 2C05-05 */ { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
}; };
void EmulationSettings::SetEqualizerBands(double *bands, uint32_t bandCount)
{
Console::Pause();
_bands.clear();
_bandGains.clear();
for(uint32_t i = 0; i < bandCount; i++) {
_bands.push_back(bands[i]);
_bandGains.push_back(0);
}
Console::Resume();
}
void EmulationSettings::SetRewindBufferSize(uint32_t seconds)
{
if(seconds == 0 || _rewindBufferSize == 0) {
Console::Pause();
RewindManager::ClearBuffer();
Console::Resume();
}
_rewindBufferSize = seconds;
}
uint32_t EmulationSettings::GetEmulationSpeed(bool ignoreTurbo) uint32_t EmulationSettings::GetEmulationSpeed(bool ignoreTurbo)
{ {
if(ignoreTurbo) { if(ignoreTurbo) {

View file

@ -537,6 +537,7 @@ private:
static RamPowerOnState _ramPowerOnState; static RamPowerOnState _ramPowerOnState;
static SimpleLock _shortcutLock; static SimpleLock _shortcutLock;
static SimpleLock _equalizerLock;
static SimpleLock _lock; static SimpleLock _lock;
public: public:
@ -658,29 +659,37 @@ public:
_audioSettingsChanged = true; _audioSettingsChanged = true;
} }
static double GetBandGain(int band) static vector<double> GetBandGains()
{ {
if(band < (int)_bandGains.size()) { auto lock = _equalizerLock.AcquireSafe();
return _bandGains[band]; return _bandGains;
} else {
return 0;
}
} }
static void SetBandGain(int band, double gain) static void SetBandGain(int band, double gain)
{ {
auto lock = _equalizerLock.AcquireSafe();
if(band < (int)_bandGains.size()) { if(band < (int)_bandGains.size()) {
_bandGains[band] = gain; _bandGains[band] = gain;
}
_audioSettingsChanged = true; _audioSettingsChanged = true;
} }
}
static vector<double> GetEqualizerBands() static vector<double> GetEqualizerBands()
{ {
auto lock = _equalizerLock.AcquireSafe();
return _bands; return _bands;
} }
static void SetEqualizerBands(double *bands, uint32_t bandCount); static void SetEqualizerBands(double *bands, uint32_t bandCount)
{
auto lock = _equalizerLock.AcquireSafe();
_bands.clear();
_bandGains.clear();
for(uint32_t i = 0; i < bandCount; i++) {
_bands.push_back(bands[i]);
_bandGains.push_back(0);
}
}
static EqualizerFilterType GetEqualizerFilterType() static EqualizerFilterType GetEqualizerFilterType()
{ {
@ -830,7 +839,10 @@ public:
return _rewindSpeed; return _rewindSpeed;
} }
static void SetRewindBufferSize(uint32_t seconds); static void SetRewindBufferSize(uint32_t seconds)
{
_rewindBufferSize = seconds;
}
static uint32_t GetRewindBufferSize() static uint32_t GetRewindBufferSize()
{ {

View file

@ -9,7 +9,7 @@ using std::thread;
#include "ClientConnectionData.h" #include "ClientConnectionData.h"
#include "GameClientConnection.h" #include "GameClientConnection.h"
unique_ptr<GameClient> GameClient::Instance; shared_ptr<GameClient> GameClient::_instance;
GameClient::GameClient() GameClient::GameClient()
{ {
@ -29,36 +29,42 @@ GameClient::~GameClient()
bool GameClient::Connected() bool GameClient::Connected()
{ {
if(Instance) { shared_ptr<GameClient> instance = _instance;
return Instance->_connected; return instance ? instance->_connected : false;
} else {
return false;
}
} }
void GameClient::Connect(shared_ptr<ClientConnectionData> connectionData) void GameClient::Connect(shared_ptr<ClientConnectionData> connectionData)
{ {
Instance.reset(new GameClient()); _instance.reset(new GameClient());
Instance->PrivateConnect(connectionData);
Instance->_clientThread.reset(new thread(&GameClient::Exec, Instance.get())); shared_ptr<GameClient> instance = _instance;
if(instance) {
instance->PrivateConnect(connectionData);
instance->_clientThread.reset(new thread(&GameClient::Exec, instance.get()));
}
} }
void GameClient::Disconnect() void GameClient::Disconnect()
{ {
Instance.reset(); _instance.reset();
}
shared_ptr<GameClientConnection> GameClient::GetConnection()
{
shared_ptr<GameClient> instance = _instance;
return instance ? instance->_connection : nullptr;
} }
void GameClient::PrivateConnect(shared_ptr<ClientConnectionData> connectionData) void GameClient::PrivateConnect(shared_ptr<ClientConnectionData> connectionData)
{ {
_stop = false; _stop = false;
_socket.reset(new Socket()); shared_ptr<Socket> socket(new Socket());
if(_socket->Connect(connectionData->Host.c_str(), connectionData->Port)) { if(socket->Connect(connectionData->Host.c_str(), connectionData->Port)) {
_connection.reset(new GameClientConnection(_socket, connectionData)); _connection.reset(new GameClientConnection(socket, connectionData));
_connected = true; _connected = true;
} else { } else {
MessageManager::DisplayMessage("NetPlay", "CouldNotConnect"); MessageManager::DisplayMessage("NetPlay", "CouldNotConnect");
_connected = false; _connected = false;
_socket.reset();
} }
} }
@ -71,7 +77,7 @@ void GameClient::Exec()
_connection->SendInput(); _connection->SendInput();
} else { } else {
_connected = false; _connected = false;
_socket.reset(); _connection->Shutdown();
_connection.reset(); _connection.reset();
break; break;
} }
@ -89,34 +95,26 @@ void GameClient::ProcessNotification(ConsoleNotificationType type, void* paramet
uint8_t GameClient::GetControllerState(uint8_t port) uint8_t GameClient::GetControllerState(uint8_t port)
{ {
if(Instance && Instance->_connection) { shared_ptr<GameClientConnection> connection = GetConnection();
return Instance->_connection->GetControllerState(port); return connection ? connection->GetControllerState(port) : 0;
}
return 0;
} }
void GameClient::SelectController(uint8_t port) void GameClient::SelectController(uint8_t port)
{ {
if(Instance && Instance->_connection) { shared_ptr<GameClientConnection> connection = GetConnection();
Instance->_connection->SelectController(port); if(connection) {
connection->SelectController(port);
} }
} }
uint8_t GameClient::GetAvailableControllers() uint8_t GameClient::GetAvailableControllers()
{ {
if(Instance && Instance->_connection) { shared_ptr<GameClientConnection> connection = GetConnection();
return Instance->_connection->GetAvailableControllers(); return connection ? connection->GetAvailableControllers() : 0;
}
return 0;
} }
uint8_t GameClient::GetControllerPort() uint8_t GameClient::GetControllerPort()
{ {
if(Instance && Instance->_connection) { shared_ptr<GameClientConnection> connection = GetConnection();
return Instance->_connection->GetControllerPort(); return connection ? connection->GetControllerPort() : GameConnection::SpectatorPort;
}
return GameConnection::SpectatorPort;
} }

View file

@ -10,14 +10,15 @@ class ClientConnectionData;
class GameClient : public INotificationListener class GameClient : public INotificationListener
{ {
private: private:
static unique_ptr<GameClient> Instance; static shared_ptr<GameClient> _instance;
unique_ptr<thread> _clientThread; unique_ptr<thread> _clientThread;
atomic<bool> _stop; atomic<bool> _stop;
shared_ptr<Socket> _socket; shared_ptr<GameClientConnection> _connection;
unique_ptr<GameClientConnection> _connection;
bool _connected = false; bool _connected = false;
static shared_ptr<GameClientConnection> GetConnection();
void PrivateConnect(shared_ptr<ClientConnectionData> connectionData); void PrivateConnect(shared_ptr<ClientConnectionData> connectionData);
void Exec(); void Exec();

View file

@ -27,12 +27,20 @@ GameClientConnection::GameClientConnection(shared_ptr<Socket> socket, shared_ptr
GameClientConnection::~GameClientConnection() GameClientConnection::~GameClientConnection()
{ {
Shutdown();
}
void GameClientConnection::Shutdown()
{
if(!_shutdown) {
_shutdown = true; _shutdown = true;
DisableControllers(); DisableControllers();
EmulationSettings::ClearFlags(EmulationFlags::ForceMaxSpeed);
MessageManager::UnregisterNotificationListener(this);
MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer); MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer);
MessageManager::DisplayMessage("NetPlay", "ConnectionLost"); MessageManager::DisplayMessage("NetPlay", "ConnectionLost");
MessageManager::UnregisterNotificationListener(this); }
} }
void GameClientConnection::SendHandshake() void GameClientConnection::SendHandshake()
@ -49,6 +57,7 @@ void GameClientConnection::SendControllerSelection(uint8_t port)
void GameClientConnection::ClearInputData() void GameClientConnection::ClearInputData()
{ {
LockHandler lock = _writeLock.AcquireSafe();
for(int i = 0; i < 4; i++) { for(int i = 0; i < 4; i++) {
_inputSize[i] = 0; _inputSize[i] = 0;
_inputData[i].clear(); _inputData[i].clear();

View file

@ -41,6 +41,8 @@ public:
GameClientConnection(shared_ptr<Socket> socket, shared_ptr<ClientConnectionData> connectionData); GameClientConnection(shared_ptr<Socket> socket, shared_ptr<ClientConnectionData> connectionData);
~GameClientConnection(); ~GameClientConnection();
void Shutdown();
void ProcessNotification(ConsoleNotificationType type, void* parameter) override; void ProcessNotification(ConsoleNotificationType type, void* parameter) override;
uint8_t GetControllerState(uint8_t port); uint8_t GetControllerState(uint8_t port);

View file

@ -20,6 +20,7 @@ GameConnection::GameConnection(shared_ptr<Socket> socket, shared_ptr<ClientConne
void GameConnection::ReadSocket() void GameConnection::ReadSocket()
{ {
auto lock = _socketLock.AcquireSafe();
int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, 0x40000 - _readPosition, 0); int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, 0x40000 - _readPosition, 0);
if(bytesReceived > 0) { if(bytesReceived > 0) {
_readPosition += bytesReceived; _readPosition += bytesReceived;
@ -32,7 +33,7 @@ bool GameConnection::ExtractMessage(void *buffer, uint32_t &messageLength)
if(messageLength > 1000000) { if(messageLength > 1000000) {
MessageManager::Log("[Netplay] Invalid data received, closing connection."); MessageManager::Log("[Netplay] Invalid data received, closing connection.");
_socket->Close(); Disconnect();
return false; return false;
} }
@ -71,13 +72,13 @@ NetMessage* GameConnection::ReadMessage()
void GameConnection::SendNetMessage(NetMessage &message) void GameConnection::SendNetMessage(NetMessage &message)
{ {
_socketLock.Acquire(); auto lock = _socketLock.AcquireSafe();
message.Send(*_socket.get()); message.Send(*_socket.get());
_socketLock.Release();
} }
void GameConnection::Disconnect() void GameConnection::Disconnect()
{ {
auto lock = _socketLock.AcquireSafe();
_socket->Close(); _socket->Close();
} }

View file

@ -567,6 +567,7 @@ std::unordered_map<string, string> MessageManager::_caResources = {
std::list<string> MessageManager::_log; std::list<string> MessageManager::_log;
SimpleLock MessageManager::_logLock; SimpleLock MessageManager::_logLock;
SimpleLock MessageManager::_notificationLock;
IMessageManager* MessageManager::_messageManager = nullptr; IMessageManager* MessageManager::_messageManager = nullptr;
vector<INotificationListener*> MessageManager::_notificationListeners; vector<INotificationListener*> MessageManager::_notificationListeners;
@ -651,16 +652,20 @@ string MessageManager::GetLog()
void MessageManager::RegisterNotificationListener(INotificationListener* notificationListener) void MessageManager::RegisterNotificationListener(INotificationListener* notificationListener)
{ {
auto lock = _notificationLock.AcquireSafe();
MessageManager::_notificationListeners.push_back(notificationListener); MessageManager::_notificationListeners.push_back(notificationListener);
} }
void MessageManager::UnregisterNotificationListener(INotificationListener* notificationListener) void MessageManager::UnregisterNotificationListener(INotificationListener* notificationListener)
{ {
auto lock = _notificationLock.AcquireSafe();
MessageManager::_notificationListeners.erase(std::remove(MessageManager::_notificationListeners.begin(), MessageManager::_notificationListeners.end(), notificationListener), MessageManager::_notificationListeners.end()); MessageManager::_notificationListeners.erase(std::remove(MessageManager::_notificationListeners.begin(), MessageManager::_notificationListeners.end(), notificationListener), MessageManager::_notificationListeners.end());
} }
void MessageManager::SendNotification(ConsoleNotificationType type, void* parameter) void MessageManager::SendNotification(ConsoleNotificationType type, void* parameter)
{ {
auto lock = _notificationLock.AcquireSafe();
//Iterate on a copy to prevent issues if a notification causes a listener to unregister itself //Iterate on a copy to prevent issues if a notification causes a listener to unregister itself
vector<INotificationListener*> listeners = MessageManager::_notificationListeners; vector<INotificationListener*> listeners = MessageManager::_notificationListeners;
vector<INotificationListener*> processedListeners; vector<INotificationListener*> processedListeners;

View file

@ -22,6 +22,7 @@ private:
static std::unordered_map<string, string> _caResources; static std::unordered_map<string, string> _caResources;
static SimpleLock _logLock; static SimpleLock _logLock;
static SimpleLock _notificationLock;
static std::list<string> _log; static std::list<string> _log;
public: public:

View file

@ -28,16 +28,16 @@ RewindManager::~RewindManager()
void RewindManager::ClearBuffer() void RewindManager::ClearBuffer()
{ {
if(_instance) { if(_instance) {
_instance->_history.clear(); _history.clear();
_instance->_historyBackup.clear(); _historyBackup.clear();
_instance->_currentHistory = RewindData(); _currentHistory = RewindData();
_instance->_framesToFastForward = 0; _framesToFastForward = 0;
_instance->_videoHistory.clear(); _videoHistory.clear();
_instance->_videoHistoryBuilder.clear(); _videoHistoryBuilder.clear();
_instance->_audioHistory.clear(); _audioHistory.clear();
_instance->_audioHistoryBuilder.clear(); _audioHistoryBuilder.clear();
_instance->_rewindState = RewindState::Stopped; _rewindState = RewindState::Stopped;
_instance->AddHistoryBlock(); _currentHistory = RewindData();
} }
} }
@ -73,6 +73,8 @@ void RewindManager::ProcessNotification(ConsoleNotificationType type, void * par
_currentHistory.FrameCount++; _currentHistory.FrameCount++;
break; break;
} }
} else {
ClearBuffer();
} }
} }
} }
@ -80,6 +82,7 @@ void RewindManager::ProcessNotification(ConsoleNotificationType type, void * par
void RewindManager::AddHistoryBlock() void RewindManager::AddHistoryBlock()
{ {
uint32_t maxHistorySize = EmulationSettings::GetRewindBufferSize() * 120; uint32_t maxHistorySize = EmulationSettings::GetRewindBufferSize() * 120;
if(maxHistorySize > 0) {
while(_history.size() > maxHistorySize) { while(_history.size() > maxHistorySize) {
_history.pop_front(); _history.pop_front();
} }
@ -89,6 +92,7 @@ void RewindManager::AddHistoryBlock()
} }
_currentHistory = RewindData(); _currentHistory = RewindData();
_currentHistory.SaveState(); _currentHistory.SaveState();
}
} }
void RewindManager::PopHistory() void RewindManager::PopHistory()

View file

@ -40,6 +40,8 @@ private:
void ProcessFrame(void *frameBuffer, uint32_t width, uint32_t height); void ProcessFrame(void *frameBuffer, uint32_t width, uint32_t height);
bool ProcessAudio(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate); bool ProcessAudio(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate);
void ClearBuffer();
public: public:
RewindManager(); RewindManager();
~RewindManager(); ~RewindManager();
@ -47,8 +49,6 @@ public:
void ProcessNotification(ConsoleNotificationType type, void* parameter) override; void ProcessNotification(ConsoleNotificationType type, void* parameter) override;
void ProcessEndOfFrame(); void ProcessEndOfFrame();
static void ClearBuffer();
static void RecordInput(uint8_t port, uint8_t input); static void RecordInput(uint8_t port, uint8_t input);
static uint8_t GetInput(uint8_t port); static uint8_t GetInput(uint8_t port);

View file

@ -311,6 +311,7 @@ void SoundMixer::UpdateEqualizers(bool forceUpdate)
EqualizerFilterType type = EmulationSettings::GetEqualizerFilterType(); EqualizerFilterType type = EmulationSettings::GetEqualizerFilterType();
if(type != EqualizerFilterType::None) { if(type != EqualizerFilterType::None) {
vector<double> bands = EmulationSettings::GetEqualizerBands(); vector<double> bands = EmulationSettings::GetEqualizerBands();
vector<double> bandGains = EmulationSettings::GetBandGains();
if(bands.size() != _eqFrequencyGrid->get_number_of_bands()) { if(bands.size() != _eqFrequencyGrid->get_number_of_bands()) {
_equalizerLeft.reset(); _equalizerLeft.reset();
@ -332,8 +333,8 @@ void SoundMixer::UpdateEqualizers(bool forceUpdate)
} }
for(unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++) { for(unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++) {
_equalizerLeft->change_band_gain_db(i, EmulationSettings::GetBandGain(i)); _equalizerLeft->change_band_gain_db(i, bandGains[i]);
_equalizerRight->change_band_gain_db(i, EmulationSettings::GetBandGain(i)); _equalizerRight->change_band_gain_db(i, bandGains[i]);
} }
} else { } else {
_equalizerLeft.reset(); _equalizerLeft.reset();

View file

@ -458,7 +458,9 @@ namespace Mesen.GUI.Forms
break; break;
case InteropEmu.ConsoleNotificationType.DisconnectedFromServer: case InteropEmu.ConsoleNotificationType.DisconnectedFromServer:
this.BeginInvoke((MethodInvoker)(() => {
ConfigManager.Config.ApplyConfig(); ConfigManager.Config.ApplyConfig();
}));
break; break;
case InteropEmu.ConsoleNotificationType.GameStopped: case InteropEmu.ConsoleNotificationType.GameStopped: