Use modern for-loops in WebCore/Modules - 2
[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 #if PLATFORM(IOS)
44     , m_paused(false)
45 #endif
46     , m_transactionClient(std::make_unique<SQLTransactionClient>())
47     , m_transactionCoordinator(std::make_unique<SQLTransactionCoordinator>())
48     , m_cleanupSync(0)
49 {
50     m_selfRef = this;
51 }
52
53 DatabaseThread::~DatabaseThread()
54 {
55     // The DatabaseThread will only be destructed when both its owner
56     // DatabaseContext has deref'ed it, and the databaseThread() thread function
57     // has deref'ed the DatabaseThread object. The DatabaseContext destructor
58     // will take care of ensuring that a termination request has been issued.
59     // The termination request will trigger an orderly shutdown of the thread
60     // function databaseThread(). In shutdown, databaseThread() will deref the
61     // DatabaseThread before returning.
62     ASSERT(terminationRequested());
63 }
64
65 bool DatabaseThread::start()
66 {
67     MutexLocker lock(m_threadCreationMutex);
68
69     if (m_threadID)
70         return true;
71
72     m_threadID = createThread(DatabaseThread::databaseThreadStart, this, "WebCore: Database");
73
74     return m_threadID;
75 }
76
77 void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
78 {
79     m_cleanupSync = cleanupSync;
80     LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
81 #if PLATFORM(IOS)
82     m_pausedQueue.kill();
83 #endif
84     m_queue.kill();
85 }
86
87 bool DatabaseThread::terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer) const
88 {
89 #ifndef NDEBUG
90     if (taskSynchronizer)
91         taskSynchronizer->setHasCheckedForTermination();
92 #else
93     UNUSED_PARAM(taskSynchronizer);
94 #endif
95
96     return m_queue.killed();
97 }
98
99 void DatabaseThread::databaseThreadStart(void* vDatabaseThread)
100 {
101     DatabaseThread* dbThread = static_cast<DatabaseThread*>(vDatabaseThread);
102     dbThread->databaseThread();
103 }
104
105 #if PLATFORM(IOS)
106 class DatabaseUnpauseTask : public DatabaseTask {
107 public:
108     explicit DatabaseUnpauseTask(DatabaseThread& thread)
109         : DatabaseTask(0, 0)
110         , m_thread(thread)
111     { }
112
113     virtual bool shouldPerformWhilePaused() const 
114     {
115         // Since we're not locking the DatabaseThread::m_paused in the main database thread loop, it's possible that
116         // a DatabaseUnpauseTask might be added to the m_pausedQueue and performed from within ::handlePausedQueue.
117         // To protect against this, we allow it to be performed even if the database is paused.
118         // If the thread is paused when it is being performed, the tasks from the paused queue will simply be
119         // requeued instead of performed.
120         return true;
121     }
122
123 private:
124     virtual void doPerformTask()
125     {
126         m_thread.handlePausedQueue();
127     }
128 #if !LOG_DISABLED
129     virtual const char* debugTaskName() const { return "DatabaseUnpauseTask"; }
130 #endif
131
132     DatabaseThread& m_thread;
133 };
134
135
136 void DatabaseThread::setPaused(bool paused)
137 {
138     if (m_paused == paused)
139         return;
140
141     MutexLocker pausedLocker(m_pausedMutex);
142     m_paused = paused;
143     if (!m_paused)
144         scheduleTask(std::make_unique<DatabaseUnpauseTask>(*this));
145 }
146
147 void DatabaseThread::handlePausedQueue()
148 {
149     Vector<std::unique_ptr<DatabaseTask> > pausedTasks;
150     while (auto task = m_pausedQueue.tryGetMessage())
151         pausedTasks.append(WTF::move(task));
152
153     for (auto& pausedTask : pausedTasks) {
154         AutodrainedPool pool;
155
156         std::unique_ptr<DatabaseTask> task(pausedTask.release());
157         {
158             MutexLocker pausedLocker(m_pausedMutex);
159             if (m_paused) {
160                 m_pausedQueue.append(WTF::move(task));
161                 continue;
162             }
163         }
164             
165         if (terminationRequested())
166             break;
167     
168         task->performTask();
169     }
170 }
171 #endif //PLATFORM(IOS)
172
173
174 void DatabaseThread::databaseThread()
175 {
176     {
177         // Wait for DatabaseThread::start() to complete.
178         MutexLocker lock(m_threadCreationMutex);
179         LOG(StorageAPI, "Started DatabaseThread %p", this);
180     }
181
182     while (auto task = m_queue.waitForMessage()) {
183         AutodrainedPool pool;
184
185 #if PLATFORM(IOS)
186         if (!m_paused || task->shouldPerformWhilePaused())
187             task->performTask();
188         else
189             m_pausedQueue.append(WTF::move(task));
190 #else
191         task->performTask();
192 #endif
193     }
194
195     // Clean up the list of all pending transactions on this database thread
196     m_transactionCoordinator->shutdown();
197
198     LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
199
200     // 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
201     // inconsistent or locked state.
202     if (m_openDatabaseSet.size() > 0) {
203         // As the call to close will modify the original set, we must take a copy to iterate over.
204         DatabaseSet openSetCopy;
205         openSetCopy.swap(m_openDatabaseSet);
206         for (auto& openDatabase : openSetCopy)
207             openDatabase->close();
208     }
209
210     // Detach the thread so its resources are no longer of any concern to anyone else
211     detachThread(m_threadID);
212
213     DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;
214
215     // Clear the self refptr, possibly resulting in deletion
216     m_selfRef = 0;
217
218     if (cleanupSync) // Someone wanted to know when we were done cleaning up.
219         cleanupSync->taskCompleted();
220 }
221
222 void DatabaseThread::recordDatabaseOpen(Database* database)
223 {
224     ASSERT(currentThread() == m_threadID);
225     ASSERT(database);
226     ASSERT(!m_openDatabaseSet.contains(database));
227     m_openDatabaseSet.add(database);
228 }
229
230 void DatabaseThread::recordDatabaseClosed(Database* database)
231 {
232     ASSERT(currentThread() == m_threadID);
233     ASSERT(database);
234     ASSERT(m_queue.killed() || m_openDatabaseSet.contains(database));
235     m_openDatabaseSet.remove(database);
236 }
237
238 void DatabaseThread::scheduleTask(std::unique_ptr<DatabaseTask> task)
239 {
240     ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination());
241     m_queue.append(WTF::move(task));
242 }
243
244 void DatabaseThread::scheduleImmediateTask(std::unique_ptr<DatabaseTask> task)
245 {
246     ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination());
247     m_queue.prepend(WTF::move(task));
248 }
249
250 class SameDatabasePredicate {
251 public:
252     SameDatabasePredicate(const Database* database) : m_database(database) { }
253     bool operator()(const DatabaseTask& task) const { return task.database() == m_database; }
254 private:
255     const Database* m_database;
256 };
257
258 void DatabaseThread::unscheduleDatabaseTasks(Database* database)
259 {
260     // Note that the thread loop is running, so some tasks for the database
261     // may still be executed. This is unavoidable.
262     SameDatabasePredicate predicate(database);
263     m_queue.removeIf(predicate);
264 }
265
266 bool DatabaseThread::hasPendingDatabaseActivity() const
267 {
268     for (auto& database : m_openDatabaseSet) {
269         if (database->hasPendingCreationEvent() || database->hasPendingTransaction())
270             return true;
271     }
272     return false;
273 }
274
275 } // namespace WebCore