Esempio n. 1
0
void DatabaseContext::stopDatabases()
{
    stopSyncDatabases();
    if (m_isRegistered) {
        DatabaseManager::manager().unregisterDatabaseContext(this);
        m_isRegistered = false;
    }

    // Though we initiate termination of the DatabaseThread here in
    // stopDatabases(), we can't clear the m_databaseThread ref till we get to
    // the destructor. This is because the Databases that are managed by
    // DatabaseThread still rely on this ref between the context and the thread
    // to execute the task for closing the database. By the time we get to the
    // destructor, we're guaranteed that the databases are destructed (which is
    // why our ref count is 0 then and we're destructing). Then, the
    // m_databaseThread RefPtr destructor will deref and delete the
    // DatabaseThread.

    if (m_databaseThread && !m_hasRequestedTermination) {
        DatabaseTaskSynchronizer sync;
        m_databaseThread->requestTermination(&sync);
        m_hasRequestedTermination = true;
        sync.waitForTaskCompletion();
    }
}
Esempio n. 2
0
    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());
    }
    virtual void performTask(ScriptExecutionContext *context)
    {
        ASSERT(context->isWorkerContext());
        WorkerContext* workerContext = static_cast<WorkerContext*>(context);

#if ENABLE(DATABASE)
        // We currently ignore any DatabasePolicy used for the document's
        // databases; if it's actually used anywhere, this should be revisited.
        DatabaseTaskSynchronizer cleanupSync;
        workerContext->stopDatabases(&cleanupSync);
#endif

        workerContext->stopActiveDOMObjects();

        // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
        // which become dangling once Heap is destroyed.
        workerContext->removeAllEventListeners();

#if ENABLE(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.
        workerContext->postTask(WorkerThreadShutdownFinishTask::create());
    }
Esempio n. 4
0
bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
    DatabaseTaskSynchronizer synchronizer;
    if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
        return false;

    bool success = false;
    auto task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
    databaseContext()->databaseThread()->scheduleImmediateTask(WTF::move(task));
    synchronizer.waitForTaskCompletion();

    return success;
}
Esempio n. 5
0
bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode& e)
{
    DatabaseTaskSynchronizer synchronizer;
    if (!m_scriptExecutionContext->databaseThread() || m_scriptExecutionContext->databaseThread()->terminationRequested(&synchronizer))
        return false;

    bool success = false;
    OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, e, success);
    m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
    synchronizer.waitForTaskCompletion();

    return success;
}
Esempio n. 6
0
bool DatabaseBackend::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
    DatabaseTaskSynchronizer synchronizer;
    if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
        return false;

    DatabaseTracker::tracker().prepareToOpenDatabase(this);
    bool success = false;
    OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
    databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
    synchronizer.waitForTaskCompletion();

    return success;
}
Vector<String> Database::tableNames()
{
    // FIXME: Not using isolatedCopy on these strings looks ok since threads take strict turns
    // in dealing with them. However, if the code changes, this may not be true anymore.
    Vector<String> result;
    DatabaseTaskSynchronizer synchronizer;
    if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
        return result;

    OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
    databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
    synchronizer.waitForTaskCompletion();

    return result;
}
Esempio n. 8
0
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();
}
void Database::markAsDeletedAndClose()
{
    if (m_deleted || !databaseContext()->databaseThread())
        return;

    LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
    m_deleted = true;

    DatabaseTaskSynchronizer synchronizer;
    if (databaseContext()->databaseThread()->terminationRequested(&synchronizer)) {
        LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
        return;
    }

    OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
    databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
    synchronizer.waitForTaskCompletion();
}
Esempio n. 10
0
void DatabaseThread::databaseThread()
{
    {
        // Wait for DatabaseThread::start() to complete.
        LockHolder lock(m_threadCreationMutex);
        LOG(StorageAPI, "Started DatabaseThread %p", this);
    }

    while (auto task = m_queue.waitForMessage()) {
        AutodrainedPool pool;

        task->performTask();
    }

    // Clean up the list of all pending transactions on this database thread
    m_transactionCoordinator->shutdown();

    LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount());

    // Close the databases that we ran transactions on. This ensures that if any transactions are still open, they are rolled back and we don't leave the database in an
    // inconsistent or locked state.
    DatabaseSet openSetCopy;
    {
        LockHolder lock(m_openDatabaseSetMutex);
        if (m_openDatabaseSet.size() > 0) {
            // As the call to close will modify the original set, we must take a copy to iterate over.
            openSetCopy.swap(m_openDatabaseSet);
        }
    }

    for (auto& openDatabase : openSetCopy)
        openDatabase->close();

    // Detach the thread so its resources are no longer of any concern to anyone else
    detachThread(m_threadID);

    DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;

    // Clear the self refptr, possibly resulting in deletion
    m_selfRef = nullptr;

    if (cleanupSync) // Someone wanted to know when we were done cleaning up.
        cleanupSync->taskCompleted();
}
Esempio n. 11
0
    virtual void performTask(ScriptExecutionContext *context)
    {
        ASSERT(context->isWorkerContext());
        WorkerContext* workerContext = static_cast<WorkerContext*>(context);

        // We currently ignore any DatabasePolicy used for the document's
        // databases; if it's actually used anywhere, this should be revisited.
        DatabaseTaskSynchronizer cleanupSync;
        workerContext->stopDatabases(&cleanupSync);

        workerContext->stopActiveDOMObjects();
        workerContext->clearScript();

        // 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();

        // Stick a shutdown command at the end of the queue, so that we deal
        // with all the cleanup tasks the databases post first.
        workerContext->postTask(WorkerThreadShutdownFinishTask::create());
    }