15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     documentation and/or other materials provided with the distribution.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     its contributors may be used to endorse or promote products derived
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     from this software without specific prior written permission.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webdatabase/DatabaseThread.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webdatabase/Database.h"
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webdatabase/DatabaseTask.h"
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webdatabase/SQLTransactionClient.h"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webdatabase/SQLTransactionCoordinator.h"
36a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/Logging.h"
37a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch#include "platform/heap/glue/MessageLoopInterruptor.h"
38a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch#include "platform/heap/glue/PendingGCRunner.h"
39a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "public/platform/Platform.h"
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)DatabaseThread::DatabaseThread()
44a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    : m_transactionClient(adoptPtr(new SQLTransactionClient()))
4543e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)    , m_transactionCoordinator(adoptPtrWillBeNoop(new SQLTransactionCoordinator()))
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_cleanupSync(0)
47a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    , m_terminationRequested(false)
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)DatabaseThread::~DatabaseThread()
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
53d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ASSERT(m_openDatabaseSet.isEmpty());
54d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Oilpan: The database thread must have finished its cleanup tasks before
55d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // the following clear(). Otherwise, WebThread destructor blocks the caller
56d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // thread, and causes a deadlock with ThreadState cleanup.
57d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // DatabaseContext::stop() asks the database thread to close all of
58d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // databases, and wait until GC heap cleanup of the database thread. So we
59d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // can safely destruct WebThread here.
60a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    m_thread.clear();
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6343e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)void DatabaseThread::trace(Visitor* visitor)
6443e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles){
6543e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)    visitor->trace(m_openDatabaseSet);
6643e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)    visitor->trace(m_transactionCoordinator);
6743e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)}
6843e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)
69a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)void DatabaseThread::start()
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
71a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (m_thread)
72a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        return;
73a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    m_thread = adoptPtr(blink::Platform::current()->createThread("WebCore: Database"));
74d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_thread->postTask(new Task(WTF::bind(&DatabaseThread::setupDatabaseThread, this)));
75d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
76d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
77d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void DatabaseThread::setupDatabaseThread()
78d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
79d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_pendingGCRunner = adoptPtr(new PendingGCRunner);
80d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_messageLoopInterruptor = adoptPtr(new MessageLoopInterruptor(m_thread.get()));
81d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_thread->addTaskObserver(m_pendingGCRunner.get());
82d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ThreadState::attach();
83d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ThreadState::current()->addInterruptor(m_messageLoopInterruptor.get());
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
86a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdochvoid DatabaseThread::requestTermination(TaskSynchronizer *cleanupSync)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    MutexLocker lock(m_terminationRequestedMutex);
89a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ASSERT(!m_terminationRequested);
90a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    m_terminationRequested = true;
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_cleanupSync = cleanupSync;
92a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF_LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
93a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    m_thread->postTask(new Task(WTF::bind(&DatabaseThread::cleanupDatabaseThread, this)));
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
96a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdochbool DatabaseThread::terminationRequested(TaskSynchronizer* taskSynchronizer) const
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifndef NDEBUG
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (taskSynchronizer)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        taskSynchronizer->setHasCheckedForTermination();
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    MutexLocker lock(m_terminationRequestedMutex);
104a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    return m_terminationRequested;
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
107a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)void DatabaseThread::cleanupDatabaseThread()
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
109a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF_LOG(StorageAPI, "Cleaning up DatabaseThread %p", this);
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Clean up the list of all pending transactions on this database thread
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_transactionCoordinator->shutdown();
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 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
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // inconsistent or locked state.
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_openDatabaseSet.size() > 0) {
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // As the call to close will modify the original set, we must take a copy to iterate over.
118d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        WillBeHeapHashSet<RefPtrWillBeMember<DatabaseBackend> > openSetCopy;
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        openSetCopy.swap(m_openDatabaseSet);
120d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        WillBeHeapHashSet<RefPtrWillBeMember<DatabaseBackend> >::iterator end = openSetCopy.end();
121d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        for (WillBeHeapHashSet<RefPtrWillBeMember<DatabaseBackend> >::iterator it = openSetCopy.begin(); it != end; ++it)
122d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            (*it)->close();
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
125d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_thread->postTask(new Task(WTF::bind(&DatabaseThread::cleanupDatabaseThreadCompleted, this)));
126d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
127d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
128d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void DatabaseThread::cleanupDatabaseThreadCompleted()
129d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
130d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ThreadState::current()->removeInterruptor(m_messageLoopInterruptor.get());
131d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ThreadState::detach();
132d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // We need to unregister PendingGCRunner before finising this task to avoid
133d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // PendingGCRunner::didProcessTask accesses dead ThreadState.
134d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    m_thread->removeTaskObserver(m_pendingGCRunner.get());
135d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
136a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (m_cleanupSync) // Someone wanted to know when we were done cleaning up.
137a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        m_cleanupSync->taskCompleted();
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
140926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void DatabaseThread::recordDatabaseOpen(DatabaseBackend* database)
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    ASSERT(isDatabaseThread());
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(database);
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!m_openDatabaseSet.contains(database));
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_openDatabaseSet.add(database);
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
148926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void DatabaseThread::recordDatabaseClosed(DatabaseBackend* database)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    ASSERT(isDatabaseThread());
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(database);
152a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ASSERT(m_terminationRequested || m_openDatabaseSet.contains(database));
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_openDatabaseSet.remove(database);
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DatabaseThread::isDatabaseOpen(DatabaseBackend* database)
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    ASSERT(isDatabaseThread());
15951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    ASSERT(database);
16009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    MutexLocker lock(m_terminationRequestedMutex);
161a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    return !m_terminationRequested && m_openDatabaseSet.contains(database);
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
166a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ASSERT(m_thread);
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination());
168a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // WebThread takes ownership of the task.
169a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    m_thread->postTask(task.leakPtr());
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
173