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 42 namespace WebCore { 43 44 DatabaseThread::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 53 DatabaseThread::~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 59 bool 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 71 void 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 79 bool 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 91 void* DatabaseThread::databaseThreadStart(void* vDatabaseThread) 92 { 93 DatabaseThread* dbThread = static_cast<DatabaseThread*>(vDatabaseThread); 94 return dbThread->databaseThread(); 95 } 96 97 void* 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 141 void 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 149 void 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 157 void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task) 158 { 159 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 160 m_queue.append(task); 161 } 162 163 void DatabaseThread::scheduleImmediateTask(PassOwnPtr<DatabaseTask> task) 164 { 165 ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination()); 166 m_queue.prepend(task); 167 } 168 169 class SameDatabasePredicate { 170 public: 171 SameDatabasePredicate(const Database* database) : m_database(database) { } 172 bool operator()(DatabaseTask* task) const { return task->database() == m_database; } 173 private: 174 const Database* m_database; 175 }; 176 177 void 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