modifying the protocol system to have bon synchronous and asynchronous updates (required by gui and graphics to avoid crashes because of threads)

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13246 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius 2013-07-15 14:31:14 +00:00
parent 72dd260bd1
commit 3bb6122f8e
31 changed files with 152 additions and 93 deletions

View File

@ -19,6 +19,7 @@ void NetworkWorld::update(float dt)
ProtocolManager::getInstance()->getProtocol(PROTOCOL_SYNCHRONIZATION));
if (protocol) // if this protocol exists, that's that we play online
{
Log::info("NetworkWorld", "Coutdown value is %d", protocol->getCountdown());
if (protocol->getCountdown() > 0)
{
return;

View File

@ -90,9 +90,13 @@ class Protocol
*/
virtual void unpause();
/*!
* \brief Called by the protocol listener as often as possible. Must be re-defined.
* \brief Called by the protocol listener, synchronously with the main loop. Must be re-defined.
*/
virtual void update() = 0;
/*!
* \brief Called by the protocol listener as often as possible. Must be re-defined.
*/
virtual void asynchronousUpdate() = 0;
/*!
* \brief Called when the protocol is to be killed.
*/

View File

@ -38,6 +38,16 @@ void* protocolManagerUpdate(void* data)
}
return NULL;
}
void* protocolManagerAsynchronousUpdate(void* data)
{
ProtocolManager* manager = static_cast<ProtocolManager*>(data);
while(!manager->exit())
{
manager->asynchronousUpdate();
irr_driver->getDevice()->sleep(20);
}
return NULL;
}
ProtocolManager::ProtocolManager()
{
@ -50,12 +60,15 @@ ProtocolManager::ProtocolManager()
pthread_mutex_lock(&m_exit_mutex); // will let the update function run
/// NOT USED on client but updated in main loop (because of GUI crash)
/// FIXME used on server because mainloop never running
if (NetworkManager::getInstance()->isServer())
{
m_update_thread = (pthread_t*)(malloc(sizeof(pthread_t)));
pthread_create(m_update_thread, NULL, protocolManagerUpdate, this);
}
// always run this one
m_asynchronous_update_thread = (pthread_t*)(malloc(sizeof(pthread_t)));
pthread_create(m_asynchronous_update_thread, NULL, protocolManagerAsynchronousUpdate, this);
}
ProtocolManager::~ProtocolManager()
@ -274,6 +287,18 @@ void ProtocolManager::propagateEvent(Event* event)
}
void ProtocolManager::update()
{
// now update all protocols
pthread_mutex_lock(&m_protocols_mutex);
for (unsigned int i = 0; i < m_protocols.size(); i++)
{
if (m_protocols[i].state == PROTOCOL_STATE_RUNNING)
m_protocols[i].protocol->update();
}
pthread_mutex_unlock(&m_protocols_mutex);
}
void ProtocolManager::asynchronousUpdate()
{
// before updating, notice protocols that they have received information
int size = m_events_to_process.size();
@ -287,16 +312,17 @@ void ProtocolManager::update()
propagateEvent(event);
}
// now update all protocols
// now update all protocols that need to be updated in asynchronous mode
pthread_mutex_lock(&m_protocols_mutex);
for (unsigned int i = 0; i < m_protocols.size(); i++)
{
if (m_protocols[i].state == PROTOCOL_STATE_RUNNING)
m_protocols[i].protocol->update();
m_protocols[i].protocol->asynchronousUpdate();
}
pthread_mutex_unlock(&m_protocols_mutex);
// process queued events for protocols
// these requests are asynchronous
pthread_mutex_lock(&m_requests_mutex);
for (unsigned int i = 0; i < m_requests.size(); i++)
{

View File

@ -158,10 +158,21 @@ class ProtocolManager : public Singleton<ProtocolManager>
* protocols that they have events to process. Then ask all protocols
* to update themselves. Finally processes stored requests about
* starting, stoping, pausing etc... protocols.
* This function is called by a thread as often as possible.
* This function is not FPS-dependant.
* This function is called by the main loop.
* This function IS FPS-dependant.
*/
virtual void update();
/*!
* \brief Updates the manager.
*
* This function processes the events queue, notifies the concerned
* protocols that they have events to process. Then ask all protocols
* to update themselves. Finally processes stored requests about
* starting, stoping, pausing etc... protocols.
* This function is called in a thread.
* This function IS NOT FPS-dependant.
*/
virtual void asynchronousUpdate();
/*!
* \brief Get the number of protocols running.
@ -296,6 +307,8 @@ class ProtocolManager : public Singleton<ProtocolManager>
/*! Update thread.*/
pthread_t* m_update_thread;
/*! Asynchronous update thread.*/
pthread_t* m_asynchronous_update_thread;
};

View File

@ -15,6 +15,7 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {}
protected:

View File

@ -31,7 +31,7 @@
// ----------------------------------------------------------------------------
ConnectToPeer::ConnectToPeer(uint32_t peer_id) :
ConnectToPeer::ConnectToPeer(uint32_t peer_id) :
Protocol(NULL, PROTOCOL_CONNECTION)
{
m_peer_id = peer_id;
@ -69,7 +69,7 @@ void ConnectToPeer::setup()
// ----------------------------------------------------------------------------
void ConnectToPeer::update()
void ConnectToPeer::asynchronousUpdate()
{
switch(m_state)
{
@ -80,11 +80,11 @@ void ConnectToPeer::update()
break;
}
case WAITING_PEER_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we know the peer address
{
if (m_peer_address.ip != 0 && m_peer_address.port != 0)
{
{
m_state = CONNECTING;
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_peer_address, 2.0));
}

View File

@ -28,17 +28,18 @@ class ConnectToPeer : public Protocol, public CallbackObject
public:
ConnectToPeer(uint32_t peer_id);
virtual ~ConnectToPeer();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
TransportAddress m_peer_address;
TransportAddress m_public_address;
uint32_t m_peer_id;
uint32_t m_current_protocol_id;
enum STATE
{
NONE,

View File

@ -33,7 +33,7 @@
// ----------------------------------------------------------------------------
ConnectToServer::ConnectToServer() :
ConnectToServer::ConnectToServer() :
Protocol(NULL, PROTOCOL_CONNECTION)
{
m_server_id = 0;
@ -43,7 +43,7 @@ ConnectToServer::ConnectToServer() :
// ----------------------------------------------------------------------------
ConnectToServer::ConnectToServer(uint32_t server_id) :
ConnectToServer::ConnectToServer(uint32_t server_id) :
Protocol(NULL, PROTOCOL_CONNECTION)
{
m_server_id = server_id;
@ -83,7 +83,7 @@ void ConnectToServer::setup()
// ----------------------------------------------------------------------------
void ConnectToServer::update()
void ConnectToServer::asynchronousUpdate()
{
switch(m_state)
{
@ -94,7 +94,7 @@ void ConnectToServer::update()
break;
}
case GETTING_SELF_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // now we know the public addr
{
m_state = SHOWING_SELF_ADDRESS;
@ -108,7 +108,7 @@ void ConnectToServer::update()
}
break;
case SHOWING_SELF_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // now our public address is in the database
{
if (m_quick_join)
@ -124,7 +124,7 @@ void ConnectToServer::update()
}
break;
case GETTING_SERVER_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we know the server address
{
m_state = REQUESTING_CONNECTION;
@ -132,10 +132,10 @@ void ConnectToServer::update()
}
break;
case REQUESTING_CONNECTION:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // server knows we wanna connect
{
if (m_server_address.ip == 0 || m_server_address.port == 0)
if (m_server_address.ip == 0 || m_server_address.port == 0)
{ // server data not correct, hide address and stop
m_state = HIDING_ADDRESS;
m_current_protocol_id = m_listener->requestStart(new HidePublicAddress());
@ -164,7 +164,7 @@ void ConnectToServer::update()
break;
}
case HIDING_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we have hidden our address
{
m_state = DONE;

View File

@ -29,18 +29,19 @@ class ConnectToServer : public Protocol, public CallbackObject
ConnectToServer(); //!< Quick join
ConnectToServer(uint32_t server_id); //!< Specify server id
virtual ~ConnectToServer();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
TransportAddress m_server_address;
TransportAddress m_public_address;
uint32_t m_server_id;
uint32_t m_current_protocol_id;
bool m_quick_join;
enum STATE
{
NONE,

View File

@ -44,7 +44,7 @@ void GetPeerAddress::setup()
m_state = NONE;
}
void GetPeerAddress::update()
void GetPeerAddress::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -26,22 +26,23 @@ class GetPeerAddress : public Protocol
public:
GetPeerAddress(uint32_t peer_id, CallbackObject* callback_object);
virtual ~GetPeerAddress();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
void setPeerID(uint32_t m_peer_id);
protected:
uint32_t m_peer_id;
enum STATE
enum STATE
{
NONE,
DONE
};
STATE m_state;
};
#endif // GET_PEER_ADDRESS_HPP

View File

@ -55,8 +55,8 @@ void GetPublicAddress::setup()
{
m_state = NOTHING_DONE;
}
void GetPublicAddress::update()
void GetPublicAddress::asynchronousUpdate()
{
if (m_state == NOTHING_DONE)
{
@ -66,22 +66,22 @@ void GetPublicAddress::update()
m_stun_tansaction_id[1] = stunRand();
m_stun_tansaction_id[2] = stunRand();
uint16_t message_length = 0x0000;
uint8_t bytes[21]; // the message to be sent
// bytes 0-1 : the type of the message,
// bytes 0-1 : the type of the message,
bytes[0] = (uint8_t)(message_type>>8);
bytes[1] = (uint8_t)(message_type);
// bytes 2-3 : message length added to header (attributes)
bytes[2] = (uint8_t)(message_length>>8);
bytes[3] = (uint8_t)(message_length);
// bytes 4-7 : magic cookie to recognize the stun protocol
bytes[4] = (uint8_t)(m_stun_magic_cookie>>24);
bytes[4] = (uint8_t)(m_stun_magic_cookie>>24);
bytes[5] = (uint8_t)(m_stun_magic_cookie>>16);
bytes[6] = (uint8_t)(m_stun_magic_cookie>>8);
bytes[7] = (uint8_t)(m_stun_magic_cookie);
// bytes 8-19 : the transaction id
bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24);
bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16);
@ -95,8 +95,8 @@ void GetPublicAddress::update()
bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16);
bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8);
bytes[19] = (uint8_t)(m_stun_tansaction_id[2]);
bytes[20] = '\0';
bytes[20] = '\0';
Log::verbose("GetPublicAddress", "Querrying STUN server 132.177.123.6");
unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6;
NetworkManager::getInstance()->setManualSocketsMode(true);
@ -108,7 +108,7 @@ void GetPublicAddress::update()
unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6;
uint8_t* data = NetworkManager::getInstance()->getHost()->receiveRawPacket(TransportAddress(dst, 3478));
assert(data);
// check that the stun response is a response, contains the magic cookie and the transaction ID
if ( data[0] == 0x01 &&
data[1] == 0x01 &&
@ -133,7 +133,7 @@ void GetPublicAddress::update()
{
Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer");
int message_size = data[2]*256+data[3];
// parse the stun message now:
bool finish = false;
uint8_t* attributes = data+20;
@ -149,7 +149,7 @@ void GetPublicAddress::update()
}
uint16_t port;
uint32_t address;
bool valid = false;
bool valid = false;
while(!finish)
{
int type = attributes[0]*256+attributes[1];
@ -160,13 +160,13 @@ void GetPublicAddress::update()
case 1:
assert(size == 8);
assert(attributes[5] = 0x01); // IPv4 only
port = attributes[6]*256+attributes[7];
port = attributes[6]*256+attributes[7];
address = (attributes[8]<<24 & 0xFF000000)+(attributes[9]<<16 & 0x00FF0000)+(attributes[10]<<8 & 0x0000FF00)+(attributes[11] & 0x000000FF);
finish = true;
valid = true;
continue;
break;
default:
default:
break;
}
attributes = attributes + 4 + size;
@ -184,15 +184,15 @@ void GetPublicAddress::update()
{
Log::debug("GetPublicAddress", "The public address has been found : %i.%i.%i.%i:%i", address>>24&0xff, address>>16&0xff, address>>8&0xff, address&0xff, port);
m_state = ADDRESS_KNOWN;
NetworkManager::getInstance()->setManualSocketsMode(false);
NetworkManager::getInstance()->setManualSocketsMode(false);
TransportAddress* addr = static_cast<TransportAddress*>(m_callback_object);
addr->ip = address;
addr->port = port;
}
else
else
m_state = NOTHING_DONE; // need to re-send the stun request
}
else
else
{
m_state = NOTHING_DONE; // need to re-send the stun request
}

View File

@ -26,12 +26,13 @@ class GetPublicAddress : public Protocol
public:
GetPublicAddress(CallbackObject* callback_object);
virtual ~GetPublicAddress();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
enum STATE
{

View File

@ -41,7 +41,7 @@ void HidePublicAddress::setup()
m_state = NONE;
}
void HidePublicAddress::update()
void HidePublicAddress::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -27,13 +27,14 @@ class HidePublicAddress : public Protocol
public:
HidePublicAddress();
virtual ~HidePublicAddress();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
enum STATE
{
NONE,

View File

@ -40,7 +40,7 @@ void PingProtocol::setup()
m_last_ping_time = 0;
}
void PingProtocol::update()
void PingProtocol::asynchronousUpdate()
{
if (Time::getRealTime() > m_last_ping_time+m_delay_between_pings)
{

View File

@ -9,11 +9,12 @@ class PingProtocol : public Protocol
public:
PingProtocol(const TransportAddress& ping_dst, double delay_between_pings);
virtual ~PingProtocol();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
TransportAddress m_ping_dst;
double m_delay_between_pings;

View File

@ -42,7 +42,7 @@ void QuickJoinProtocol::setup()
m_state = NONE;
}
void QuickJoinProtocol::update()
void QuickJoinProtocol::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -9,11 +9,12 @@ class QuickJoinProtocol : public Protocol
public:
QuickJoinProtocol(CallbackObject* callback_object, uint32_t* server_id);
virtual ~QuickJoinProtocol();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
uint32_t* m_server_id;
enum STATE

View File

@ -41,7 +41,7 @@ void RequestConnection::setup()
m_state = NONE;
}
void RequestConnection::update()
void RequestConnection::asynchronousUpdate()
{
switch (m_state)
{

View File

@ -8,21 +8,22 @@ class RequestConnection : public Protocol
public:
RequestConnection(uint32_t server_id);
virtual ~RequestConnection();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
uint32_t m_server_id;
enum STATE
{
NONE,
DONE
};
STATE m_state;
};
#endif // REQUEST_CONNECTION_HPP

View File

@ -12,6 +12,7 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {};
void startGame();

View File

@ -41,7 +41,7 @@ void ShowPublicAddress::setup()
m_state = NONE;
}
void ShowPublicAddress::update()
void ShowPublicAddress::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -27,13 +27,14 @@ class ShowPublicAddress : public Protocol
public:
ShowPublicAddress();
virtual ~ShowPublicAddress();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
enum STATE
{
NONE,

View File

@ -26,6 +26,7 @@ class StartGameProtocol : public Protocol
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {}
void ready();

View File

@ -40,7 +40,7 @@ void StartServer::setup()
m_state = NONE;
}
void StartServer::update()
void StartServer::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -4,7 +4,7 @@
#include "network/protocol.hpp"
/*!
* This protocol tells to the database that the server is up and running,
* This protocol tells to the database that the server is up and running,
* and shows online the public IP:port that stores the NetworkManager.
*/
class StartServer : public Protocol
@ -12,11 +12,12 @@ class StartServer : public Protocol
public:
StartServer();
virtual ~StartServer();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
enum STATE
{

View File

@ -40,7 +40,7 @@ void StopServer::setup()
m_state = NONE;
}
void StopServer::update()
void StopServer::asynchronousUpdate()
{
if (m_state == NONE)
{

View File

@ -12,11 +12,12 @@ class StopServer : public Protocol
public:
StopServer();
virtual ~StopServer();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
protected:
enum STATE
{

View File

@ -103,7 +103,7 @@ void SynchronizationProtocol::setup()
//-----------------------------------------------------------------------------
void SynchronizationProtocol::update()
void SynchronizationProtocol::asynchronousUpdate()
{
static double timer = Time::getRealTime();
double current_time = Time::getRealTime();
@ -123,7 +123,7 @@ void SynchronizationProtocol::update()
if (m_countdown_activated)
{
ns.ai16(m_countdown);
Log::info("SynchronizationProtocol", "Countdown value : %u", m_countdown);
Log::info("SynchronizationProtocol", "Countdown value : %d", m_countdown);
}
Log::verbose("SynchronizationProtocol", "Added sequence number %u for peer %d", m_pings[i].size(), i);
timer = current_time;
@ -131,7 +131,7 @@ void SynchronizationProtocol::update()
m_listener->sendMessage(this, peers[i], ns, false);
m_pings_count[i]++;
}
Log::info("SynchronizationProtocol", "Countdown remaining : %u", m_countdown);
Log::info("SynchronizationProtocol", "Countdown remaining : %d", m_countdown);
}
}

View File

@ -13,7 +13,8 @@ class SynchronizationProtocol : public Protocol
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
virtual void update() {}
virtual void asynchronousUpdate();
void startCountdown(int ms_countdown);