From 8111f2f3128ce5aefad17e80c74a8c39f6d006a9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 13:11:32 -0700 Subject: [PATCH] Factor shared threadpool setup/teardown behavior out of platform dependent policies. --- Release/src/pplx/threadpool.cpp | 130 ++++++++++++++++---------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index d2dc6161a2..f96c2c5109 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -10,7 +10,9 @@ #include "pplx/threadpool.h" #include +#include #include +#include #if defined(__ANDROID__) #include @@ -19,6 +21,32 @@ namespace { +#if defined(__ANDROID__) +// This pointer will be 0-initialized by default (at load time). +std::atomic JVM; + +JNIEnv* get_jvm_env() +{ + abort_if_no_jvm(); + JNIEnv* env = nullptr; + auto result = JVM.load()->AttachCurrentThread(&env, nullptr); + if (result != JNI_OK) + { + throw std::runtime_error("Could not attach to JVM"); + } + + return env; +} + +static void abort_if_no_jvm() +{ + if (JVM == nullptr) + { + __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); + std::abort(); + } +} +#endif // __ANDROID__ struct threadpool_impl final : crossplat::threadpool { @@ -39,6 +67,11 @@ struct threadpool_impl final : crossplat::threadpool } } + threadpool_impl& get_shared() + { + return *this; + } + private: void add_thread() { @@ -50,7 +83,7 @@ struct threadpool_impl final : crossplat::threadpool { crossplat::JVM.load()->DetachCurrentThread(); } -#endif +#endif // __ANDROID__ static void* thread_start(void *arg) CPPREST_NOEXCEPT { @@ -58,95 +91,62 @@ struct threadpool_impl final : crossplat::threadpool // Calling get_jvm_env() here forces the thread to be attached. crossplat::get_jvm_env(); pthread_cleanup_push(detach_from_java, nullptr); -#endif +#endif // __ANDROID__ threadpool_impl* _this = reinterpret_cast(arg); _this->m_service.run(); #if defined(__ANDROID__) pthread_cleanup_pop(true); -#endif +#endif // __ANDROID__ return arg; } std::vector> m_threads; boost::asio::io_service::work m_work; }; -} -namespace crossplat +#if defined(_WIN32) +struct shared_threadpool { -#if defined(__ANDROID__) -// This pointer will be 0-initialized by default (at load time). -std::atomic JVM; + typename std::aligned_union<0, threadpool_impl>::type shared_storage; -static void abort_if_no_jvm() -{ - if (JVM == nullptr) + threadpool_impl& get_shared() { - __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); - std::abort(); + return reinterpret_cast(shared_storage); } -} -JNIEnv* get_jvm_env() -{ - abort_if_no_jvm(); - JNIEnv* env = nullptr; - auto result = JVM.load()->AttachCurrentThread(&env, nullptr); - if (result != JNI_OK) + shared_threadpool(size_t n) { - throw std::runtime_error("Could not attach to JVM"); + ::new (static_cast(&get_shared())) threadpool_impl(n); } - - return env; -} - -threadpool& threadpool::shared_instance() -{ - abort_if_no_jvm(); - static threadpool_impl s_shared(40); - return s_shared; -} - -#elif defined(_WIN32) - -// if linked into a DLL, the threadpool shared instance will be destroyed at DLL_PROCESS_DETACH, -// at which stage joining threads causes deadlock, hence this dance -threadpool& threadpool::shared_instance() -{ - static bool terminate_threads = false; - static struct restore_terminate_threads + ~shared_threadpool() { - ~restore_terminate_threads() - { - boost::asio::detail::thread::set_terminate_threads(terminate_threads); - } - } destroyed_after; - - static threadpool_impl s_shared(40); + // if linked into a DLL, the threadpool shared instance will be + // destroyed at DLL_PROCESS_DETACH, at which stage joining threads + // causes deadlock, hence this dance + bool terminate_threads = boost::asio::detail::thread::terminate_threads(); + boost::asio::detail::thread::set_terminate_threads(true); + get_shared().~threadpool_impl(); + boost::asio::detail::thread::set_terminate_threads(terminate_threads); + } +}; - static struct enforce_terminate_threads - { - ~enforce_terminate_threads() - { - terminate_threads = boost::asio::detail::thread::terminate_threads(); - boost::asio::detail::thread::set_terminate_threads(true); - } - } destroyed_before; +typedef shared_threadpool platform_shared_threadpool; +#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv // +typedef threadpool_impl platform_shared_threadpool; +#endif - return s_shared; } -#else - -// initialize the static shared threadpool +namespace crossplat +{ threadpool& threadpool::shared_instance() { - static threadpool_impl s_shared(40); - return s_shared; +#if defined(__ANDROID__) + abort_if_no_jvm(); +#endif // __ANDROID__ + static platform_shared_threadpool s_shared_impl(40); + return s_shared_impl.get_shared(); } - -#endif - } #if defined(__ANDROID__) @@ -159,4 +159,4 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } -#endif +#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32)