1
1
/* **
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
+ **/
7
5
#include " stdafx.h"
8
6
9
7
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32)
10
8
#include " pplx/threadpool.h"
11
9
12
10
#include < boost/asio/detail/thread.hpp>
13
11
#include < new>
14
- #include < vector>
15
12
#include < type_traits>
13
+ #include < utility>
14
+ #include < vector>
16
15
17
16
#if defined(__ANDROID__)
18
17
#include < android/log.h>
@@ -29,9 +28,11 @@ static void abort_if_no_jvm()
29
28
{
30
29
if (JVM == nullptr )
31
30
{
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" );
35
36
std::abort ();
36
37
}
37
38
}
@@ -52,9 +53,7 @@ JNIEnv* get_jvm_env()
52
53
53
54
struct threadpool_impl final : crossplat::threadpool
54
55
{
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)
58
57
{
59
58
for (size_t i = 0 ; i < n; i++)
60
59
add_thread ();
@@ -69,26 +68,20 @@ struct threadpool_impl final : crossplat::threadpool
69
68
}
70
69
}
71
70
72
- threadpool_impl& get_shared ()
73
- {
74
- return *this ;
75
- }
71
+ threadpool_impl& get_shared () { return *this ; }
76
72
77
73
private:
78
74
void add_thread ()
79
75
{
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 ); })));
82
78
}
83
79
84
80
#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 (); }
89
82
#endif // __ANDROID__
90
83
91
- static void * thread_start (void * arg) CPPREST_NOEXCEPT
84
+ static void * thread_start (void * arg) CPPREST_NOEXCEPT
92
85
{
93
86
#if defined(__ANDROID__)
94
87
// Calling get_jvm_env() here forces the thread to be attached.
@@ -110,17 +103,14 @@ struct threadpool_impl final : crossplat::threadpool
110
103
#if defined(_WIN32)
111
104
struct shared_threadpool
112
105
{
113
- std::aligned_union<0 , threadpool_impl>::type shared_storage;
106
+ union {
107
+ threadpool_impl shared_storage;
108
+ };
114
109
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) {}
119
113
120
- shared_threadpool (size_t n)
121
- {
122
- ::new (static_cast <void *>(&get_shared ())) threadpool_impl (n);
123
- }
124
114
~shared_threadpool ()
125
115
{
126
116
// if linked into a DLL, the threadpool shared instance will be
@@ -138,52 +128,59 @@ typedef shared_threadpool platform_shared_threadpool;
138
128
typedef threadpool_impl platform_shared_threadpool;
139
129
#endif
140
130
141
- std::pair< bool , platform_shared_threadpool*> initialize_shared_threadpool ( size_t num_threads)
131
+ namespace
142
132
{
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 ()
154
146
{
155
- std::lock_guard<std::mutex> guard (mtx);
156
- if (!initialized.load ())
147
+ if (initialized)
157
148
{
158
- ::new (static_cast <void *>(ptr)) platform_shared_threadpool (num_threads);
159
- initialized.store (true );
160
- initialized_this_time = true ;
149
+ storage.~T ();
161
150
}
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
163
161
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 ;
165
166
static std::once_flag of;
166
167
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);
172
174
initialized_this_time = true ;
173
175
});
174
- #endif // __ANDROID__
175
176
176
- return {initialized_this_time, ptr };
177
+ return {initialized_this_time, &uninit_threadpool. storage };
177
178
}
178
179
}
179
180
180
181
namespace crossplat
181
182
{
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 (); }
187
184
188
185
void threadpool::initialize_with_threads (size_t num_threads)
189
186
{
@@ -196,9 +193,7 @@ void threadpool::initialize_with_threads(size_t num_threads)
196
193
}
197
194
198
195
#if defined(__ANDROID__)
199
- void cpprest_init (JavaVM* vm) {
200
- JVM = vm;
201
- }
196
+ void cpprest_init (JavaVM* vm) { JVM = vm; }
202
197
#endif
203
198
204
199
std::unique_ptr<crossplat::threadpool> crossplat::threadpool::construct (size_t num_threads)
0 commit comments