HRESULT Initialize()

in Source/Task/ThreadPool_stl.cpp [32:146]


        HRESULT Initialize(
            _In_opt_ void* context,
            _In_ ThreadPoolCallback* callback) noexcept
        {
            m_context = context;
            m_callback = callback;

            uint32_t numThreads = std::thread::hardware_concurrency();
            if (numThreads == 0)
            {
                numThreads = 1;
            }

            try
            {
                while (numThreads != 0)
                {
                    numThreads--;
                    m_pool.emplace_back(std::thread([this]
                    {
#if defined(HC_PLATFORM) && HC_PLATFORM == HC_PLATFORM_ANDROID
                        JNIEnv* jniEnv = nullptr;
                        JavaVM* jvm = nullptr;
#endif

                        std::unique_lock<std::mutex> lock(m_wakeLock);
                        while (true)
                        {
                            if (m_calls == 0)
                            {
                                m_wake.wait(lock);
                            }

                            if (m_terminate)
                            {
                                break;
                            }

#if defined(HC_PLATFORM) && HC_PLATFORM == HC_PLATFORM_ANDROID
                            // lazy check for the JavaVM, we do it here so that we
                            // will attach even if the thread pool is initialized
                            // before we're given the jvm
                            if (!jniEnv)
                            {
                                jvm = s_javaVm;
                                if (jvm)
                                {
                                    jvm->AttachCurrentThread(&jniEnv, nullptr);
                                }
                            }
#endif

                            if (m_calls != 0)
                            {
                                m_calls--;

                                // ActionComplete is an optional call
                                // the callback can make to indicate 
                                // all portions of the call have finished
                                // and it is safe to release the
                                // thread pool, even if the callback has
                                // not totally unwound.  This is neccessary
                                // to allow users to close a task queue from
                                // within a callback.  Task queue guards with an 
                                // extra ref to ensure a safe point where 
                                // member state is no longer accessed, but the
                                // final release does need to wait on outstanding
                                // calls.

                                {
                                    std::unique_lock<std::mutex> lock(m_activeLock);
                                    m_activeCalls++;
                                }

                                ActionCompleteImpl ac(this);

                                lock.unlock();
                                AddRef();
                                m_callback(m_context, ac);
                                lock.lock();

                                if (!ac.Invoked)
                                {
                                    ac();
                                }

                                if (m_terminate)
                                {
                                    lock.unlock();
                                    Release(); // This could destroy us
                                    break;
                                }
                                else
                                {
                                    Release();
                                }
                            }
                        }

#if defined(HC_PLATFORM) && HC_PLATFORM == HC_PLATFORM_ANDROID
                        if (jniEnv && jvm)
                        {
                            jvm->DetachCurrentThread();
                        }
#endif
                    }));
                }
            }
            catch (const std::bad_alloc&)
            {
                return E_OUTOFMEMORY;
            }

            return S_OK;
        }