1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * ==--==
17 *
18 * Simple Linux implementation of a static thread pool.
19 *
20 * For the latest on this and related APIs, please see http://casablanca.codeplex.com.
21 *
22 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
23 ***/
24 #pragma once
25
26 #include <pthread.h>
27 #include <vector>
28
29 #if defined(__clang__)
30 #pragma clang diagnostic push
31 #pragma clang diagnostic ignored "-Wconversion"
32 #pragma clang diagnostic ignored "-Wunreachable-code"
33 #endif
34 #include "boost/asio.hpp"
35 #if defined(__clang__)
36 #pragma clang diagnostic pop
37 #endif
38
39 #if (defined(ANDROID) || defined(__ANDROID__))
40 #include <atomic>
41 #include <jni.h>
42 #include "pplx/pplx.h"
43 #endif
44
46
47 #if (defined(ANDROID) || defined(__ANDROID__))
48 // IDEA: Break this section into a separate android/jni header
49 extern std::atomic<JavaVM*> JVM;
50 JNIEnv* get_jvm_env();
51
52 struct java_local_ref_deleter
53 {
54 void operator()(jobject lref) const
55 {
56 crossplat::get_jvm_env()->DeleteLocalRef(lref);
57 }
58 };
59
60 template<class T>
61 using java_local_ref = std::unique_ptr<typename std::remove_pointer<T>::type, java_local_ref_deleter>;
62 #endif
63
65 {
66 public:
67
69 : m_service(n),
70 m_work(m_service)
71 {
72 for (size_t i = 0; i < n; i++)
73 add_thread();
74 }
75
77
79 {
80 m_service.stop();
81 for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter)
82 {
83 pthread_t t = *iter;
84 void* res;
85 pthread_join(t, &res);
86 }
87 }
88
89 template<typename T>
90 void schedule(T task)
91 {
92 m_service.post(task);
93 }
94
95 boost::asio::io_service& service()
96 {
97 return m_service;
98 }
99
100 private:
101 struct _cancel_thread { };
102
103 void add_thread()
104 {
105 pthread_t t;
106 auto result = pthread_create(&t, nullptr, &thread_start, this);
107 if (result == 0)
108 m_threads.push_back(t);
109 }
110
111 void remove_thread()
112 {
113 schedule([]() -> void { throw _cancel_thread(); });
114 }
115
116 #if (defined(ANDROID) || defined(__ANDROID__))
117 static void detach_from_java(void*)
118 {
119 JVM.load()->DetachCurrentThread();
120 }
121 #endif
122
123 static void* thread_start(void *arg)
124 {
125 #if (defined(ANDROID) || defined(__ANDROID__))
126 // Calling get_jvm_env() here forces the thread to be attached.
127 get_jvm_env();
128 pthread_cleanup_push(detach_from_java, nullptr);
129 #endif
131 try
132 {
133 _this->m_service.run();
134 }
135 catch (const _cancel_thread&)
136 {
137 // thread was cancelled
138 }
139 catch (...)
140 {
141 // Something bad happened
142 #if (defined(ANDROID) || defined(__ANDROID__))
143 // Reach into the depths of the 'droid!
144 // NOTE: Uses internals of the bionic library
145 // Written against android ndk r9d, 7/26/2014
146 __pthread_cleanup_pop(&__cleanup, true);
147 throw;
148 #endif
149 }
150 #if (defined(ANDROID) || defined(__ANDROID__))
151 pthread_cleanup_pop(true);
152 #endif
153 return arg;
154 }
155
156 std::vector<pthread_t> m_threads;
157 boost::asio::io_service m_service;
158 boost::asio::io_service::work m_work;
159 };
160
161 }
Definition: threadpool.h:45
Definition: threadpool.h:64