void AudioDestinationHandler::render(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames) { // We don't want denormals slowing down any of the audio processing // since they can very seriously hurt performance. // This will take care of all AudioNodes because they all process within this scope. DenormalDisabler denormalDisabler; // Need to check if the context actually alive. Otherwise the subsequent // steps will fail. If the context is not alive somehow, return immediately // and do nothing. // // TODO(hongchan): because the context can go away while rendering, so this // check cannot guarantee the safe execution of the following steps. ASSERT(context()); if (!context()) return; context()->deferredTaskHandler().setAudioThreadToCurrentThread(); // If the destination node is not initialized, pass the silence to the final // audio destination (one step before the FIFO). This check is for the case // where the destination is in the middle of tearing down process. if (!isInitialized()) { destinationBus->zero(); return; } // Let the context take care of any business at the start of each render quantum. context()->handlePreRenderTasks(); // Prepare the local audio input provider for this render quantum. if (sourceBus) m_localAudioInputProvider.set(sourceBus); ASSERT(numberOfInputs() >= 1); if (numberOfInputs() < 1) { destinationBus->zero(); return; } // This will cause the node(s) connected to us to process, which in turn will pull on their input(s), // all the way backwards through the rendering graph. AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames); if (!renderedBus) { destinationBus->zero(); } else if (renderedBus != destinationBus) { // in-place processing was not possible - so copy destinationBus->copyFrom(*renderedBus); } // Process nodes which need a little extra help because they are not connected to anything, but still need to process. context()->deferredTaskHandler().processAutomaticPullNodes(numberOfFrames); // Let the context take care of any business at the end of each render quantum. context()->handlePostRenderTasks(); // Advance current sample-frame. size_t newSampleFrame = m_currentSampleFrame + numberOfFrames; releaseStore(&m_currentSampleFrame, newSampleFrame); }
void resumeOthers(bool barrierLocked = false) { ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(); atomicSubtract(&m_unparkedThreadCount, threads.size()); releaseStore(&m_canResume, 1); // FIXME: Resumed threads will all contend for m_mutex just to unlock it // later which is a waste of resources. if (UNLIKELY(barrierLocked)) { m_resume.broadcast(); } else { // FIXME: Resumed threads will all contend for // m_mutex just to unlock it later which is a waste of // resources. MutexLocker locker(m_mutex); m_resume.broadcast(); } ThreadState* current = ThreadState::current(); for (ThreadState* state : threads) { if (state == current) continue; for (ThreadState::Interruptor* interruptor : state->interruptors()) interruptor->clearInterrupt(); } threadAttachMutex().unlock(); ASSERT(ThreadState::current()->isAtSafePoint()); }
// Request other attached threads that are not at safe points to park themselves on safepoints. bool parkOthers() { ASSERT(ThreadState::current()->isAtSafePoint()); // Lock threadAttachMutex() to prevent threads from attaching. threadAttachMutex().lock(); ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(); MutexLocker locker(m_mutex); atomicAdd(&m_unparkedThreadCount, threads.size()); releaseStore(&m_canResume, 0); ThreadState* current = ThreadState::current(); for (ThreadState* state : threads) { if (state == current) continue; for (ThreadState::Interruptor* interruptor : state->interruptors()) interruptor->requestInterrupt(); } while (acquireLoad(&m_unparkedThreadCount) > 0) { double expirationTime = currentTime() + lockingTimeout(); if (!m_parked.timedWait(m_mutex, expirationTime)) { // One of the other threads did not return to a safepoint within the maximum // time we allow for threads to be parked. Abandon the GC and resume the // currently parked threads. resumeOthers(true); return false; } } return true; }
bool OfflineAudioDestinationHandler::renderIfNotSuspended(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames) { // We don't want denormals slowing down any of the audio processing // since they can very seriously hurt performance. // This will take care of all AudioNodes because they all process within this scope. DenormalDisabler denormalDisabler; context()->deferredTaskHandler().setAudioThread(currentThread()); if (!context()->isDestinationInitialized()) { destinationBus->zero(); return false; } // Take care pre-render tasks at the beginning of each render quantum. Then // it will stop the rendering loop if the context needs to be suspended // at the beginning of the next render quantum. if (context()->handlePreOfflineRenderTasks()) { suspendOfflineRendering(); return true; } // Prepare the local audio input provider for this render quantum. if (sourceBus) m_localAudioInputProvider.set(sourceBus); ASSERT(numberOfInputs() >= 1); if (numberOfInputs() < 1) { destinationBus->zero(); return false; } // This will cause the node(s) connected to us to process, which in turn will pull on their input(s), // all the way backwards through the rendering graph. AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames); if (!renderedBus) { destinationBus->zero(); } else if (renderedBus != destinationBus) { // in-place processing was not possible - so copy destinationBus->copyFrom(*renderedBus); } // Process nodes which need a little extra help because they are not connected to anything, but still need to process. context()->deferredTaskHandler().processAutomaticPullNodes(numberOfFrames); // Let the context take care of any business at the end of each render quantum. context()->handlePostOfflineRenderTasks(); // Advance current sample-frame. size_t newSampleFrame = m_currentSampleFrame + numberOfFrames; releaseStore(&m_currentSampleFrame, newSampleFrame); return false; }
void GCInfoTable::ensureGCInfoIndex(const GCInfo* gcInfo, size_t* gcInfoIndexSlot) { ASSERT(gcInfo); ASSERT(gcInfoIndexSlot); // Keep a global GCInfoTable lock while allocating a new slot. DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, new Mutex); MutexLocker locker(mutex); // If more than one thread ends up allocating a slot for // the same GCInfo, have later threads reuse the slot // allocated by the first. if (*gcInfoIndexSlot) return; int index = ++s_gcInfoIndex; size_t gcInfoIndex = static_cast<size_t>(index); RELEASE_ASSERT(gcInfoIndex < GCInfoTable::maxIndex); if (gcInfoIndex >= s_gcInfoTableSize) resize(); s_gcInfoTable[gcInfoIndex] = gcInfo; releaseStore(reinterpret_cast<int*>(gcInfoIndexSlot), index); }
void DeferredTaskHandler::setAudioThreadToCurrentThread() { DCHECK(!isMainThread()); ThreadIdentifier thread = currentThread(); releaseStore(&m_audioThread, thread); }
void CryptoResultImpl::ResultCancel::cancel() { releaseStore(&m_cancelled, 1); }