1/* 2 * Copyright (C) 2007, 2008 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(DATABASE) 33 34#include "AutodrainedPool.h" 35#include "Database.h" 36#include "DatabaseTask.h" 37#include "Logging.h" 38#include "SQLTransactionClient.h" 39#include "SQLTransactionCoordinator.h" 40#include <wtf/UnusedParam.h> 41 42namespace WebCore { 43 44DatabaseThread::DatabaseThread() 45 : m_threadID(0) 46 , m_transactionClient(adoptPtr(new SQLTransactionClient())) 47 , m_transactionCoordinator(adoptPtr(new SQLTransactionCoordinator())) 48 , m_cleanupSync(0) 49{ 50 m_selfRef = this; 51} 52 53DatabaseThread::~DatabaseThread() 54{ 55 // FIXME: Any cleanup required here? Since the thread deletes itself after running its detached course, I don't think so. Lets be sure. 56 ASSERT(terminationRequested()); 57} 58 59bool DatabaseThread::start() 60{ 61 MutexLocker lock(m_threadCreationMutex); 62 63 if (m_threadID) 64 return true; 65 66 m_threadID = createThread(DatabaseThread::databaseThreadStart, this, "WebCore: Database"); 67 68 return m_threadID; 69} 70 71void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync) 72{ 73 ASSERT(!m_cleanupSync); 74 m_cleanupSync = cleanupSync; 75 LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this); 76 m_queue.kill(); 77} 78 79bool DatabaseThread::terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer) const 80{ 81#ifndef NDEBUG 82 if (taskSynchronizer) 83 taskSynchronizer->setHasCheckedForTermination(); 84#else 85 UNUSED_PARAM(taskSynchronizer); 86#endif 87 88 return m_queue.killed(); 89} 90 91void* DatabaseThread::databaseThreadStart(void* vDatabaseThread) 92{ 93 DatabaseThread* dbThread = static_cast<DatabaseThread*>(vDatabaseThread); 94 return dbThread->databaseThread(); 95} 96 97void* DatabaseThread::databaseThread() 98{ 99 { 100 // Wait for DatabaseThread::start() to complete. 101 MutexLocker lock(m_threadCreationMutex); 102 LOG(StorageAPI, "Started DatabaseThread %p", this); 103 } 104 105 AutodrainedPool pool; 106 while (OwnPtr<DatabaseTask> task = m_queue.waitForMessage()) { 107 task->performTask(); 108 pool.cycle(); 109 } 110 111 // Clean up the list of all pending transactions on this database thread 112 m_transactionCoordinator->shutdown(); 113 114 LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); 115 116 // 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 117 // inconsistent or locked state. 118 if (m_openDatabaseSet.size() > 0) { 119 // As the call to close will modify the original set, we must take a copy to iterate over. 120 DatabaseSet openSetCopy; 121 openSetCopy.swap(m_openDatabaseSet); 122 DatabaseSet::iterator end = openSetCopy.end(); 123 for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it) 124 (*it)->close(); 125 } 126 127 // Detach the thread so its resources are no longer of any concern to anyone else 128 detachThread(m_threadID); 129 130 DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync; 131 132 // Clear the self refptr, possibly resulting in deletion 133 m_selfRef = 0; 134 135 if (cleanupSync) // Someone wanted to know when we were done cleaning up. 136 cleanupSync->taskCompleted(); 137 138 return 0; 139} 140 141void DatabaseThread::recordDatabaseOpen(Database* database) 142{ 143 ASSERT(currentThread() == m_threadID); 144 ASSERT(database); 145 ASSERT(!m_openDatabaseSet.contains(database)); 146 m_openDatabaseSet.add(database); 147} 148 149void DatabaseThread::recordDatabaseClosed(Database* database) 150{ 151 ASSERT(currentThread() == m_threadID); 152 ASSERT(database); 153 ASSERT(m_queue.killed() || m_openDatabaseSet.contains(database)); 154 m_openDatabaseSet.remove(database); 155} 156 157void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task) 158{ 159 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 160 m_queue.append(task); 161} 162 163void DatabaseThread::scheduleImmediateTask(PassOwnPtr<DatabaseTask> task) 164{ 165 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 166 m_queue.prepend(task); 167} 168 169class SameDatabasePredicate { 170public: 171 SameDatabasePredicate(const Database* database) : m_database(database) { } 172 bool operator()(DatabaseTask* task) const { return task->database() == m_database; } 173private: 174 const Database* m_database; 175}; 176 177void DatabaseThread::unscheduleDatabaseTasks(Database* database) 178{ 179 // Note that the thread loop is running, so some tasks for the database 180 // may still be executed. This is unavoidable. 181 SameDatabasePredicate predicate(database); 182 m_queue.removeIf(predicate); 183} 184} // namespace WebCore 185#endif 186