Skip to content

Commit

Permalink
Factor shared threadpool setup/teardown behavior out of platform depe…
Browse files Browse the repository at this point in the history
…ndent policies.
  • Loading branch information
BillyONeal committed Aug 4, 2018
1 parent 77e184a commit 8111f2f
Showing 1 changed file with 65 additions and 65 deletions.
130 changes: 65 additions & 65 deletions Release/src/pplx/threadpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include "pplx/threadpool.h"

#include <boost/asio/detail/thread.hpp>
#include <new>
#include <vector>
#include <type_traits>

#if defined(__ANDROID__)
#include <android/log.h>
Expand All @@ -19,6 +21,32 @@

namespace
{
#if defined(__ANDROID__)
// This pointer will be 0-initialized by default (at load time).
std::atomic<JavaVM*> JVM;

JNIEnv* get_jvm_env()
{
abort_if_no_jvm();
JNIEnv* env = nullptr;
auto result = JVM.load()->AttachCurrentThread(&env, nullptr);
if (result != JNI_OK)
{
throw std::runtime_error("Could not attach to JVM");
}

return env;
}

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");
std::abort();
}
}
#endif // __ANDROID__

struct threadpool_impl final : crossplat::threadpool
{
Expand All @@ -39,6 +67,11 @@ struct threadpool_impl final : crossplat::threadpool
}
}

threadpool_impl& get_shared()
{
return *this;
}

private:
void add_thread()
{
Expand All @@ -50,103 +83,70 @@ struct threadpool_impl final : crossplat::threadpool
{
crossplat::JVM.load()->DetachCurrentThread();
}
#endif
#endif // __ANDROID__

static void* thread_start(void *arg) CPPREST_NOEXCEPT
{
#if defined(__ANDROID__)
// Calling get_jvm_env() here forces the thread to be attached.
crossplat::get_jvm_env();
pthread_cleanup_push(detach_from_java, nullptr);
#endif
#endif // __ANDROID__
threadpool_impl* _this = reinterpret_cast<threadpool_impl*>(arg);
_this->m_service.run();
#if defined(__ANDROID__)
pthread_cleanup_pop(true);
#endif
#endif // __ANDROID__
return arg;
}

std::vector<std::unique_ptr<boost::asio::detail::thread>> m_threads;
boost::asio::io_service::work m_work;
};
}

namespace crossplat
#if defined(_WIN32)
struct shared_threadpool
{
#if defined(__ANDROID__)
// This pointer will be 0-initialized by default (at load time).
std::atomic<JavaVM*> JVM;
typename std::aligned_union<0, threadpool_impl>::type shared_storage;

static void abort_if_no_jvm()
{
if (JVM == nullptr)
threadpool_impl& get_shared()
{
__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();
return reinterpret_cast<threadpool_impl&>(shared_storage);
}
}

JNIEnv* get_jvm_env()
{
abort_if_no_jvm();
JNIEnv* env = nullptr;
auto result = JVM.load()->AttachCurrentThread(&env, nullptr);
if (result != JNI_OK)
shared_threadpool(size_t n)
{
throw std::runtime_error("Could not attach to JVM");
::new (static_cast<void*>(&get_shared())) threadpool_impl(n);
}

return env;
}

threadpool& threadpool::shared_instance()
{
abort_if_no_jvm();
static threadpool_impl s_shared(40);
return s_shared;
}

#elif defined(_WIN32)

// if linked into a DLL, the threadpool shared instance will be destroyed at DLL_PROCESS_DETACH,
// at which stage joining threads causes deadlock, hence this dance
threadpool& threadpool::shared_instance()
{
static bool terminate_threads = false;
static struct restore_terminate_threads
~shared_threadpool()
{
~restore_terminate_threads()
{
boost::asio::detail::thread::set_terminate_threads(terminate_threads);
}
} destroyed_after;

static threadpool_impl s_shared(40);
// if linked into a DLL, the threadpool shared instance will be
// destroyed at DLL_PROCESS_DETACH, at which stage joining threads
// causes deadlock, hence this dance
bool terminate_threads = boost::asio::detail::thread::terminate_threads();
boost::asio::detail::thread::set_terminate_threads(true);
get_shared().~threadpool_impl();
boost::asio::detail::thread::set_terminate_threads(terminate_threads);
}
};

static struct enforce_terminate_threads
{
~enforce_terminate_threads()
{
terminate_threads = boost::asio::detail::thread::terminate_threads();
boost::asio::detail::thread::set_terminate_threads(true);
}
} destroyed_before;
typedef shared_threadpool platform_shared_threadpool;
#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv //
typedef threadpool_impl platform_shared_threadpool;
#endif

return s_shared;
}

#else

// initialize the static shared threadpool
namespace crossplat
{
threadpool& threadpool::shared_instance()
{
static threadpool_impl s_shared(40);
return s_shared;
#if defined(__ANDROID__)
abort_if_no_jvm();
#endif // __ANDROID__
static platform_shared_threadpool s_shared_impl(40);
return s_shared_impl.get_shared();
}

#endif

}

#if defined(__ANDROID__)
Expand All @@ -159,4 +159,4 @@ std::unique_ptr<crossplat::threadpool> crossplat::threadpool::construct(size_t n
{
return std::unique_ptr<crossplat::threadpool>(new threadpool_impl(num_threads));
}
#endif
#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32)

3 comments on commit 8111f2f

@zixincheng
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems for android build, the namespace have some issue.

Error Message:
cpprestsdk/Release/src/pplx/threadpool.cpp:39:9: error: unused function 'get_jvm_env' [-Werror,-Wunused-function]
JNIEnv* get_jvm_env()

I think the cause is this change move the android parameters and function out of the crossplat namesapce.

line 95, and line 200.

@BillyONeal
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmm now I'm wondering how this compiles...

@zixincheng
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems for android build, the namespace have some issue.

Error Message:
cpprestsdk/Release/src/pplx/threadpool.cpp:39:9: error: unused function 'get_jvm_env' [-Werror,-Wunused-function]
JNIEnv* get_jvm_env()

I think the cause is this change move the android parameters and function out of the crossplat namesapce.

line 95, and line 200.

Also line 87, after remove the name space "crossplat::" , it works fine.

Please sign in to comment.