1/* 2 * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "DatabaseThread.h" 31 32#if ENABLE(SQL_DATABASE) 33 34#include "Database.h" 35#include "DatabaseTask.h" 36#include "Logging.h" 37#include "SQLTransactionClient.h" 38#include "SQLTransactionCoordinator.h" 39#include <wtf/AutodrainedPool.h> 40 41namespace WebCore { 42 43DatabaseThread::DatabaseThread() 44 : m_threadID(0) 45 , m_transactionClient(adoptPtr(new SQLTransactionClient())) 46 , m_transactionCoordinator(adoptPtr(new SQLTransactionCoordinator())) 47 , m_cleanupSync(0) 48{ 49 m_selfRef = this; 50} 51 52DatabaseThread::~DatabaseThread() 53{ 54 // The DatabaseThread will only be destructed when both its owner 55 // DatabaseContext has deref'ed it, and the databaseThread() thread function 56 // has deref'ed the DatabaseThread object. The DatabaseContext destructor 57 // will take care of ensuring that a termination request has been issued. 58 // The termination request will trigger an orderly shutdown of the thread 59 // function databaseThread(). In shutdown, databaseThread() will deref the 60 // DatabaseThread before returning. 61 ASSERT(terminationRequested()); 62} 63 64bool DatabaseThread::start() 65{ 66 MutexLocker lock(m_threadCreationMutex); 67 68 if (m_threadID) 69 return true; 70 71 m_threadID = createThread(DatabaseThread::databaseThreadStart, this, "WebCore: Database"); 72 73 return m_threadID; 74} 75 76void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync) 77{ 78 m_cleanupSync = cleanupSync; 79 LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this); 80 m_queue.kill(); 81} 82 83bool DatabaseThread::terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer) const 84{ 85#ifndef NDEBUG 86 if (taskSynchronizer) 87 taskSynchronizer->setHasCheckedForTermination(); 88#else 89 UNUSED_PARAM(taskSynchronizer); 90#endif 91 92 return m_queue.killed(); 93} 94 95void DatabaseThread::databaseThreadStart(void* vDatabaseThread) 96{ 97 DatabaseThread* dbThread = static_cast<DatabaseThread*>(vDatabaseThread); 98 dbThread->databaseThread(); 99} 100 101void DatabaseThread::databaseThread() 102{ 103 { 104 // Wait for DatabaseThread::start() to complete. 105 MutexLocker lock(m_threadCreationMutex); 106 LOG(StorageAPI, "Started DatabaseThread %p", this); 107 } 108 109 while (OwnPtr<DatabaseTask> task = m_queue.waitForMessage()) { 110 AutodrainedPool pool; 111 112 task->performTask(); 113 } 114 115 // Clean up the list of all pending transactions on this database thread 116 m_transactionCoordinator->shutdown(); 117 118 LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); 119 120 // 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 121 // inconsistent or locked state. 122 if (m_openDatabaseSet.size() > 0) { 123 // As the call to close will modify the original set, we must take a copy to iterate over. 124 DatabaseSet openSetCopy; 125 openSetCopy.swap(m_openDatabaseSet); 126 DatabaseSet::iterator end = openSetCopy.end(); 127 for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it) 128 (*it).get()->close(); 129 } 130 131 // Detach the thread so its resources are no longer of any concern to anyone else 132 detachThread(m_threadID); 133 134 DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync; 135 136 // Clear the self refptr, possibly resulting in deletion 137 m_selfRef = 0; 138 139 if (cleanupSync) // Someone wanted to know when we were done cleaning up. 140 cleanupSync->taskCompleted(); 141} 142 143void DatabaseThread::recordDatabaseOpen(DatabaseBackend* database) 144{ 145 ASSERT(currentThread() == m_threadID); 146 ASSERT(database); 147 ASSERT(!m_openDatabaseSet.contains(database)); 148 m_openDatabaseSet.add(database); 149} 150 151void DatabaseThread::recordDatabaseClosed(DatabaseBackend* database) 152{ 153 ASSERT(currentThread() == m_threadID); 154 ASSERT(database); 155 ASSERT(m_queue.killed() || m_openDatabaseSet.contains(database)); 156 m_openDatabaseSet.remove(database); 157} 158 159void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task) 160{ 161 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 162 m_queue.append(task); 163} 164 165void DatabaseThread::scheduleImmediateTask(PassOwnPtr<DatabaseTask> task) 166{ 167 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 168 m_queue.prepend(task); 169} 170 171class SameDatabasePredicate { 172public: 173 SameDatabasePredicate(const DatabaseBackend* database) : m_database(database) { } 174 bool operator()(DatabaseTask* task) const { return task->database() == m_database; } 175private: 176 const DatabaseBackend* m_database; 177}; 178 179void DatabaseThread::unscheduleDatabaseTasks(DatabaseBackend* database) 180{ 181 // Note that the thread loop is running, so some tasks for the database 182 // may still be executed. This is unavoidable. 183 SameDatabasePredicate predicate(database); 184 m_queue.removeIf(predicate); 185} 186} // namespace WebCore 187#endif 188