Skip to content

Commit

Permalink
Remove use of aligned_union that broke CentOS 7. (#987)
Browse files Browse the repository at this point in the history
  • Loading branch information
BillyONeal authored Dec 7, 2018
1 parent 744f33b commit 65267c6
Showing 1 changed file with 61 additions and 66 deletions.
127 changes: 61 additions & 66 deletions Release/src/pplx/threadpool.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
/***
* 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)
#include "pplx/threadpool.h"

#include <boost/asio/detail/thread.hpp>
#include <new>
#include <vector>
#include <type_traits>
#include <utility>
#include <vector>

#if defined(__ANDROID__)
#include <android/log.h>
Expand All @@ -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();
}
}
Expand All @@ -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();
Expand All @@ -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<boost::asio::detail::thread>(
new boost::asio::detail::thread([&]{ thread_start(this); })));
m_threads.push_back(
std::unique_ptr<boost::asio::detail::thread>(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.
Expand All @@ -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<threadpool_impl&>(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<void*>(&get_shared())) threadpool_impl(n);
}
~shared_threadpool()
{
// if linked into a DLL, the threadpool shared instance will be
Expand All @@ -138,52 +128,59 @@ typedef shared_threadpool platform_shared_threadpool;
typedef threadpool_impl platform_shared_threadpool;
#endif

std::pair<bool, platform_shared_threadpool*> 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<platform_shared_threadpool&>(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<bool> initialized;
abort_if_no_jvm();
if (!initialized.load())
template<class T>
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<std::mutex> guard(mtx);
if (!initialized.load())
if (initialized)
{
::new (static_cast<void*>(ptr)) platform_shared_threadpool(num_threads);
initialized.store(true);
initialized_this_time = true;
storage.~T();
}
} // also unlock
}

template<class... Args>
void construct(Args&&... vals)
{
::new (static_cast<void*>(&storage)) T(std::forward<Args>(vals)...);
initialized = true;
}
};
} // unnamed namespace

#else // ^^^ __ANDROID__ ^^^ // vvv !__ANDROID___ vvv //
std::pair<bool, platform_shared_threadpool*> initialize_shared_threadpool(size_t num_threads)
{
static uninitialized<platform_shared_threadpool> 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<void*>(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)
{
Expand All @@ -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> crossplat::threadpool::construct(size_t num_threads)
Expand Down

0 comments on commit 65267c6

Please sign in to comment.