Skip to content

Commit 65267c6

Browse files
authored
Remove use of aligned_union that broke CentOS 7. (#987)
1 parent 744f33b commit 65267c6

File tree

1 file changed

+61
-66
lines changed

1 file changed

+61
-66
lines changed

Release/src/pplx/threadpool.cpp

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
/***
2-
* Copyright (C) Microsoft. All rights reserved.
3-
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4-
*
5-
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
6-
**/
2+
* Copyright (C) Microsoft. All rights reserved.
3+
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
**/
75
#include "stdafx.h"
86

97
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32)
108
#include "pplx/threadpool.h"
119

1210
#include <boost/asio/detail/thread.hpp>
1311
#include <new>
14-
#include <vector>
1512
#include <type_traits>
13+
#include <utility>
14+
#include <vector>
1615

1716
#if defined(__ANDROID__)
1817
#include <android/log.h>
@@ -29,9 +28,11 @@ static void abort_if_no_jvm()
2928
{
3029
if (JVM == nullptr)
3130
{
32-
__android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s",
33-
"The CppREST SDK must be initialized before first use on android: "
34-
"https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android");
31+
__android_log_print(ANDROID_LOG_ERROR,
32+
"CPPRESTSDK",
33+
"%s",
34+
"The CppREST SDK must be initialized before first use on android: "
35+
"https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android");
3536
std::abort();
3637
}
3738
}
@@ -52,9 +53,7 @@ JNIEnv* get_jvm_env()
5253

5354
struct threadpool_impl final : crossplat::threadpool
5455
{
55-
threadpool_impl(size_t n)
56-
: crossplat::threadpool(n)
57-
, m_work(m_service)
56+
threadpool_impl(size_t n) : crossplat::threadpool(n), m_work(m_service)
5857
{
5958
for (size_t i = 0; i < n; i++)
6059
add_thread();
@@ -69,26 +68,20 @@ struct threadpool_impl final : crossplat::threadpool
6968
}
7069
}
7170

72-
threadpool_impl& get_shared()
73-
{
74-
return *this;
75-
}
71+
threadpool_impl& get_shared() { return *this; }
7672

7773
private:
7874
void add_thread()
7975
{
80-
m_threads.push_back(std::unique_ptr<boost::asio::detail::thread>(
81-
new boost::asio::detail::thread([&]{ thread_start(this); })));
76+
m_threads.push_back(
77+
std::unique_ptr<boost::asio::detail::thread>(new boost::asio::detail::thread([&] { thread_start(this); })));
8278
}
8379

8480
#if defined(__ANDROID__)
85-
static void detach_from_java(void*)
86-
{
87-
JVM.load()->DetachCurrentThread();
88-
}
81+
static void detach_from_java(void*) { JVM.load()->DetachCurrentThread(); }
8982
#endif // __ANDROID__
9083

91-
static void* thread_start(void *arg) CPPREST_NOEXCEPT
84+
static void* thread_start(void* arg) CPPREST_NOEXCEPT
9285
{
9386
#if defined(__ANDROID__)
9487
// Calling get_jvm_env() here forces the thread to be attached.
@@ -110,17 +103,14 @@ struct threadpool_impl final : crossplat::threadpool
110103
#if defined(_WIN32)
111104
struct shared_threadpool
112105
{
113-
std::aligned_union<0, threadpool_impl>::type shared_storage;
106+
union {
107+
threadpool_impl shared_storage;
108+
};
114109

115-
threadpool_impl& get_shared()
116-
{
117-
return reinterpret_cast<threadpool_impl&>(shared_storage);
118-
}
110+
threadpool_impl& get_shared() { return shared_storage; }
111+
112+
shared_threadpool(size_t n) : shared_storage(n) {}
119113

120-
shared_threadpool(size_t n)
121-
{
122-
::new (static_cast<void*>(&get_shared())) threadpool_impl(n);
123-
}
124114
~shared_threadpool()
125115
{
126116
// if linked into a DLL, the threadpool shared instance will be
@@ -138,52 +128,59 @@ typedef shared_threadpool platform_shared_threadpool;
138128
typedef threadpool_impl platform_shared_threadpool;
139129
#endif
140130

141-
std::pair<bool, platform_shared_threadpool*> initialize_shared_threadpool(size_t num_threads)
131+
namespace
142132
{
143-
static std::aligned_union<0, platform_shared_threadpool>::type storage;
144-
platform_shared_threadpool* const ptr =
145-
&reinterpret_cast<platform_shared_threadpool&>(storage);
146-
bool initialized_this_time = false;
147-
#if defined(__ANDROID__)
148-
// mutex based implementation due to paranoia about (lack of) call_once support on Android
149-
// remove this if/when call_once is supported
150-
static std::mutex mtx;
151-
static std::atomic<bool> initialized;
152-
abort_if_no_jvm();
153-
if (!initialized.load())
133+
template<class T>
134+
struct uninitialized
135+
{
136+
union {
137+
T storage;
138+
};
139+
140+
bool initialized;
141+
142+
uninitialized() CPPREST_NOEXCEPT : initialized(false) {}
143+
uninitialized(const uninitialized&) = delete;
144+
uninitialized& operator=(const uninitialized&) = delete;
145+
~uninitialized()
154146
{
155-
std::lock_guard<std::mutex> guard(mtx);
156-
if (!initialized.load())
147+
if (initialized)
157148
{
158-
::new (static_cast<void*>(ptr)) platform_shared_threadpool(num_threads);
159-
initialized.store(true);
160-
initialized_this_time = true;
149+
storage.~T();
161150
}
162-
} // also unlock
151+
}
152+
153+
template<class... Args>
154+
void construct(Args&&... vals)
155+
{
156+
::new (static_cast<void*>(&storage)) T(std::forward<Args>(vals)...);
157+
initialized = true;
158+
}
159+
};
160+
} // unnamed namespace
163161

164-
#else // ^^^ __ANDROID__ ^^^ // vvv !__ANDROID___ vvv //
162+
std::pair<bool, platform_shared_threadpool*> initialize_shared_threadpool(size_t num_threads)
163+
{
164+
static uninitialized<platform_shared_threadpool> uninit_threadpool;
165+
bool initialized_this_time = false;
165166
static std::once_flag of;
166167

167-
// #if defined(__ANDROID__) // if call_once can be used for android
168-
// abort_if_no_jvm();
169-
// #endif // __ANDROID__
170-
std::call_once(of, [num_threads, ptr, &initialized_this_time] {
171-
::new (static_cast<void*>(ptr)) platform_shared_threadpool(num_threads);
168+
#if defined(__ANDROID__)
169+
abort_if_no_jvm();
170+
#endif // __ANDROID__
171+
172+
std::call_once(of, [num_threads, &initialized_this_time] {
173+
uninit_threadpool.construct(num_threads);
172174
initialized_this_time = true;
173175
});
174-
#endif // __ANDROID__
175176

176-
return {initialized_this_time, ptr};
177+
return {initialized_this_time, &uninit_threadpool.storage};
177178
}
178179
}
179180

180181
namespace crossplat
181182
{
182-
threadpool& threadpool::shared_instance()
183-
{
184-
return initialize_shared_threadpool(40).second->get_shared();
185-
}
186-
183+
threadpool& threadpool::shared_instance() { return initialize_shared_threadpool(40).second->get_shared(); }
187184

188185
void threadpool::initialize_with_threads(size_t num_threads)
189186
{
@@ -196,9 +193,7 @@ void threadpool::initialize_with_threads(size_t num_threads)
196193
}
197194

198195
#if defined(__ANDROID__)
199-
void cpprest_init(JavaVM* vm) {
200-
JVM = vm;
201-
}
196+
void cpprest_init(JavaVM* vm) { JVM = vm; }
202197
#endif
203198

204199
std::unique_ptr<crossplat::threadpool> crossplat::threadpool::construct(size_t num_threads)

0 commit comments

Comments
 (0)