diff --git a/src/Main.cc b/src/Main.cc index 9387cbbc..64350df4 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -2361,7 +2361,7 @@ Action a_run_server_replay_log( } if (evthread_use_pthreads()) { - throw runtime_error("failed to setup libevent threads"); + throw runtime_error("failed to set up libevent threads"); } if (!isdir("system/players")) { diff --git a/src/PatchServer.cc b/src/PatchServer.cc index 33bdcebf..a82509f8 100644 --- a/src/PatchServer.cc +++ b/src/PatchServer.cc @@ -395,17 +395,31 @@ void PatchServer::on_client_error(Channel& ch, short events) { } PatchServer::PatchServer(shared_ptr config) - : base(event_base_new(), event_base_free), - config(config), - destroy_clients_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &PatchServer::dispatch_destroy_clients, this), event_free), - th(&PatchServer::thread_fn, this) {} + : config(config) { + if (config->shared_base) { + this->base = config->shared_base; + this->base_is_shared = true; + } else { + this->base.reset(event_base_new(), event_base_free); + this->base_is_shared = false; + } + this->destroy_clients_ev.reset( + event_new(this->base.get(), -1, EV_TIMEOUT, &PatchServer::dispatch_destroy_clients, this), event_free); + if (!this->base_is_shared) { + this->th = thread(&PatchServer::thread_fn, this); + } +} void PatchServer::schedule_stop() { - event_base_loopexit(this->base.get(), nullptr); + if (!this->base_is_shared) { + event_base_loopexit(this->base.get(), nullptr); + } } void PatchServer::wait_for_stop() { - this->th.join(); + if (!this->base_is_shared) { + this->th.join(); + } } void PatchServer::listen(const std::string& addr_str, const string& socket_path, Version version) { diff --git a/src/PatchServer.hh b/src/PatchServer.hh index b1796844..24653be4 100644 --- a/src/PatchServer.hh +++ b/src/PatchServer.hh @@ -22,6 +22,7 @@ public: std::string message; std::shared_ptr license_index; std::shared_ptr patch_file_index; + std::shared_ptr shared_base; }; PatchServer() = delete; @@ -86,6 +87,7 @@ private: }; std::shared_ptr base; + bool base_is_shared; std::shared_ptr config; std::unordered_set> clients_to_destroy; diff --git a/src/ServerState.cc b/src/ServerState.cc index a18cb4bf..ecea29ff 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -1787,6 +1787,14 @@ void ServerState::load_all() { shared_ptr ServerState::generate_patch_server_config(bool is_bb) const { auto ret = make_shared(); +#ifdef PHOSG_WINDOWS + // libevent doesn't play nice with Cygwin, so we run the patch server on the + // main thread there. The problem seems to be that the locking structures are + // never set up, presumably since we call event_use_pthreads() since + // event_use_windows_threads() doesn't exist. (Does literally no one else use + // libevent with Cygwin??) + ret->shared_base = this->base; +#endif ret->allow_unregistered_users = this->allow_unregistered_users; ret->hide_data_from_logs = this->hide_download_commands; ret->idle_timeout_usecs = this->patch_client_idle_timeout_usecs;