TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) { m_lazyDecoder->setData(m_data, true); sk_sp<SkImage> image = m_lazyDecoder->createFrameAtIndex(0); ASSERT_TRUE(image); EXPECT_EQ(1, image->width()); EXPECT_EQ(1, image->height()); SkPictureRecorder recorder; SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawImage(image.get(), 0, 0); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); EXPECT_EQ(0, m_decodeRequestCount); // Create a thread to rasterize SkPicture. std::unique_ptr<WebThread> thread = WTF::wrapUnique(Platform::current()->createThread("RasterThread")); thread->getWebTaskRunner()->postTask( BLINK_FROM_HERE, crossThreadBind(&rasterizeMain, crossThreadUnretained(m_surface->getCanvas()), crossThreadUnretained(picture.get()))); thread.reset(); EXPECT_EQ(0, m_decodeRequestCount); SkBitmap canvasBitmap; canvasBitmap.allocN32Pixels(100, 100); ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); }
void WorkletBackingThreadHolder::shutdownAndWait() { DCHECK(isMainThread()); WaitableEvent waitableEvent; m_thread->backingThread().postTask( BLINK_FROM_HERE, crossThreadBind(&WorkletBackingThreadHolder::shutdownOnThread, crossThreadUnretained(this), crossThreadUnretained(&waitableEvent))); waitableEvent.wait(); }
void HTMLParserThread::shutdown() { ASSERT(isMainThread()); ASSERT(s_sharedThread); // currentThread will always be non-null in production, but can be null in // Chromium unit tests. if (Platform::current()->currentThread() && s_sharedThread->m_thread) { WaitableEvent waitableEvent; s_sharedThread->postTask( crossThreadBind(&HTMLParserThread::cleanupHTMLParserThread, crossThreadUnretained(s_sharedThread), crossThreadUnretained(&waitableEvent))); waitableEvent.wait(); } delete s_sharedThread; s_sharedThread = nullptr; }
void WebSharedWorkerImpl::didTerminateWorkerThread() { Platform::current()->mainThread()->getWebTaskRunner()->postTask( BLINK_FROM_HERE, crossThreadBind( &WebSharedWorkerImpl::didTerminateWorkerThreadOnMainThread, crossThreadUnretained(this))); }
void WebSharedWorkerImpl::postMessageToPageInspector(const String& message) { m_mainFrame->frame()->document()->postInspectorTask( BLINK_FROM_HERE, createCrossThreadTask( &WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread, crossThreadUnretained(this), message)); }
WorkletBackingThreadHolder::WorkletBackingThreadHolder( std::unique_ptr<WorkerBackingThread> backingThread) : m_thread(std::move(backingThread)), m_initialized(false) { DCHECK(isMainThread()); m_thread->backingThread().postTask( BLINK_FROM_HERE, crossThreadBind(&WorkletBackingThreadHolder::initializeOnThread, crossThreadUnretained(this))); }
void HTMLParserThread::postTask(std::unique_ptr<CrossThreadClosure> closure) { ASSERT(isMainThread()); if (!m_thread) { m_thread = WebThreadSupportingGC::create("HTMLParserThread", BlinkGC::MainThreadHeapMode); postTask(crossThreadBind(&HTMLParserThread::setupHTMLParserThread, crossThreadUnretained(this))); } m_thread->postTask(BLINK_FROM_HERE, std::move(closure)); }
void ServiceWorkerGlobalScopeProxy::postMessageToPageInspector( const String& message) { DCHECK(m_embeddedWorker); // The TaskType of Inspector tasks need to be Unthrottled because they need to // run even on a suspended page. getParentFrameTaskRunners() ->get(TaskType::Unthrottled) ->postTask( BLINK_FROM_HERE, crossThreadBind(&WebEmbeddedWorkerImpl::postMessageToPageInspector, crossThreadUnretained(m_embeddedWorker), message)); }
DataConsumerHandleTestUtil::Thread::Thread( const char* name, InitializationPolicy initializationPolicy) : m_thread( WebThreadSupportingGC::create(name, BlinkGC::MainThreadHeapMode)), m_initializationPolicy(initializationPolicy), m_waitableEvent(wrapUnique(new WaitableEvent())) { m_thread->postTask( BLINK_FROM_HERE, crossThreadBind(&Thread::initialize, crossThreadUnretained(this))); m_waitableEvent->wait(); }
void DatabaseTracker::closeDatabasesImmediately(SecurityOrigin* origin, const String& name) { String originString = origin->toRawString(); MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(originString); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; // We have to call closeImmediately() on the context thread. for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it) (*it)->getDatabaseContext()->getExecutionContext()->postTask(BLINK_FROM_HERE, createCrossThreadTask(&DatabaseTracker::closeOneDatabaseImmediately, crossThreadUnretained(this), originString, name, *it)); }
DataConsumerHandleTestUtil::Thread::~Thread() { m_thread->postTask( BLINK_FROM_HERE, crossThreadBind(&Thread::shutdown, crossThreadUnretained(this))); m_waitableEvent->wait(); }
void ScriptProcessorHandler::process(size_t framesToProcess) { // Discussion about inputs and outputs: // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input // and output (see inputBus and outputBus below). Additionally, there is a // double-buffering for input and output which is exposed directly to // JavaScript (see inputBuffer and outputBuffer below). This node is the // producer for inputBuffer and the consumer for outputBuffer. The JavaScript // code is the consumer of inputBuffer and the producer for outputBuffer. // Get input and output busses. AudioBus* inputBus = input(0).bus(); AudioBus* outputBus = output(0).bus(); // Get input and output buffers. We double-buffer both the input and output // sides. unsigned doubleBufferIndex = this->doubleBufferIndex(); bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && doubleBufferIndex < m_inputBuffers.size() && doubleBufferIndex < m_outputBuffers.size(); DCHECK(isDoubleBufferIndexGood); if (!isDoubleBufferIndexGood) return; AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get(); AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); // Check the consistency of input and output buffers. unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels(); bool buffersAreGood = outputBuffer && bufferSize() == outputBuffer->length() && m_bufferReadWriteIndex + framesToProcess <= bufferSize(); // If the number of input channels is zero, it's ok to have inputBuffer = 0. if (m_internalInputBus->numberOfChannels()) buffersAreGood = buffersAreGood && inputBuffer && bufferSize() == inputBuffer->length(); DCHECK(buffersAreGood); if (!buffersAreGood) return; // We assume that bufferSize() is evenly divisible by framesToProcess - should // always be true, but we should still check. bool isFramesToProcessGood = framesToProcess && bufferSize() >= framesToProcess && !(bufferSize() % framesToProcess); DCHECK(isFramesToProcessGood); if (!isFramesToProcessGood) return; unsigned numberOfOutputChannels = outputBus->numberOfChannels(); bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) && (numberOfOutputChannels == m_numberOfOutputChannels); DCHECK(channelsAreGood); if (!channelsAreGood) return; for (unsigned i = 0; i < numberOfInputChannels; ++i) m_internalInputBus->setChannelMemory( i, inputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, framesToProcess); if (numberOfInputChannels) m_internalInputBus->copyFrom(*inputBus); // Copy from the output buffer to the output. for (unsigned i = 0; i < numberOfOutputChannels; ++i) memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess); // Update the buffering index. m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % bufferSize(); // m_bufferReadWriteIndex will wrap back around to 0 when the current input // and output buffers are full. // When this happens, fire an event and swap buffers. if (!m_bufferReadWriteIndex) { // Avoid building up requests on the main thread to fire process events when // they're not being handled. This could be a problem if the main thread is // very busy doing other things and is being held up handling previous // requests. The audio thread can't block on this lock, so we call // tryLock() instead. MutexTryLocker tryLocker(m_processEventLock); if (!tryLocker.locked()) { // We're late in handling the previous request. The main thread must be // very busy. The best we can do is clear out the buffer ourself here. outputBuffer->zero(); } else if (context()->getExecutionContext()) { // With the realtime context, execute the script code asynchronously // and do not wait. if (context()->hasRealtimeConstraint()) { // Fire the event on the main thread with the appropriate buffer // index. context()->getExecutionContext()->postTask( BLINK_FROM_HERE, createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent, crossThreadUnretained(this), m_doubleBufferIndex)); } else { // If this node is in the offline audio context, use the // waitable event to synchronize to the offline rendering thread. std::unique_ptr<WaitableEvent> waitableEvent = wrapUnique(new WaitableEvent()); context()->getExecutionContext()->postTask( BLINK_FROM_HERE, createCrossThreadTask( &ScriptProcessorHandler::fireProcessEventForOfflineAudioContext, crossThreadUnretained(this), m_doubleBufferIndex, crossThreadUnretained(waitableEvent.get()))); // Okay to block the offline audio rendering thread since it is // not the actual audio device thread. waitableEvent->wait(); } } swapBuffers(); } }
std::unique_ptr<CompositorMutatorClient> CompositorMutatorImpl::createClient() { std::unique_ptr<CompositorMutatorClient> mutatorClient; WaitableEvent doneEvent; if (WebThread* compositorThread = Platform::current()->compositorThread()) { compositorThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&createCompositorMutatorClient, crossThreadUnretained(&mutatorClient), crossThreadUnretained(&doneEvent))); } else { createCompositorMutatorClient(&mutatorClient, &doneEvent); } // TODO(flackr): Instead of waiting for this event, we may be able to just set the // mutator on the CompositorProxyClient directly from the compositor thread before // it gets used there. We still need to make sure we only create one mutator though. doneEvent.wait(); return mutatorClient; }