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);
}
Exemple #2
0
    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());
    }
Exemple #3
0
    // 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);
}