Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove use of aligned_union that broke CentOS 7. #987

Merged
merged 5 commits into from
Dec 7, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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