Merge branch 'develop' into cmake-cleanup

develop
lethosor 2019-07-20 15:15:39 -04:00
commit 8a07426643
7 changed files with 173 additions and 65 deletions

@ -346,9 +346,10 @@ if(APPLE)
endif() endif()
endif() endif()
if(NOT EXTERNAL_LIBSTDCXX)
install(PROGRAMS ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib install(PROGRAMS ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib
DESTINATION ./hack/) DESTINATION ./hack/)
endif()
endif() endif()
#### expose depends #### #### expose depends ####

@ -95,6 +95,12 @@ list(APPEND SRC_LIBLUA ${HDR_LIBLUA})
add_library(lua SHARED ${SRC_LIBLUA}) add_library(lua SHARED ${SRC_LIBLUA})
target_link_libraries(lua ${LIBS}) target_link_libraries(lua ${LIBS})
if(MSVC)
target_compile_options(lua PRIVATE /FI dfhack_llimits.h)
else()
target_compile_options(lua PRIVATE -include dfhack_llimits.h)
endif()
install(TARGETS lua install(TARGETS lua
LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION}
RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION})

@ -0,0 +1,61 @@
/**
Copyright © 2018 Pauli <suokkos@gmail.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#ifdef _MSC_VER
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <stdlib.h>
/*! \file dfhack_llimits.h
* dfhack specific lua porting header that overrides lua defaults for thread
* safety.
*/
#ifdef _MSC_VER
typedef CRITICAL_SECTION mutex_t;
#else
typedef pthread_mutex_t mutex_t;
#endif
struct lua_extra_state {
mutex_t* mutex;
};
#define luai_mutex(L) ((lua_extra_state*)lua_getextraspace(L))->mutex
#ifdef _MSC_VER
#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); InitializeCriticalSection(luai_mutex(L))
#define luai_userstateclose(L) lua_unlock(L); DeleteCriticalSection(luai_mutex(L)); free(luai_mutex(L))
#define lua_lock(L) EnterCriticalSection(luai_mutex(L))
#define lua_unlock(L) LeaveCriticalSection(luai_mutex(L))
#else
#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); *luai_mutex(L) = PTHREAD_MUTEX_INITIALIZER
#define luai_userstateclose(L) lua_unlock(L); pthread_mutex_destroy(luai_mutex(L)); free(luai_mutex(L))
#define lua_lock(L) pthread_mutex_lock(luai_mutex(L))
#define lua_unlock(L) pthread_mutex_unlock(luai_mutex(L))
#endif

@ -1427,6 +1427,7 @@ bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
static void run_dfhack_init(color_ostream &out, Core *core) static void run_dfhack_init(color_ostream &out, Core *core)
{ {
CoreSuspender lock;
if (!df::global::world || !df::global::ui || !df::global::gview) if (!df::global::world || !df::global::ui || !df::global::gview)
{ {
out.printerr("Key globals are missing, skipping loading dfhack.init.\n"); out.printerr("Key globals are missing, skipping loading dfhack.init.\n");
@ -1528,6 +1529,7 @@ Core::Core() :
HotkeyMutex{}, HotkeyMutex{},
HotkeyCond{}, HotkeyCond{},
alias_mutex{}, alias_mutex{},
started{false},
misc_data_mutex{}, misc_data_mutex{},
CoreSuspendMutex{}, CoreSuspendMutex{},
CoreWakeup{}, CoreWakeup{},
@ -1537,7 +1539,7 @@ Core::Core() :
// init the console. This must be always the first step! // init the console. This must be always the first step!
plug_mgr = 0; plug_mgr = 0;
errorstate = false; errorstate = false;
started = false; vinfo = 0;
memset(&(s_mods), 0, sizeof(s_mods)); memset(&(s_mods), 0, sizeof(s_mods));
// set up hotkey capture // set up hotkey capture
@ -1547,7 +1549,6 @@ Core::Core() :
last_pause_state = false; last_pause_state = false;
top_viewscreen = NULL; top_viewscreen = NULL;
screen_window = NULL; screen_window = NULL;
server = NULL;
color_ostream::log_errors_to_stderr = true; color_ostream::log_errors_to_stderr = true;
@ -1765,6 +1766,8 @@ bool Core::Init()
// create plugin manager // create plugin manager
plug_mgr = new PluginManager(this); plug_mgr = new PluginManager(this);
plug_mgr->init(); plug_mgr->init();
cerr << "Starting the TCP listener.\n";
auto listen = ServerMain::listen(RemoteClient::GetDefaultPort());
IODATA *temp = new IODATA; IODATA *temp = new IODATA;
temp->core = this; temp->core = this;
temp->plug_mgr = plug_mgr; temp->plug_mgr = plug_mgr;
@ -1789,9 +1792,7 @@ bool Core::Init()
started = true; started = true;
modstate = 0; modstate = 0;
cerr << "Starting the TCP listener.\n"; if (!listen.get())
server = new ServerMain();
if (!server->listen(RemoteClient::GetDefaultPort()))
cerr << "TCP listen failed.\n"; cerr << "TCP listen failed.\n";
if (df::global::ui_sidebar_menus) if (df::global::ui_sidebar_menus)
@ -2294,6 +2295,8 @@ int Core::Shutdown ( void )
HotkeyCond.notify_one(); HotkeyCond.notify_one();
} }
ServerMain::block();
d->hotkeythread.join(); d->hotkeythread.join();
d->iothread.join(); d->iothread.join();

@ -57,12 +57,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sstream> #include <sstream>
#include <memory> #include <memory>
#include <thread>
#include "json/json.h" #include "json/json.h"
#include "tinythread.h"
using namespace DFHack; using namespace DFHack;
using namespace tthread;
using dfproto::CoreTextNotification; using dfproto::CoreTextNotification;
using dfproto::CoreTextFragment; using dfproto::CoreTextFragment;
@ -72,6 +71,30 @@ bool readFullBuffer(CSimpleSocket *socket, void *buf, int size);
bool sendRemoteMessage(CSimpleSocket *socket, int16_t id, bool sendRemoteMessage(CSimpleSocket *socket, int16_t id,
const ::google::protobuf::MessageLite *msg, bool size_ready); const ::google::protobuf::MessageLite *msg, bool size_ready);
std::mutex ServerMain::access_{};
bool ServerMain::blocked_{};
namespace {
struct BlockedException : std::exception {
const char* what() const noexcept override
{
return "Core has blocked all connection. This should have been catched.";
}
};
}
namespace DFHack {
struct BlockGuard {
std::lock_guard<std::mutex> lock;
BlockGuard() :
lock{ServerMain::access_}
{
if (ServerMain::blocked_)
throw BlockedException{};
}
};
}
RPCService::RPCService() RPCService::RPCService()
{ {
@ -134,9 +157,6 @@ ServerConnection::ServerConnection(CActiveSocket *socket)
core_service = new CoreService(); core_service = new CoreService();
core_service->finalize(this, &functions); core_service->finalize(this, &functions);
thread = new tthread::thread(threadFn, (void*)this);
thread->detach();
} }
ServerConnection::~ServerConnection() ServerConnection::~ServerConnection()
@ -144,7 +164,6 @@ ServerConnection::~ServerConnection()
in_error = true; in_error = true;
socket->Close(); socket->Close();
delete socket; delete socket;
delete thread;
for (auto it = plugin_services.begin(); it != plugin_services.end(); ++it) for (auto it = plugin_services.begin(); it != plugin_services.end(); ++it)
delete it->second; delete it->second;
@ -216,13 +235,14 @@ void ServerConnection::connection_ostream::flush_proxy()
} }
} }
void ServerConnection::threadFn(void *arg) void ServerConnection::Accepted(CActiveSocket* socket)
{ {
ServerConnection *me = (ServerConnection*)arg; std::thread{[](CActiveSocket* socket) {
try {
me->threadFn(); ServerConnection(socket).threadFn();
} catch (BlockedException e) {
delete me; }
}, socket}.detach();
} }
void ServerConnection::threadFn() void ServerConnection::threadFn()
@ -292,6 +312,7 @@ void ServerConnection::threadFn()
// Find and call the function // Find and call the function
int in_size = header.size; int in_size = header.size;
BlockGuard lock;
ServerFunctionBase *fn = vector_get(functions, header.id); ServerFunctionBase *fn = vector_get(functions, header.id);
MessageLite *reply = NULL; MessageLite *reply = NULL;
@ -378,25 +399,21 @@ void ServerConnection::threadFn()
std::cerr << "Shutting down client connection." << endl; std::cerr << "Shutting down client connection." << endl;
} }
ServerMain::ServerMain() namespace {
{
socket = new CPassiveSocket(); struct ServerMainImpl : public ServerMain {
thread = NULL; CPassiveSocket socket;
} static void threadFn(std::promise<bool> promise, int port);
ServerMainImpl(std::promise<bool> promise, int port);
~ServerMainImpl();
};
ServerMain::~ServerMain()
{
socket->Close();
delete socket;
delete thread;
} }
bool ServerMain::listen(int port) ServerMainImpl::ServerMainImpl(std::promise<bool> promise, int port) :
socket{}
{ {
if (thread) socket.Initialize();
return true;
socket->Initialize();
std::string filename("dfhack-config/remote-server.json"); std::string filename("dfhack-config/remote-server.json");
@ -427,29 +444,49 @@ bool ServerMain::listen(int port)
} }
std::cerr << "Listening on port " << port << (allow_remote ? " (remote enabled)" : "") << std::endl; std::cerr << "Listening on port " << port << (allow_remote ? " (remote enabled)" : "") << std::endl;
if (allow_remote) const char* addr = allow_remote ? NULL : "127.0.0.1";
{ if (!socket.Listen(addr, port)) {
if (!socket->Listen(NULL, port)) promise.set_value(false);
return false; return;
}
else
{
if (!socket->Listen("127.0.0.1", port))
return false;
} }
promise.set_value(true);
}
thread = new tthread::thread(threadFn, this); ServerMainImpl::~ServerMainImpl()
thread->detach(); {
return true; socket.Close();
} }
void ServerMain::threadFn(void *arg) std::future<bool> ServerMain::listen(int port)
{ {
ServerMain *me = (ServerMain*)arg; std::promise<bool> promise;
CActiveSocket *client; auto rv = promise.get_future();
std::thread{&ServerMainImpl::threadFn, std::move(promise), port}.detach();
return rv;
}
void ServerMainImpl::threadFn(std::promise<bool> promise, int port)
{
ServerMainImpl server{std::move(promise), port};
CActiveSocket *client = nullptr;
while ((client = me->socket->Accept()) != NULL) try {
while ((client = server.socket.Accept()) != NULL)
{ {
new ServerConnection(client); BlockGuard lock;
ServerConnection::Accepted(client);
client = nullptr;
} }
} catch(BlockedException e) {
if (client)
client->Close();
delete client;
}
}
void ServerMain::block()
{
std::lock_guard<std::mutex> lock{access_};
blocked_ = true;
} }

@ -283,7 +283,7 @@ namespace DFHack
df::viewscreen *top_viewscreen; df::viewscreen *top_viewscreen;
bool last_pause_state; bool last_pause_state;
// Very important! // Very important!
bool started; std::atomic<bool> started;
// Additional state change scripts // Additional state change scripts
std::vector<StateChangeScript> state_change_scripts; std::vector<StateChangeScript> state_change_scripts;
@ -308,7 +308,6 @@ namespace DFHack
friend class CoreSuspenderBase; friend class CoreSuspenderBase;
friend struct CoreSuspendClaimMain; friend struct CoreSuspendClaimMain;
friend struct CoreSuspendReleaseMain; friend struct CoreSuspendReleaseMain;
ServerMain *server;
}; };
class CoreSuspenderBase : protected std::unique_lock<std::recursive_mutex> { class CoreSuspenderBase : protected std::unique_lock<std::recursive_mutex> {

@ -28,6 +28,8 @@ distribution.
#include "RemoteClient.h" #include "RemoteClient.h"
#include "Core.h" #include "Core.h"
#include <future>
class CPassiveSocket; class CPassiveSocket;
class CActiveSocket; class CActiveSocket;
class CSimpleSocket; class CSimpleSocket;
@ -233,26 +235,25 @@ namespace DFHack
CoreService *core_service; CoreService *core_service;
std::map<std::string, RPCService*> plugin_services; std::map<std::string, RPCService*> plugin_services;
tthread::thread *thread;
static void threadFn(void *);
void threadFn(); void threadFn();
ServerConnection(CActiveSocket* socket);
~ServerConnection();
public: public:
ServerConnection(CActiveSocket *socket);
~ServerConnection(); static void Accepted(CActiveSocket* socket);
ServerFunctionBase *findFunction(color_ostream &out, const std::string &plugin, const std::string &name); ServerFunctionBase *findFunction(color_ostream &out, const std::string &plugin, const std::string &name);
}; };
class ServerMain { class ServerMain {
CPassiveSocket *socket; static std::mutex access_;
static bool blocked_;
friend struct BlockGuard;
tthread::thread *thread;
static void threadFn(void *);
public: public:
ServerMain();
~ServerMain();
bool listen(int port); static std::future<bool> listen(int port);
static void block();
}; };
} }