diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 1c28cca8f7..58920c0253 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -1,9 +1,7 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + **/ #include "stdafx.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) @@ -11,8 +9,9 @@ #include #include -#include #include +#include +#include #if defined(__ANDROID__) #include @@ -29,9 +28,11 @@ 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"); + __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(); } } @@ -52,9 +53,7 @@ JNIEnv* get_jvm_env() struct threadpool_impl final : crossplat::threadpool { - threadpool_impl(size_t n) - : crossplat::threadpool(n) - , m_work(m_service) + threadpool_impl(size_t n) : crossplat::threadpool(n), m_work(m_service) { for (size_t i = 0; i < n; i++) add_thread(); @@ -69,26 +68,20 @@ struct threadpool_impl final : crossplat::threadpool } } - threadpool_impl& get_shared() - { - return *this; - } + threadpool_impl& get_shared() { return *this; } private: void add_thread() { - m_threads.push_back(std::unique_ptr( - new boost::asio::detail::thread([&]{ thread_start(this); }))); + m_threads.push_back( + std::unique_ptr(new boost::asio::detail::thread([&] { thread_start(this); }))); } #if defined(__ANDROID__) - static void detach_from_java(void*) - { - JVM.load()->DetachCurrentThread(); - } + static void detach_from_java(void*) { JVM.load()->DetachCurrentThread(); } #endif // __ANDROID__ - static void* thread_start(void *arg) CPPREST_NOEXCEPT + static void* thread_start(void* arg) CPPREST_NOEXCEPT { #if defined(__ANDROID__) // Calling get_jvm_env() here forces the thread to be attached. @@ -110,17 +103,14 @@ struct threadpool_impl final : crossplat::threadpool #if defined(_WIN32) struct shared_threadpool { - std::aligned_union<0, threadpool_impl>::type shared_storage; + union { + threadpool_impl shared_storage; + }; - threadpool_impl& get_shared() - { - return reinterpret_cast(shared_storage); - } + threadpool_impl& get_shared() { return shared_storage; } + + shared_threadpool(size_t n) : shared_storage(n) {} - shared_threadpool(size_t n) - { - ::new (static_cast(&get_shared())) threadpool_impl(n); - } ~shared_threadpool() { // if linked into a DLL, the threadpool shared instance will be @@ -138,52 +128,59 @@ typedef shared_threadpool platform_shared_threadpool; typedef threadpool_impl platform_shared_threadpool; #endif -std::pair initialize_shared_threadpool(size_t num_threads) +namespace { - static std::aligned_union<0, platform_shared_threadpool>::type storage; - platform_shared_threadpool* const ptr = - &reinterpret_cast(storage); - bool initialized_this_time = false; -#if defined(__ANDROID__) - // mutex based implementation due to paranoia about (lack of) call_once support on Android - // remove this if/when call_once is supported - static std::mutex mtx; - static std::atomic initialized; - abort_if_no_jvm(); - if (!initialized.load()) +template +struct uninitialized +{ + union { + T storage; + }; + + bool initialized; + + uninitialized() CPPREST_NOEXCEPT : initialized(false) {} + uninitialized(const uninitialized&) = delete; + uninitialized& operator=(const uninitialized&) = delete; + ~uninitialized() { - std::lock_guard guard(mtx); - if (!initialized.load()) + if (initialized) { - ::new (static_cast(ptr)) platform_shared_threadpool(num_threads); - initialized.store(true); - initialized_this_time = true; + storage.~T(); } - } // also unlock + } + + template + void construct(Args&&... vals) + { + ::new (static_cast(&storage)) T(std::forward(vals)...); + initialized = true; + } +}; +} // unnamed namespace -#else // ^^^ __ANDROID__ ^^^ // vvv !__ANDROID___ vvv // +std::pair initialize_shared_threadpool(size_t num_threads) +{ + static uninitialized uninit_threadpool; + bool initialized_this_time = false; static std::once_flag of; -// #if defined(__ANDROID__) // if call_once can be used for android -// abort_if_no_jvm(); -// #endif // __ANDROID__ - std::call_once(of, [num_threads, ptr, &initialized_this_time] { - ::new (static_cast(ptr)) platform_shared_threadpool(num_threads); + #if defined(__ANDROID__) + abort_if_no_jvm(); + #endif // __ANDROID__ + + std::call_once(of, [num_threads, &initialized_this_time] { + uninit_threadpool.construct(num_threads); initialized_this_time = true; }); -#endif // __ANDROID__ - return {initialized_this_time, ptr}; + return {initialized_this_time, &uninit_threadpool.storage}; } } namespace crossplat { -threadpool& threadpool::shared_instance() -{ - return initialize_shared_threadpool(40).second->get_shared(); -} - +threadpool& threadpool::shared_instance() { return initialize_shared_threadpool(40).second->get_shared(); } void threadpool::initialize_with_threads(size_t num_threads) { @@ -196,9 +193,7 @@ void threadpool::initialize_with_threads(size_t num_threads) } #if defined(__ANDROID__) -void cpprest_init(JavaVM* vm) { - JVM = vm; -} +void cpprest_init(JavaVM* vm) { JVM = vm; } #endif std::unique_ptr crossplat::threadpool::construct(size_t num_threads)