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
5354struct 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
7773private:
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)
111104struct 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;
138128typedef 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
180181namespace 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
188185void 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
204199std::unique_ptr<crossplat::threadpool> crossplat::threadpool::construct (size_t num_threads)
0 commit comments