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 "modules/webdatabase/Database.h" 33 #include "modules/webdatabase/DatabaseTask.h" 34 #include "modules/webdatabase/SQLTransactionClient.h" 35 #include "modules/webdatabase/SQLTransactionCoordinator.h" 36 #include "platform/Logging.h" 37 #include "platform/heap/glue/MessageLoopInterruptor.h" 38 #include "platform/heap/glue/PendingGCRunner.h" 39 #include "public/platform/Platform.h" 40 41 namespace blink { 42 43 DatabaseThread::DatabaseThread() 44 : m_transactionClient(adoptPtr(new SQLTransactionClient())) 45 , m_transactionCoordinator(adoptPtrWillBeNoop(new SQLTransactionCoordinator())) 46 , m_cleanupSync(0) 47 , m_terminationRequested(false) 48 { 49 } 50 51 DatabaseThread::~DatabaseThread() 52 { 53 ASSERT(m_openDatabaseSet.isEmpty()); 54 ASSERT(!m_thread); 55 } 56 57 void DatabaseThread::trace(Visitor* visitor) 58 { 59 #if ENABLE(OILPAN) 60 visitor->trace(m_openDatabaseSet); 61 visitor->trace(m_transactionCoordinator); 62 #endif 63 } 64 65 void DatabaseThread::start() 66 { 67 if (m_thread) 68 return; 69 m_thread = WebThreadSupportingGC::create("WebCore: Database"); 70 m_thread->postTask(new Task(WTF::bind(&DatabaseThread::setupDatabaseThread, this))); 71 } 72 73 void DatabaseThread::setupDatabaseThread() 74 { 75 m_thread->attachGC(); 76 } 77 78 void DatabaseThread::terminate() 79 { 80 TaskSynchronizer sync; 81 { 82 MutexLocker lock(m_terminationRequestedMutex); 83 ASSERT(!m_terminationRequested); 84 m_terminationRequested = true; 85 m_cleanupSync = &sync; 86 WTF_LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this); 87 m_thread->postTask(new Task(WTF::bind(&DatabaseThread::cleanupDatabaseThread, this))); 88 } 89 sync.waitForTaskCompletion(); 90 // The WebThread destructor blocks until all the tasks of the database 91 // thread are processed. However, it shouldn't block at all because 92 // the database thread has already finished processing the cleanup task. 93 m_thread.clear(); 94 } 95 96 bool DatabaseThread::terminationRequested() const 97 { 98 MutexLocker lock(m_terminationRequestedMutex); 99 return m_terminationRequested; 100 } 101 102 void DatabaseThread::cleanupDatabaseThread() 103 { 104 WTF_LOG(StorageAPI, "Cleaning up DatabaseThread %p", this); 105 106 // Clean up the list of all pending transactions on this database thread 107 m_transactionCoordinator->shutdown(); 108 109 // 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 110 // inconsistent or locked state. 111 if (m_openDatabaseSet.size() > 0) { 112 // As the call to close will modify the original set, we must take a copy to iterate over. 113 WillBeHeapHashSet<RefPtrWillBeMember<Database> > openSetCopy; 114 openSetCopy.swap(m_openDatabaseSet); 115 WillBeHeapHashSet<RefPtrWillBeMember<Database> >::iterator end = openSetCopy.end(); 116 for (WillBeHeapHashSet<RefPtrWillBeMember<Database> >::iterator it = openSetCopy.begin(); it != end; ++it) 117 (*it)->close(); 118 } 119 120 m_thread->postTask(new Task(WTF::bind(&DatabaseThread::cleanupDatabaseThreadCompleted, this))); 121 } 122 123 void DatabaseThread::cleanupDatabaseThreadCompleted() 124 { 125 m_thread->detachGC(); 126 if (m_cleanupSync) // Someone wanted to know when we were done cleaning up. 127 m_cleanupSync->taskCompleted(); 128 } 129 130 void DatabaseThread::recordDatabaseOpen(Database* database) 131 { 132 ASSERT(isDatabaseThread()); 133 ASSERT(database); 134 ASSERT(!m_openDatabaseSet.contains(database)); 135 m_openDatabaseSet.add(database); 136 } 137 138 void DatabaseThread::recordDatabaseClosed(Database* database) 139 { 140 ASSERT(isDatabaseThread()); 141 ASSERT(database); 142 ASSERT(m_terminationRequested || m_openDatabaseSet.contains(database)); 143 m_openDatabaseSet.remove(database); 144 } 145 146 bool DatabaseThread::isDatabaseOpen(Database* database) 147 { 148 ASSERT(isDatabaseThread()); 149 ASSERT(database); 150 MutexLocker lock(m_terminationRequestedMutex); 151 return !m_terminationRequested && m_openDatabaseSet.contains(database); 152 } 153 154 void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task) 155 { 156 ASSERT(m_thread); 157 ASSERT(!terminationRequested()); 158 // WebThread takes ownership of the task. 159 m_thread->postTask(task.leakPtr()); 160 } 161 162 } // namespace blink 163