mutex fixes, server shutdown works again

This commit is contained in:
Max-Wilhelm Bruker 2012-03-17 19:05:22 +01:00
parent d792c3ddc6
commit 671214c60e
9 changed files with 34 additions and 27 deletions

View file

@ -9,7 +9,6 @@ LocalServerInterface::LocalServerInterface(LocalServer *_server)
LocalServerInterface::~LocalServerInterface() LocalServerInterface::~LocalServerInterface()
{ {
prepareDestroy();
} }
void LocalServerInterface::transmitProtocolItem(const ServerMessage &item) void LocalServerInterface::transmitProtocolItem(const ServerMessage &item)

View file

@ -32,7 +32,7 @@
#include <QDebug> #include <QDebug>
Server::Server(QObject *parent) Server::Server(QObject *parent)
: QObject(parent), nextGameId(0), nextReplayId(0) : QObject(parent), nextGameId(0), nextReplayId(0), clientsLock(QReadWriteLock::Recursive)
{ {
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game"); qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room"); qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
@ -45,17 +45,17 @@ Server::~Server()
void Server::prepareDestroy() void Server::prepareDestroy()
{ {
clientsLock.lockForWrite();
while (!clients.isEmpty())
clients.first()->prepareDestroy();
clientsLock.unlock();
roomsLock.lockForWrite(); roomsLock.lockForWrite();
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) while (roomIterator.hasNext())
delete roomIterator.next().value(); delete roomIterator.next().value();
rooms.clear(); rooms.clear();
roomsLock.unlock(); roomsLock.unlock();
clientsLock.lockForWrite();
while (!clients.isEmpty())
delete clients.takeFirst();
clientsLock.unlock();
} }
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr) AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr)

View file

@ -307,6 +307,12 @@ void Server_Game::stopGameIfFinished()
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions) Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
{ {
{
QMapIterator<int, Server_Player *> playerIterator(players);
while (playerIterator.hasNext())
if (playerIterator.next().value()->getUserInfo()->name() == user->name())
return Response::RespContextError;
}
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) { if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
if ((_password != password) && !(spectator && !spectatorsNeedPassword)) if ((_password != password) && !(spectator && !spectatorsNeedPassword))
return Response::RespWrongPassword; return Response::RespWrongPassword;

View file

@ -98,9 +98,6 @@ Server_ProtocolHandler::~Server_ProtocolHandler()
{ {
} }
// This is essentially the destructor, but it needs to be called from the
// child's destructor so that the server mutex does not get unlocked during
// finalization.
void Server_ProtocolHandler::prepareDestroy() void Server_ProtocolHandler::prepareDestroy()
{ {
qDebug("Server_ProtocolHandler::prepareDestroy"); qDebug("Server_ProtocolHandler::prepareDestroy");
@ -146,6 +143,8 @@ void Server_ProtocolHandler::prepareDestroy()
r->gamesMutex.unlock(); r->gamesMutex.unlock();
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
deleteLater();
} }
void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game) void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game)
@ -437,7 +436,7 @@ void Server_ProtocolHandler::pingClockTimeout()
} }
if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime())
deleteLater(); prepareDestroy();
++timeRunning; ++timeRunning;
} }
@ -486,7 +485,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
QMapIterator<int, Server_Room *> roomIterator(server->getRooms()); QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
gameListMutex.lock();
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
room->gamesMutex.lock(); room->gamesMutex.lock();
@ -498,7 +496,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
for (int j = 0; j < gamePlayers.size(); ++j) for (int j = 0; j < gamePlayers.size(); ++j)
if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) { if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) {
gamePlayers[j]->setProtocolHandler(this); gamePlayers[j]->setProtocolHandler(this);
gameListMutex.lock();
games.insert(game->getGameId(), QPair<int, int>(room->getId(), gamePlayers[j]->getPlayerId())); games.insert(game->getGameId(), QPair<int, int>(room->getId(), gamePlayers[j]->getPlayerId()));
gameListMutex.unlock();
Event_GameJoined event1; Event_GameJoined event1;
event1.set_game_id(game->getGameId()); event1.set_game_id(game->getGameId());
@ -526,7 +527,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
} }
room->gamesMutex.unlock(); room->gamesMutex.unlock();
} }
gameListMutex.unlock();
server->roomsLock.unlock(); server->roomsLock.unlock();
rc.setResponseExtension(re); rc.setResponseExtension(re);
@ -777,11 +777,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QMutexLocker locker(&gameListMutex);
if (games.contains(cmd.game_id()))
return Response::RespContextError;
room->gamesMutex.lock(); room->gamesMutex.lock();
Server_Game *g = room->getGames().value(cmd.game_id()); Server_Game *g = room->getGames().value(cmd.game_id());
if (!g) { if (!g) {
@ -795,7 +790,9 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
if (result == Response::RespOk) { if (result == Response::RespOk) {
Server_Player *player = g->addPlayer(this, cmd.spectator()); Server_Player *player = g->addPlayer(this, cmd.spectator());
gameListMutex.lock();
games.insert(cmd.game_id(), QPair<int, int>(room->getId(), player->getPlayerId())); games.insert(cmd.game_id(), QPair<int, int>(room->getId(), player->getPlayerId()));
gameListMutex.unlock();
Event_GameJoined event1; Event_GameJoined event1;
event1.set_game_id(g->getGameId()); event1.set_game_id(g->getGameId());

View file

@ -95,7 +95,6 @@ protected:
bool acceptsUserListChanges; bool acceptsUserListChanges;
bool acceptsRoomListChanges; bool acceptsRoomListChanges;
void prepareDestroy();
int sessionId; int sessionId;
private: private:
QMutex gameListMutex; QMutex gameListMutex;
@ -174,6 +173,8 @@ private slots:
void pingClockTimeout(); void pingClockTimeout();
signals: signals:
void logDebugMessage(const QString &message, Server_ProtocolHandler *session); void logDebugMessage(const QString &message, Server_ProtocolHandler *session);
public slots:
void prepareDestroy();
public: public:
Server_ProtocolHandler(Server *_server, QObject *parent = 0); Server_ProtocolHandler(Server *_server, QObject *parent = 0);
~Server_ProtocolHandler(); ~Server_ProtocolHandler();

View file

@ -128,7 +128,6 @@ int main(int argc, char *argv[])
loggerThread = new QThread; loggerThread = new QThread;
logger = new ServerLogger; logger = new ServerLogger;
logger->moveToThread(loggerThread); logger->moveToThread(loggerThread);
QObject::connect(logger, SIGNAL(destroyed()), loggerThread, SLOT(quit()));
loggerThread->start(); loggerThread->start();
QMetaObject::invokeMethod(logger, "startLog", Qt::BlockingQueuedConnection, Q_ARG(QString, settings->value("server/logfile").toString())); QMetaObject::invokeMethod(logger, "startLog", Qt::BlockingQueuedConnection, Q_ARG(QString, settings->value("server/logfile").toString()));

View file

@ -82,6 +82,8 @@ class Servatrice : public Server
private slots: private slots:
void statusUpdate(); void statusUpdate();
void shutdownTimeout(); void shutdownTimeout();
public slots:
void scheduleShutdown(const QString &reason, int minutes);
public: public:
mutable QMutex dbMutex; mutable QMutex dbMutex;
Servatrice(QSettings *_settings, QObject *parent = 0); Servatrice(QSettings *_settings, QObject *parent = 0);
@ -110,7 +112,6 @@ public:
QMap<QString, ServerInfo_User> getIgnoreList(const QString &name); QMap<QString, ServerInfo_User> getIgnoreList(const QString &name);
bool isInBuddyList(const QString &whoseList, const QString &who); bool isInBuddyList(const QString &whoseList, const QString &who);
bool isInIgnoreList(const QString &whoseList, const QString &who); bool isInIgnoreList(const QString &whoseList, const QString &who);
void scheduleShutdown(const QString &reason, int minutes);
void incTxBytes(quint64 num); void incTxBytes(quint64 num);
void incRxBytes(quint64 num); void incRxBytes(quint64 num);
int getUserIdInDB(const QString &name); int getUserIdInDB(const QString &name);

View file

@ -16,6 +16,8 @@ ServerLogger::ServerLogger(QObject *parent)
ServerLogger::~ServerLogger() ServerLogger::~ServerLogger()
{ {
flushBuffer(); flushBuffer();
// This does not work with the destroyed() signal as this destructor is called after the main event loop is done.
thread()->quit();
} }
void ServerLogger::startLog(const QString &logFileName) void ServerLogger::startLog(const QString &logFileName)

View file

@ -60,8 +60,9 @@ static const int protocolVersion = 13;
ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent) ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent)
: Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), messageInProgress(false) : Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), messageInProgress(false)
{ {
bool success = true;
connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError)));
connect(this, SIGNAL(outputBufferChanged()), this, SLOT(flushOutputBuffer()), Qt::QueuedConnection); connect(this, SIGNAL(outputBufferChanged()), this, SLOT(flushOutputBuffer()), Qt::QueuedConnection);
@ -81,18 +82,19 @@ ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_s
sendProtocolItem(*se); sendProtocolItem(*se);
delete se; delete se;
deleteLater(); success = false;
} }
server->addClient(this); server->addClient(this);
if (!success)
prepareDestroy();
} }
ServerSocketInterface::~ServerSocketInterface() ServerSocketInterface::~ServerSocketInterface()
{ {
logger->logMessage("ServerSocketInterface destructor", this); logger->logMessage("ServerSocketInterface destructor", this);
prepareDestroy();
flushOutputBuffer(); flushOutputBuffer();
delete socket; delete socket;
socket = 0; socket = 0;
@ -143,7 +145,7 @@ void ServerSocketInterface::catchSocketError(QAbstractSocket::SocketError socket
{ {
qDebug() << "Socket error:" << socketError; qDebug() << "Socket error:" << socketError;
deleteLater(); prepareDestroy();
} }
void ServerSocketInterface::transmitProtocolItem(const ServerMessage &item) void ServerSocketInterface::transmitProtocolItem(const ServerMessage &item)
@ -623,7 +625,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban
for (int i = 0; i < userList.size(); ++i) { for (int i = 0; i < userList.size(); ++i) {
SessionEvent *se = userList[i]->prepareSessionEvent(event); SessionEvent *se = userList[i]->prepareSessionEvent(event);
userList[i]->sendProtocolItem(*se); userList[i]->sendProtocolItem(*se);
userList[i]->deleteLater(); userList[i]->prepareDestroy();
delete se; delete se;
} }
} }