mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-20 20:23:03 +02:00
Shared memory refactoring and command line control options
Now client accept following options: --disable-shm - disable shared memory usage --enable-shm-uuid - use UUID for shared memory identifier UUID is useful when a lot of clients starting simultaneously. Needed for testing and was easier to implement than alternatives.
This commit is contained in:
parent
a2284c3209
commit
1a60c1a94b
3
Global.h
3
Global.h
@ -185,6 +185,9 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
#include <boost/multi_array.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
|
@ -260,6 +260,8 @@ int main(int argc, char** argv)
|
||||
opts.add_options()
|
||||
("help,h", "display help and exit")
|
||||
("version,v", "display version information and exit")
|
||||
("disable-shm", "force disable shared memory usage")
|
||||
("enable-shm-uuid", "use UUID for shared memory identifier")
|
||||
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
|
||||
("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
|
||||
("testmap", po::value<std::string>(), "")
|
||||
@ -345,6 +347,9 @@ int main(int argc, char** argv)
|
||||
session["headless"].Bool() = true;
|
||||
session["onlyai"].Bool() = true;
|
||||
}
|
||||
// Shared memory options
|
||||
session["disable-shm"].Bool() = vm.count("disable-shm");
|
||||
session["enable-shm-uuid"].Bool() = vm.count("enable-shm-uuid");
|
||||
|
||||
// Init special testing settings
|
||||
session["serverport"].Integer() = vm.count("serverport") ? vm["serverport"].as<si64>() : 0;
|
||||
|
@ -41,9 +41,7 @@
|
||||
#include "CMT.h"
|
||||
|
||||
extern std::string NAME;
|
||||
#ifndef VCMI_ANDROID
|
||||
namespace intpr = boost::interprocess;
|
||||
#else
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "lib/CAndroidVMHelper.h"
|
||||
#endif
|
||||
|
||||
@ -1019,13 +1017,7 @@ void CServerHandler::waitForServer()
|
||||
|
||||
#ifndef VCMI_ANDROID
|
||||
if(shared)
|
||||
{
|
||||
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
||||
while(!shared->sr->ready)
|
||||
{
|
||||
shared->sr->cond.wait(slock);
|
||||
}
|
||||
}
|
||||
shared->sr->waitTillReady();
|
||||
#else
|
||||
logNetwork->infoStream() << "waiting for server";
|
||||
while (!androidTestServerReadyFlag.load())
|
||||
@ -1042,15 +1034,7 @@ void CServerHandler::waitForServer()
|
||||
|
||||
CConnection * CServerHandler::connectToServer()
|
||||
{
|
||||
#ifndef VCMI_ANDROID
|
||||
if(shared)
|
||||
{
|
||||
if(!shared->sr->ready)
|
||||
waitForServer();
|
||||
}
|
||||
#else
|
||||
waitForServer();
|
||||
#endif
|
||||
|
||||
th.update(); //put breakpoint here to attach to server before it does something stupid
|
||||
|
||||
@ -1084,15 +1068,21 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
|
||||
serverThread = nullptr;
|
||||
shared = nullptr;
|
||||
verbose = true;
|
||||
uuid = boost::uuids::to_string(boost::uuids::random_generator()());
|
||||
|
||||
#ifndef VCMI_ANDROID
|
||||
if(DO_NOT_START_SERVER)
|
||||
if(DO_NOT_START_SERVER || settings["session"]["disable-shm"].Bool())
|
||||
return;
|
||||
|
||||
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
||||
std::string sharedMemoryName = "vcmi_memory";
|
||||
if(settings["session"]["enable-shm-uuid"].Bool())
|
||||
{
|
||||
//used or automated testing when multiple clients start simultaneously
|
||||
sharedMemoryName += "_" + uuid;
|
||||
}
|
||||
try
|
||||
{
|
||||
shared = new SharedMem();
|
||||
shared = new SharedMemory(sharedMemoryName, true);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -1115,11 +1105,17 @@ void CServerHandler::callServer()
|
||||
#ifndef VCMI_ANDROID
|
||||
setThreadName("CServerHandler::callServer");
|
||||
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
|
||||
const std::string comm = VCMIDirs::get().serverPath().string()
|
||||
std::string comm = VCMIDirs::get().serverPath().string()
|
||||
+ " --port=" + getDefaultPortStr()
|
||||
+ " --run-by-client"
|
||||
+ (shared ? " --use-shm" : "")
|
||||
+ " > \"" + logName + '\"';
|
||||
+ " --uuid=" + uuid;
|
||||
if(shared)
|
||||
{
|
||||
comm += " --enable-shm";
|
||||
if(settings["session"]["enable-shm-uuid"].Bool())
|
||||
comm += " --enable-shm-uuid";
|
||||
}
|
||||
comm += " > \"" + logName + '\"';
|
||||
|
||||
int result = std::system(comm.c_str());
|
||||
if (result == 0)
|
||||
|
@ -28,7 +28,7 @@ class CGameInterface;
|
||||
class CConnection;
|
||||
class CCallback;
|
||||
struct BattleAction;
|
||||
struct SharedMem;
|
||||
struct SharedMemory;
|
||||
class CClient;
|
||||
class CScriptingModule;
|
||||
struct CPathsInfo;
|
||||
@ -46,7 +46,8 @@ public:
|
||||
|
||||
CStopWatch th;
|
||||
boost::thread *serverThread; //thread that called system to run server
|
||||
SharedMem *shared; //interprocess memory (for waiting for server)
|
||||
SharedMemory * shared;
|
||||
std::string uuid;
|
||||
bool verbose; //whether to print log msgs
|
||||
|
||||
//functions setting up local server
|
||||
|
@ -20,8 +20,8 @@ struct ServerReady
|
||||
{
|
||||
bool ready;
|
||||
uint16_t port; //ui16?
|
||||
boost::interprocess::interprocess_mutex mutex;
|
||||
boost::interprocess::interprocess_condition cond;
|
||||
boost::interprocess::interprocess_mutex mutex;
|
||||
boost::interprocess::interprocess_condition cond;
|
||||
|
||||
ServerReady()
|
||||
{
|
||||
@ -29,10 +29,19 @@ struct ServerReady
|
||||
port = 0;
|
||||
}
|
||||
|
||||
void setToTrueAndNotify(uint16_t Port)
|
||||
void waitTillReady()
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> slock(mutex);
|
||||
while(!ready)
|
||||
{
|
||||
cond.wait(slock);
|
||||
}
|
||||
}
|
||||
|
||||
void setToReadyAndNotify(const uint16_t Port)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::interprocess::interprocess_mutex> lock(mutex);
|
||||
boost::unique_lock<boost::interprocess::interprocess_mutex> lock(mutex);
|
||||
ready = true;
|
||||
port = Port;
|
||||
}
|
||||
@ -40,22 +49,33 @@ struct ServerReady
|
||||
}
|
||||
};
|
||||
|
||||
struct SharedMem
|
||||
struct SharedMemory
|
||||
{
|
||||
const char * name;
|
||||
boost::interprocess::shared_memory_object smo;
|
||||
boost::interprocess::mapped_region *mr;
|
||||
ServerReady *sr;
|
||||
boost::interprocess::mapped_region * mr;
|
||||
ServerReady * sr;
|
||||
|
||||
SharedMem() //c-tor
|
||||
:smo(boost::interprocess::open_or_create,"vcmi_memory",boost::interprocess::read_write)
|
||||
SharedMemory(std::string Name, bool initialize = false)
|
||||
: name(Name.c_str())
|
||||
{
|
||||
if(initialize)
|
||||
{
|
||||
//if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
||||
boost::interprocess::shared_memory_object::remove(name);
|
||||
}
|
||||
smo = boost::interprocess::shared_memory_object(boost::interprocess::open_or_create, name, boost::interprocess::read_write);
|
||||
smo.truncate(sizeof(ServerReady));
|
||||
mr = new boost::interprocess::mapped_region(smo,boost::interprocess::read_write);
|
||||
sr = new(mr->get_address())ServerReady();
|
||||
if(initialize)
|
||||
sr = new(mr->get_address())ServerReady();
|
||||
else
|
||||
sr = reinterpret_cast<ServerReady*>(mr->get_address());
|
||||
};
|
||||
~SharedMem() //d-tor
|
||||
|
||||
~SharedMemory()
|
||||
{
|
||||
delete mr;
|
||||
boost::interprocess::shared_memory_object::remove("vcmi_memory");
|
||||
boost::interprocess::shared_memory_object::remove(name);
|
||||
}
|
||||
};
|
||||
|
@ -41,9 +41,6 @@
|
||||
|
||||
std::string NAME_AFFIX = "server";
|
||||
std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||
#ifndef VCMI_ANDROID
|
||||
namespace intpr = boost::interprocess;
|
||||
#endif
|
||||
std::atomic<bool> serverShuttingDown(false);
|
||||
|
||||
boost::program_options::variables_map cmdLineOptions;
|
||||
@ -326,7 +323,7 @@ void CPregameServer::startListeningThread(CConnection * pc)
|
||||
}
|
||||
|
||||
CVCMIServer::CVCMIServer()
|
||||
: port(3030), io(new boost::asio::io_service()), firstConnection(nullptr)
|
||||
: port(3030), io(new boost::asio::io_service()), firstConnection(nullptr), shared(nullptr)
|
||||
{
|
||||
logNetwork->trace("CVCMIServer created!");
|
||||
if(cmdLineOptions.count("port"))
|
||||
@ -339,7 +336,7 @@ CVCMIServer::CVCMIServer()
|
||||
catch(...)
|
||||
{
|
||||
logNetwork->info("Port %d is busy, trying to use random port instead", port);
|
||||
if(cmdLineOptions.count("run-by-client") && !cmdLineOptions.count("use-shm"))
|
||||
if(cmdLineOptions.count("run-by-client") && !cmdLineOptions.count("enable-shm"))
|
||||
{
|
||||
logNetwork->error("Cant pass port number to client without shared memory!", port);
|
||||
exit(0);
|
||||
@ -425,24 +422,14 @@ void CVCMIServer::newPregame()
|
||||
void CVCMIServer::start()
|
||||
{
|
||||
#ifndef VCMI_ANDROID
|
||||
ServerReady *sr = nullptr;
|
||||
intpr::mapped_region *mr;
|
||||
if(cmdLineOptions.count("use-shm"))
|
||||
if(cmdLineOptions.count("enable-shm"))
|
||||
{
|
||||
try
|
||||
std::string sharedMemoryName = "vcmi_memory";
|
||||
if(cmdLineOptions.count("enable-shm-uuid") && cmdLineOptions.count("uuid"))
|
||||
{
|
||||
intpr::shared_memory_object smo(intpr::open_only,"vcmi_memory",intpr::read_write);
|
||||
smo.truncate(sizeof(ServerReady));
|
||||
mr = new intpr::mapped_region(smo,intpr::read_write);
|
||||
sr = reinterpret_cast<ServerReady*>(mr->get_address());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
intpr::shared_memory_object smo(intpr::create_only,"vcmi_memory",intpr::read_write);
|
||||
smo.truncate(sizeof(ServerReady));
|
||||
mr = new intpr::mapped_region(smo,intpr::read_write);
|
||||
sr = new(mr->get_address())ServerReady();
|
||||
sharedMemoryName += "_" + cmdLineOptions["uuid"].as<std::string>();
|
||||
}
|
||||
shared = new SharedMemory(sharedMemoryName);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -460,10 +447,9 @@ void CVCMIServer::start()
|
||||
logNetwork->info("Sending server ready message to client");
|
||||
}
|
||||
#else
|
||||
if(cmdLineOptions.count("use-shm"))
|
||||
if(shared)
|
||||
{
|
||||
sr->setToTrueAndNotify(port);
|
||||
delete mr;
|
||||
shared->sr->setToReadyAndNotify(port);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -557,7 +543,9 @@ static void handleCommandOptions(int argc, char *argv[])
|
||||
("help,h", "display help and exit")
|
||||
("version,v", "display version information and exit")
|
||||
("run-by-client", "indicate that server launched by client on same machine")
|
||||
("use-shm", "enable usage of shared memory")
|
||||
("uuid", po::value<std::string>(), "")
|
||||
("enable-shm-uuid", "use UUID for shared memory identifier")
|
||||
("enable-shm", "enable usage of shared memory")
|
||||
("port", po::value<ui16>(), "port at which server will listen to connections from client")
|
||||
("resultsFile", po::value<std::string>()->default_value("./results.txt"), "file to which the battle result will be appended. Used only in the DUEL mode.");
|
||||
|
||||
|
@ -17,6 +17,7 @@ class CMapInfo;
|
||||
class CConnection;
|
||||
struct CPackForSelectionScreen;
|
||||
class CGameHandler;
|
||||
struct SharedMemory;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@ -46,6 +47,7 @@ class CVCMIServer
|
||||
ui16 port;
|
||||
boost::asio::io_service *io;
|
||||
TAcceptor * acceptor;
|
||||
SharedMemory * shared;
|
||||
|
||||
CConnection *firstConnection;
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user