void NativeToJsBridge::runOnExecutorQueue(ExecutorToken executorToken, std::function<void(JSExecutor*)> task) { if (*m_destroyed) { return; } auto executorMessageQueueThread = getMessageQueueThread(executorToken); if (executorMessageQueueThread == nullptr) { LOG(WARNING) << "Dropping JS action for executor that has been unregistered..."; return; } std::shared_ptr<bool> isDestroyed = m_destroyed; executorMessageQueueThread->runOnQueue([this, isDestroyed, executorToken, task=std::move(task)] { if (*isDestroyed) { return; } JSExecutor *executor = getExecutor(executorToken); if (executor == nullptr) { LOG(WARNING) << "Dropping JS call for executor that has been unregistered..."; return; } // The executor is guaranteed to be valid for the duration of the task because: // 1. the executor is only destroyed after it is unregistered // 2. the executor is unregistered on this queue // 3. we just confirmed that the executor hasn't been unregistered above task(executor); }); }
void NativeToJsBridge::destroy() { m_delegate->quitQueueSynchronous(); auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken); executorMessageQueueThread->runOnQueueSync([this, executorMessageQueueThread] { m_mainExecutor->destroy(); executorMessageQueueThread->quitSynchronous(); unregisterExecutor(*m_mainExecutor); m_mainExecutor = nullptr; *m_destroyed = true; }); }
void NativeToJsBridge::destroy() { m_delegate->quitQueueSynchronous(); auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken); // All calls made through runOnExecutorQueue have an early exit if // m_destroyed is true. Setting this before the runOnQueueSync will cause // pending work to be cancelled and we won't have to wait for it. *m_destroyed = true; executorMessageQueueThread->runOnQueueSync([this, executorMessageQueueThread] { m_mainExecutor->destroy(); executorMessageQueueThread->quitSynchronous(); unregisterExecutor(*m_mainExecutor); m_mainExecutor = nullptr; }); }
void Bridge::callFunction( ExecutorToken executorToken, const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments, const std::string& tracingName) { if (*m_destroyed) { return; } #ifdef WITH_FBSYSTRACE int systraceCookie = m_systraceCookie++; FbSystraceAsyncFlow::begin( TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str(), systraceCookie); #endif auto executorMessageQueueThread = getMessageQueueThread(executorToken); if (executorMessageQueueThread == nullptr) { LOG(WARNING) << "Dropping JS call for executor that has been unregistered..."; return; } std::shared_ptr<bool> isDestroyed = m_destroyed; executorMessageQueueThread->runOnQueue([=] () { #ifdef WITH_FBSYSTRACE FbSystraceAsyncFlow::end( TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str(), systraceCookie); FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str()); #endif if (*isDestroyed) { return; } JSExecutor *executor = getExecutor(executorToken); if (executor == nullptr) { LOG(WARNING) << "Dropping JS call for executor that has been unregistered..."; return; } // This is safe because we are running on the executor's thread: it won't // destruct until after it's been unregistered (which we check above) and // that will happen on this thread executor->callFunction(moduleId, methodId, arguments); }); }