virtual void performTask(ScriptExecutionContext *context) { ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed. workerGlobalScope->clearScript(); }
double WorkerPerformance::now(ExecutionContext* context) const { ASSERT(context); ASSERT(context->isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); return 1000.0 * (monotonicallyIncreasingTime() - workerGlobalScope->timeOrigin()); }
virtual void performTask(ScriptExecutionContext *context) { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); #if ENABLE(SQL_DATABASE) // FIXME: Should we stop the databases as part of stopActiveDOMObjects() below? DatabaseTaskSynchronizer cleanupSync; DatabaseManager::manager().stopDatabases(workerGlobalScope, &cleanupSync); #endif workerGlobalScope->stopActiveDOMObjects(); workerGlobalScope->notifyObserversOfStop(); // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects, // which become dangling once Heap is destroyed. workerGlobalScope->removeAllEventListeners(); #if ENABLE(SQL_DATABASE) // We wait for the database thread to clean up all its stuff so that we // can do more stringent leak checks as we exit. cleanupSync.waitForTaskCompletion(); #endif // Stick a shutdown command at the end of the queue, so that we deal // with all the cleanup tasks the databases post first. workerGlobalScope->postTask(WorkerThreadShutdownFinishTask::create()); }
bool DatabaseObserver::canEstablishDatabase(ExecutionContext* executionContext, const String& name, const String& displayName, unsigned long estimatedSize) { ASSERT(executionContext->isContextThread()); ASSERT(executionContext->isDocument() || executionContext->isWorkerGlobalScope()); if (executionContext->isDocument()) { Document* document = toDocument(executionContext); WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); if (!webFrame) return false; WebViewImpl* webView = webFrame->viewImpl(); if (!webView) return false; if (webView->permissionClient()) return webView->permissionClient()->allowDatabase(webFrame, name, displayName, estimatedSize); } else { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(executionContext); WorkerPermissionClient* permissionClient = WorkerPermissionClient::from(workerGlobalScope); if (permissionClient->proxy()) return permissionClient->allowDatabase(name, displayName, estimatedSize); // FIXME: Deprecate this bridge code when PermissionClientProxy is // implemented by the embedder. WebWorkerBase* webWorker = static_cast<WebWorkerBase*>(workerGlobalScope->thread()->workerLoaderProxy().toWebWorkerBase()); WebView* view = webWorker->view(); if (!view) return false; return allowDatabaseForWorker(view->mainFrame(), name, displayName, estimatedSize); } return true; }
static ThrottlingController* from(ExecutionContext* context) { if (!context) return 0; if (context->isDocument()) { Document* document = toDocument(context); if (!document->frame()) return 0; ThrottlingController* controller = static_cast<ThrottlingController*>(WillBeHeapSupplement<LocalFrame>::from(document->frame(), supplementName())); if (controller) return controller; controller = new ThrottlingController(); WillBeHeapSupplement<LocalFrame>::provideTo(*document->frame(), supplementName(), adoptPtrWillBeNoop(controller)); return controller; } ASSERT(!isMainThread()); ASSERT(context->isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); ThrottlingController* controller = static_cast<ThrottlingController*>(WillBeHeapSupplement<WorkerClients>::from(workerGlobalScope->clients(), supplementName())); if (controller) return controller; controller = new ThrottlingController(); WillBeHeapSupplement<WorkerClients>::provideTo(*workerGlobalScope->clients(), supplementName(), adoptPtrWillBeNoop(controller)); return controller; }
PassRefPtr<WebSocketChannel> WebSocketChannel::create(ExecutionContext* context, WebSocketChannelClient* client) { ASSERT(context); ASSERT(client); String sourceURL; unsigned lineNumber = 0; RefPtr<ScriptCallStack> callStack = createScriptCallStack(1, true); if (callStack && callStack->size()) { sourceURL = callStack->at(0).sourceURL(); lineNumber = callStack->at(0).lineNumber(); } if (context->isWorkerGlobalScope()) { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); WorkerRunLoop& runLoop = workerGlobalScope->thread()->runLoop(); String mode = webSocketChannelMode + String::number(runLoop.createUniqueId()); return WorkerThreadableWebSocketChannel::create(workerGlobalScope, client, mode, sourceURL, lineNumber); } Document* document = toDocument(context); Settings* settings = document->settings(); if (settings && settings->experimentalWebSocketEnabled()) { // FIXME: Create and return an "experimental" WebSocketChannel instead of a MainThreadWebSocketChannel. return MainThreadWebSocketChannel::create(document, client, sourceURL, lineNumber); } return MainThreadWebSocketChannel::create(document, client, sourceURL, lineNumber); }
bool DatabaseObserver::canEstablishDatabase(ScriptExecutionContext* scriptExecutionContext, const String& name, const String& displayName, unsigned long estimatedSize) { ASSERT(scriptExecutionContext->isContextThread()); ASSERT(scriptExecutionContext->isDocument() || scriptExecutionContext->isWorkerGlobalScope()); if (scriptExecutionContext->isDocument()) { Document* document = toDocument(scriptExecutionContext); WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); if (!webFrame) return false; WebViewImpl* webView = webFrame->viewImpl(); if (!webView) return false; if (webView->permissionClient()) return webView->permissionClient()->allowDatabase(webFrame, name, displayName, estimatedSize); } else { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(scriptExecutionContext); WebWorkerBase* webWorker = static_cast<WebWorkerBase*>(workerGlobalScope->thread()->workerLoaderProxy().toWebWorkerBase()); WebView* view = webWorker->view(); if (!view) return false; return allowDatabaseForWorker(view->mainFrame(), name, displayName, estimatedSize); } return true; }
void WorkerDebuggerGlobalScope::Dump(JSContext* aCx, const Optional<nsAString>& aString) const { WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); if (scope) { scope->Dump(aString); } }
virtual void performTask(ScriptExecutionContext *context) { ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). workerGlobalScope->thread()->workerReportingProxy().workerGlobalScopeClosed(); }
void WebSharedWorkerImpl::connectTask(PassOwnPtr<WebMessagePortChannel> channel, ExecutionContext* context) { // Wrap the passed-in channel in a MessagePort, and send it off via a connect event. MessagePort* port = MessagePort::create(*context); port->entangle(channel); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); ASSERT_WITH_SECURITY_IMPLICATION(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }
void MemoryCache::removeURLFromCache(ExecutionContext* context, const KURL& url) { if (context->isWorkerGlobalScope()) { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); workerGlobalScope->thread()->workerLoaderProxy().postTaskToLoader(createCallbackTask(&removeURLFromCacheInternal, url)); return; } removeURLFromCacheInternal(context, url); }
void WebSharedWorkerImpl::connectTask(WebMessagePortChannelUniquePtr channel, ExecutionContext* context) { // Wrap the passed-in channel in a MessagePort, and send it off via a connect // event. MessagePort* port = MessagePort::create(*context); port->entangle(std::move(channel)); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); SECURITY_DCHECK(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }
void WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal, ErrorResult& aRv) { WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); if (!scope) { aRv.Throw(NS_ERROR_FAILURE); return; } aGlobal.set(scope->GetWrapper()); }
virtual void performTask(ScriptExecutionContext* scriptContext) { RefPtr<MessagePort> port = MessagePort::create(*scriptContext); port->entangle(m_channel.release()); ASSERT_WITH_SECURITY_IMPLICATION(scriptContext->isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(scriptContext); // Since close() stops the thread event loop, this should not ever get called while closing. ASSERT(!workerGlobalScope->isClosing()); ASSERT_WITH_SECURITY_IMPLICATION(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }
SharedWorkerConnectTask(MessagePortChannel* channel) : ScriptExecutionContext::Task([=] (ScriptExecutionContext& context) { RefPtr<MessagePort> port = MessagePort::create(context); port->entangle(std::unique_ptr<MessagePortChannel>(channel)); ASSERT_WITH_SECURITY_IMPLICATION(context.isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(&context); // Since close() stops the thread event loop, this should not ever get called while closing. ASSERT(!workerGlobalScope->isClosing()); ASSERT_WITH_SECURITY_IMPLICATION(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }) { }
WorkerScriptController* WorkerScriptController::controllerForContext(v8::Isolate* isolate) { // Happens on frame destruction, check otherwise GetCurrent() will crash. if (!isolate || !isolate->InContext()) return 0; v8::Handle<v8::Context> context = isolate->GetCurrentContext(); v8::Handle<v8::Object> global = context->Global(); global = global->FindInstanceInPrototypeChain(V8WorkerGlobalScope::domTemplate(isolate, WorkerWorld)); // Return 0 if the current executing context is not the worker context. if (global.IsEmpty()) return 0; WorkerGlobalScope* workerGlobalScope = V8WorkerGlobalScope::toNative(global); return workerGlobalScope->script(); }
void WorkerDebuggerGlobalScope::RetrieveConsoleEvents( JSContext* aCx, nsTArray<JS::Value>& aEvents, ErrorResult& aRv) { WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); if (!scope) { aRv.Throw(NS_ERROR_FAILURE); return; } RefPtr<Console> console = scope->GetConsole(aRv); if (NS_WARN_IF(aRv.Failed())) { return; } console->RetrieveConsoleEvents(aCx, aEvents, aRv); }
WorkerGlobalScopeIndexedDatabase* WorkerGlobalScopeIndexedDatabase::from(ScriptExecutionContext* context) { WorkerGlobalScopeIndexedDatabase* supplement = static_cast<WorkerGlobalScopeIndexedDatabase*>(Supplement<ScriptExecutionContext>::from(context, supplementName())); if (!supplement) { String databaseDirectoryIdentifier; WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); const GroupSettings* groupSettings = workerGlobalScope->groupSettings(); if (groupSettings) databaseDirectoryIdentifier = groupSettings->indexedDBDatabasePath(); supplement = new WorkerGlobalScopeIndexedDatabase(databaseDirectoryIdentifier); provideTo(context, supplementName(), adoptPtr(supplement)); } return supplement; }
void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { WebWaitableEvent* shutdownEvent = workerGlobalScope.thread()->shutdownEvent(); OwnPtr<WebWaitableEvent> loaderDone = adoptPtr(Platform::current()->createWaitableEvent()); Vector<WebWaitableEvent*> events; events.append(shutdownEvent); events.append(loaderDone.get()); RefPtr<ThreadableLoaderClientWrapper> clientWrapper(ThreadableLoaderClientWrapper::create(&client)); OwnPtr<WorkerLoaderClientBridgeSyncHelper> clientBridge(WorkerLoaderClientBridgeSyncHelper::create(clientWrapper.get(), loaderDone.release())); // This must be valid while loader is around. WorkerLoaderClientBridgeSyncHelper* clientBridgePtr = clientBridge.get(); RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, clientWrapper, clientBridge.release(), request, options, resourceLoaderOptions); WebWaitableEvent* signalled; { SafePointScope scope(ThreadState::HeapPointersOnStack); signalled = Platform::current()->waitMultipleEvents(events); } if (signalled == shutdownEvent) { loader->cancel(); return; } clientBridgePtr->run(); }
WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalScope, PassRefPtr<ThreadableLoaderClientWrapper> clientWrapper, PassOwnPtr<ThreadableLoaderClient> clientBridge, const ResourceRequest& request, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) : m_workerGlobalScope(&workerGlobalScope) , m_workerClientWrapper(clientWrapper) , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, clientBridge, workerGlobalScope.thread()->workerLoaderProxy(), request, options, resourceLoaderOptions, workerGlobalScope.referrerPolicy(), workerGlobalScope.url().strippedForUseAsReferrer()))) { m_workerClientWrapper->setResourceTimingClient(this); }
void WorkerGlobalScope::close() { if (m_closing) return; // Let current script run to completion but prevent future script evaluations. // After m_closing is set, all the tasks in the queue continue to be fetched but only // tasks with isCleanupTask()==true will be executed. m_closing = true; postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) { ASSERT_WITH_SECURITY_IMPLICATION(context.isWorkerGlobalScope()); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(&context); // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). workerGlobalScope->thread().workerReportingProxy().workerGlobalScopeClosed(); } }); }
void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx, AnyCallback* aHandler, ErrorResult& aRv) { WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx); if (!scope) { aRv.Throw(NS_ERROR_FAILURE); return; } RefPtr<Console> console = scope->GetConsole(aRv); if (NS_WARN_IF(aRv.Failed())) { return; } console->SetConsoleEventHandler(aHandler); }
static void setTimeoutOrInterval(const v8::FunctionCallbackInfo<v8::Value>& info, bool singleShot) { WorkerGlobalScope* workerGlobalScope = V8WorkerGlobalScope::toNative(info.Holder()); ASSERT(workerGlobalScope); int argumentCount = info.Length(); if (argumentCount < 1) return; v8::Handle<v8::Value> function = info[0]; WorkerScriptController* script = workerGlobalScope->script(); if (!script) return; ScriptState* scriptState = ScriptState::current(info.GetIsolate()); OwnPtr<ScheduledAction> action; if (function->IsString()) { if (ContentSecurityPolicy* policy = workerGlobalScope->contentSecurityPolicy()) { if (!policy->allowEval()) { v8SetReturnValue(info, 0); return; } } action = adoptPtr(new ScheduledAction(scriptState, toCoreString(function.As<v8::String>()), workerGlobalScope->url(), info.GetIsolate())); } else if (function->IsFunction()) { size_t paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; OwnPtr<v8::Local<v8::Value>[]> params; if (paramCount > 0) { params = adoptArrayPtr(new v8::Local<v8::Value>[paramCount]); for (size_t i = 0; i < paramCount; ++i) params[i] = info[i+2]; } // ScheduledAction takes ownership of actual params and releases them in its destructor. action = adoptPtr(new ScheduledAction(scriptState, v8::Handle<v8::Function>::Cast(function), paramCount, params.get(), info.GetIsolate())); } else return; int32_t timeout = argumentCount >= 2 ? info[1]->Int32Value() : 0; int timerId; if (singleShot) timerId = DOMWindowTimers::setTimeout(*workerGlobalScope, action.release(), timeout); else timerId = DOMWindowTimers::setInterval(*workerGlobalScope, action.release(), timeout); v8SetReturnValue(info, timerId); }
bool IDBFactoryBackendProxy::allowIndexedDB(ExecutionContext* context, const String& name, const WebSecurityOrigin& origin, PassRefPtr<IDBCallbacks> callbacks) { bool allowed; ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument() || context->isWorkerGlobalScope()); if (context->isDocument()) { Document* document = toDocument(context); WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); WebViewImpl* webView = webFrame->viewImpl(); // FIXME: webView->permissionClient() returns 0 in test_shell and content_shell http://crbug.com/137269 allowed = !webView->permissionClient() || webView->permissionClient()->allowIndexedDB(webFrame, name, origin); } else { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); WorkerPermissionClient* permissionClient = WorkerPermissionClient::from(workerGlobalScope); if (permissionClient->proxy()) { allowed = permissionClient->allowIndexedDB(name); if (!allowed) callbacks->onError(WebIDBDatabaseError(UnknownError, "The user denied permission to access the database.")); return allowed; } // FIXME: Deprecate this bridge code when PermissionClientProxy is // implemented by the embedder. WebWorkerBase* webWorkerBase = static_cast<WebWorkerBase*>(workerGlobalScope->thread()->workerLoaderProxy().toWebWorkerBase()); WorkerRunLoop& runLoop = workerGlobalScope->thread()->runLoop(); String mode = allowIndexedDBMode; mode.append(String::number(runLoop.createUniqueId())); RefPtr<AllowIndexedDBMainThreadBridge> bridge = AllowIndexedDBMainThreadBridge::create(workerGlobalScope, webWorkerBase, mode, name); // Either the bridge returns, or the queue gets terminated. if (runLoop.runInMode(workerGlobalScope, mode) == MessageQueueTerminated) { bridge->cancel(); return false; } allowed = bridge->result(); } if (!allowed) callbacks->onError(WebIDBDatabaseError(UnknownError, "The user denied permission to access the database.")); return allowed; }
static bool isAllowed(ScriptState* scriptState, ExecutionContext* executionContext, bool isEval) { if (executionContext->isDocument()) { Document* document = static_cast<Document*>(executionContext); if (isEval && !document->contentSecurityPolicy()->allowEval(scriptState, ContentSecurityPolicy::SendReport, ContentSecurityPolicy::WillNotThrowException)) return false; return true; } if (executionContext->isWorkerGlobalScope()) { WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(executionContext); if (!workerGlobalScope->script()) return false; ContentSecurityPolicy* policy = workerGlobalScope->contentSecurityPolicy(); if (isEval && policy && !policy->allowEval(scriptState, ContentSecurityPolicy::SendReport, ContentSecurityPolicy::WillNotThrowException)) return false; return true; } ASSERT_NOT_REACHED(); return false; }
static void openFileSystem(ScriptExecutionContext* context, const String& basePath, FileSystemType type, long long size, bool create, PassOwnPtr<AsyncFileSystemCallbacks> callbacks, FileSystemSynchronousType synchronousType) { ASSERT(context); ASSERT(type != FileSystemTypeIsolated); if (type == FileSystemTypeIsolated) return; KURL url = context->url(); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); url.setQuery(String()); url.setPath("/"); StringBuilder builder; builder.append("filesystem:"); builder.append(url.string()); builder.append(fileSystemTypeString(type)); KURL rootURL = context->completeURL(builder.toString()); ASSERT(rootURL.isValid()); // TODO: Ask user for file system permission. if (context->isDocument()) { int playerId = 0; Page* page = static_cast<Document*>(context)->page(); if (page) playerId = page->chrome().client()->platformPageClient()->playerID(); AsyncFileSystemBlackBerry::openFileSystem(rootURL, basePath, context->securityOrigin()->databaseIdentifier(), type, size, create, playerId, callbacks); } else { #if ENABLE(WORKERS) WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); String mode = openFileSystemMode; mode.append(String::number(workerGlobalScope->thread()->runLoop().createUniqueId())); WorkerAsyncFileSystemBlackBerry::openFileSystem(workerGlobalScope, rootURL, mode, basePath, context->securityOrigin()->databaseIdentifier(), type, size, create, callbacks); if (synchronousType == SynchronousFileSystem) workerGlobalScope->thread()->runLoop().runInMode(workerGlobalScope, mode); #else ASSERT_NOT_REACHED(); #endif } }
void LocalFileSystem::deleteFileSystem(ScriptExecutionContext* context, FileSystemType type, PassOwnPtr<AsyncFileSystemCallbacks> callbacks) { ASSERT(context); ASSERT(type != FileSystemTypeIsolated); if (type == FileSystemTypeIsolated) return; // TODO: Ask user for file system permission. if (context->isDocument()) AsyncFileSystemBlackBerry::deleteFileSystem(fileSystemBasePath(), context->securityOrigin()->databaseIdentifier(), type, callbacks); else { #if ENABLE(WORKERS) WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); String mode = deleteFileSystemMode; mode.append(String::number(workerGlobalScope->thread()->runLoop().createUniqueId())); WorkerAsyncFileSystemBlackBerry::deleteFileSystem(workerGlobalScope, mode, fileSystemBasePath(), context->securityOrigin()->databaseIdentifier(), type, callbacks); #else ASSERT_NOT_REACHED(); #endif } }
void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options) { WorkerRunLoop& runLoop = workerGlobalScope.thread().runLoop(); // Create a unique mode just for this synchronous resource load. String mode = loadResourceSynchronouslyMode; mode.append(String::number(runLoop.createUniqueId())); RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, client, mode, WTFMove(request), options, String()); MessageQueueWaitResult result = MessageQueueMessageReceived; while (!loader->done() && result != MessageQueueTerminated) result = runLoop.runInMode(&workerGlobalScope, mode); if (!loader->done() && result == MessageQueueTerminated) loader->cancel(); }
PassRefPtrWillBeRawPtr<DatabaseSync> WorkerGlobalScopeWebDatabase::openDatabaseSync(WorkerGlobalScope& context, const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback, ExceptionState& exceptionState) { DatabaseManager& dbManager = DatabaseManager::manager(); RefPtrWillBeRawPtr<DatabaseSync> database = nullptr; DatabaseError error = DatabaseError::None; if (RuntimeEnabledFeatures::databaseEnabled() && context.securityOrigin()->canAccessDatabase()) { String errorMessage; database = dbManager.openDatabaseSync(&context, name, version, displayName, estimatedSize, creationCallback, error, errorMessage); ASSERT(database || error != DatabaseError::None); if (error != DatabaseError::None) DatabaseManager::throwExceptionForDatabaseError(error, errorMessage, exceptionState); } else { exceptionState.throwSecurityError("Access to the WebDatabase API is denied in this context."); } return database.release(); }
void WorkerThread::stop() { // Mutex protection is necessary because stop() can be called before the context is fully created. MutexLocker lock(m_threadCreationMutex); // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever. if (m_workerGlobalScope) { m_workerGlobalScope->script()->scheduleExecutionTermination(); #if ENABLE(SQL_DATABASE) DatabaseManager::manager().interruptAllDatabasesForContext(m_workerGlobalScope.get()); #endif m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext* context ) { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); #if ENABLE(SQL_DATABASE) // FIXME: Should we stop the databases as part of stopActiveDOMObjects() below? DatabaseTaskSynchronizer cleanupSync; DatabaseManager::manager().stopDatabases(workerGlobalScope, &cleanupSync); #endif workerGlobalScope->stopActiveDOMObjects(); workerGlobalScope->notifyObserversOfStop(); // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects, // which become dangling once Heap is destroyed. workerGlobalScope->removeAllEventListeners(); #if ENABLE(SQL_DATABASE) // We wait for the database thread to clean up all its stuff so that we // can do more stringent leak checks as we exit. cleanupSync.waitForTaskCompletion(); #endif // Stick a shutdown command at the end of the queue, so that we deal // with all the cleanup tasks the databases post first. workerGlobalScope->postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext* context) { WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed. workerGlobalScope->clearScript(); } }); } }); return; } m_runLoop.terminate(); }