Commit 72c484ad authored by Dominik Charousset's avatar Dominik Charousset

Auto-init WSAStartup etc. when using CAF_MAIN

parent 9f9e701a
...@@ -109,6 +109,39 @@ public: ...@@ -109,6 +109,39 @@ public:
actor_system(const actor_system&) = delete; actor_system(const actor_system&) = delete;
actor_system& operator=(const actor_system&) = delete; actor_system& operator=(const actor_system&) = delete;
/// Calls a cleanup function in its destructor for cleaning up global state.
class [[nodiscard]] global_state_guard {
public:
using void_fun_t = void (*)();
explicit global_state_guard(void_fun_t f) : fun_(f) {
// nop
}
global_state_guard(global_state_guard&& other) noexcept : fun_(other.fun_) {
other.fun_ = nullptr;
}
global_state_guard& operator=(global_state_guard&& other) noexcept {
std::swap(fun_, other.fun_);
return *this;
}
global_state_guard() = delete;
global_state_guard(const global_state_guard&) = delete;
global_state_guard& operator=(const global_state_guard&) = delete;
~global_state_guard() {
if (fun_ != nullptr)
fun_();
}
private:
void_fun_t fun_;
};
/// An (optional) component of the actor system. /// An (optional) component of the actor system.
class CAF_CORE_EXPORT module { class CAF_CORE_EXPORT module {
public: public:
......
...@@ -1060,6 +1060,23 @@ template <class T> ...@@ -1060,6 +1060,23 @@ template <class T>
constexpr bool is_64bit_integer_v = std::is_same_v<T, int64_t> constexpr bool is_64bit_integer_v = std::is_same_v<T, int64_t>
|| std::is_same_v<T, uint64_t>; || std::is_same_v<T, uint64_t>;
/// Checks whether `T` has a static member function called `init_host_system`.
template <class T>
struct has_init_host_system {
template <class U>
static auto sfinae(U*) -> decltype(U::init_host_system(), std::true_type());
template <class U>
static auto sfinae(...) -> std::false_type;
using type = decltype(sfinae<T>(nullptr));
static constexpr bool value = type::value;
};
/// Convenience alias for `has_init_host_system<T>::value`.
template <class T>
constexpr bool has_init_host_system_v = has_init_host_system<T>::value;
} // namespace caf::detail } // namespace caf::detail
#undef CAF_HAS_MEMBER_TRAIT #undef CAF_HAS_MEMBER_TRAIT
......
...@@ -105,8 +105,28 @@ int exec_main(F fun, int argc, char** argv) { ...@@ -105,8 +105,28 @@ int exec_main(F fun, int argc, char** argv) {
} // namespace caf } // namespace caf
namespace caf::detail {
template <class... Module>
auto do_init_host_system(type_list<Module...>, type_list<>) {
return std::make_tuple(Module::init_host_system()...);
}
template <class... Module, class T, class... Ts>
auto do_init_host_system(type_list<Module...>, type_list<T, Ts...>) {
if constexpr (detail::has_init_host_system_v<T>) {
return do_init_host_system(type_list<Module..., T>{}, type_list<Ts...>{});
} else {
return do_init_host_system(type_list<Module...>{}, type_list<Ts...>{});
}
}
} // namespace caf::detail
#define CAF_MAIN(...) \ #define CAF_MAIN(...) \
int main(int argc, char** argv) { \ int main(int argc, char** argv) { \
[[maybe_unused]] auto host_init_guard = caf::detail::do_init_host_system( \
caf::detail::type_list<>{}, caf::detail::type_list<__VA_ARGS__>{}); \
caf::exec_main_init_meta_objects<__VA_ARGS__>(); \ caf::exec_main_init_meta_objects<__VA_ARGS__>(); \
caf::core::init_global_meta_objects(); \ caf::core::init_global_meta_objects(); \
return caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \ return caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \
......
...@@ -569,10 +569,14 @@ void default_multiplexer::handle_socket_event(native_socket fd, int mask, ...@@ -569,10 +569,14 @@ void default_multiplexer::handle_socket_event(native_socket fd, int mask,
void default_multiplexer::init() { void default_multiplexer::init() {
#ifdef CAF_WINDOWS #ifdef CAF_WINDOWS
// Note: when loading the caf-net module, users should call
// net::middleman::init_host_system() or net::this_host::startup().
if (!system().has_network_manager()) {
WSADATA WinsockData; WSADATA WinsockData;
if (WSAStartup(MAKEWORD(2, 2), &WinsockData) != 0) { if (WSAStartup(MAKEWORD(2, 2), &WinsockData) != 0) {
CAF_CRITICAL("WSAStartup failed"); CAF_CRITICAL("WSAStartup failed");
} }
}
#endif #endif
namespace sr = defaults::scheduler; namespace sr = defaults::scheduler;
max_throughput_ = get_or(system().config(), "caf.scheduler.max-throughput", max_throughput_ = get_or(system().config(), "caf.scheduler.max-throughput",
...@@ -631,6 +635,7 @@ default_multiplexer::~default_multiplexer() { ...@@ -631,6 +635,7 @@ default_multiplexer::~default_multiplexer() {
close_socket(pipe_reader_.fd()); close_socket(pipe_reader_.fd());
pipe_reader_.init(invalid_native_socket); pipe_reader_.init(invalid_native_socket);
#ifdef CAF_WINDOWS #ifdef CAF_WINDOWS
if (!system().has_network_manager())
WSACleanup(); WSACleanup();
#endif #endif
} }
......
...@@ -23,16 +23,28 @@ namespace caf::net { ...@@ -23,16 +23,28 @@ namespace caf::net {
/// Provides a network backend for running protocol stacks. /// Provides a network backend for running protocol stacks.
class CAF_NET_EXPORT middleman : public actor_system::module { class CAF_NET_EXPORT middleman : public actor_system::module {
public: public:
// -- constants --------------------------------------------------------------
/// Identifies the network manager module.
actor_system::module::id_t id_v = actor_system::module::network_manager;
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
using module = actor_system::module; using module = actor_system::module;
using module_ptr = actor_system::module_ptr; using module_ptr = actor_system::module_ptr;
using void_fun_t = void (*)();
// -- static utility functions ----------------------------------------------- // -- static utility functions -----------------------------------------------
static void init_global_meta_objects(); static void init_global_meta_objects();
/// Initializes global state for the network backend by calling
/// platform-dependent functions such as `WSAStartup` and `ssl::startup()`.
/// @returns a guard object shutting down the global state.
static actor_system::global_state_guard init_host_system();
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
explicit middleman(actor_system& sys); explicit middleman(actor_system& sys);
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/net/http/with.hpp" #include "caf/net/http/with.hpp"
#include "caf/net/prometheus.hpp" #include "caf/net/prometheus.hpp"
#include "caf/net/ssl/startup.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/tcp_stream_socket.hpp" #include "caf/net/tcp_stream_socket.hpp"
#include "caf/net/this_host.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/send.hpp" #include "caf/send.hpp"
...@@ -57,6 +59,15 @@ void middleman::init_global_meta_objects() { ...@@ -57,6 +59,15 @@ void middleman::init_global_meta_objects() {
// nop // nop
} }
actor_system::global_state_guard middleman::init_host_system() {
this_host::startup();
ssl::startup();
return actor_system::global_state_guard{+[] {
ssl::cleanup();
this_host::cleanup();
}};
}
middleman::middleman(actor_system& sys) middleman::middleman(actor_system& sys)
: sys_(sys), mpx_(multiplexer::make(this)) { : sys_(sys), mpx_(multiplexer::make(this)) {
// nop // nop
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment