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::_reverbDelay = 0;
uint32_t EmulationSettings::_crossFeedRatio = 0;
SimpleLock EmulationSettings::_equalizerLock;
NesModel EmulationSettings::_model = NesModel::Auto;
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 },
};
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)
{
if(ignoreTurbo) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -567,6 +567,7 @@ std::unordered_map<string, string> MessageManager::_caResources = {
std::list<string> MessageManager::_log;
SimpleLock MessageManager::_logLock;
SimpleLock MessageManager::_notificationLock;
IMessageManager* MessageManager::_messageManager = nullptr;
vector<INotificationListener*> MessageManager::_notificationListeners;
@ -651,16 +652,20 @@ string MessageManager::GetLog()
void MessageManager::RegisterNotificationListener(INotificationListener* notificationListener)
{
auto lock = _notificationLock.AcquireSafe();
MessageManager::_notificationListeners.push_back(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());
}
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
vector<INotificationListener*> listeners = MessageManager::_notificationListeners;
vector<INotificationListener*> processedListeners;

View File

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

View File

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

View File

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

View File

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

View File

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