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