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