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