Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebCore / fileapi / AsyncFileStream.cpp
1 /*
2  * Copyright (C) 2010 Google Inc.  All rights reserved.
3  * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "AsyncFileStream.h"
34
35 #include "FileStream.h"
36 #include "FileStreamClient.h"
37 #include <mutex>
38 #include <wtf/AutodrainedPool.h>
39 #include <wtf/Function.h>
40 #include <wtf/MainThread.h>
41 #include <wtf/MessageQueue.h>
42 #include <wtf/NeverDestroyed.h>
43 #include <wtf/Threading.h>
44 #include <wtf/URL.h>
45
46 namespace WebCore {
47
48 struct AsyncFileStream::Internals {
49     explicit Internals(FileStreamClient&);
50
51     FileStream stream;
52     FileStreamClient& client;
53 #if !COMPILER(MSVC)
54     std::atomic_bool destroyed { false };
55 #else
56     std::atomic_bool destroyed;
57 #endif
58 };
59
60 inline AsyncFileStream::Internals::Internals(FileStreamClient& client)
61     : client(client)
62 {
63 #if COMPILER(MSVC)
64     // Work around a bug that prevents the default value above from compiling.
65     atomic_init(&destroyed, false);
66 #endif
67 }
68
69 static void callOnFileThread(Function<void ()>&& function)
70 {
71     ASSERT(isMainThread());
72     ASSERT(function);
73
74     static NeverDestroyed<MessageQueue<Function<void ()>>> queue;
75
76     static std::once_flag createFileThreadOnce;
77     std::call_once(createFileThreadOnce, [] {
78         Thread::create("WebCore: AsyncFileStream", [] {
79             for (;;) {
80                 AutodrainedPool pool;
81
82                 auto function = queue.get().waitForMessage();
83
84                 // This can never be null because we never kill the MessageQueue.
85                 ASSERT(function);
86
87                 // This can bever be null because we never queue a function that is null.
88                 ASSERT(*function);
89
90                 (*function)();
91             }
92         });
93     });
94
95     queue.get().append(std::make_unique<Function<void ()>>(WTFMove(function)));
96 }
97
98 AsyncFileStream::AsyncFileStream(FileStreamClient& client)
99     : m_internals(std::make_unique<Internals>(client))
100 {
101     ASSERT(isMainThread());
102 }
103
104 AsyncFileStream::~AsyncFileStream()
105 {
106     ASSERT(isMainThread());
107
108     // Set flag to prevent client callbacks and also prevent queued operations from starting.
109     m_internals->destroyed = true;
110
111     // Call through file thread and back to main thread to make sure deletion happens
112     // after all file thread functions and all main thread functions called from them.
113     callOnFileThread([internals = WTFMove(m_internals)]() mutable {
114         callOnMainThread([internals = WTFMove(internals)] {
115         });
116     });
117 }
118
119 void AsyncFileStream::perform(WTF::Function<WTF::Function<void(FileStreamClient&)>(FileStream&)>&& operation)
120 {
121     auto& internals = *m_internals;
122     callOnFileThread([&internals, operation = WTFMove(operation)] {
123         // Don't do the operation if stop was already called on the main thread. Note that there is
124         // a race here, but since skipping the operation is an optimization it's OK that we can't
125         // guarantee exactly which operations are skipped. Note that this is also the only reason
126         // we use an atomic_bool rather than just a bool for destroyed.
127         if (internals.destroyed)
128             return;
129         callOnMainThread([&internals, mainThreadWork = operation(internals.stream)] {
130             if (internals.destroyed)
131                 return;
132             mainThreadWork(internals.client);
133         });
134     });
135 }
136
137 void AsyncFileStream::getSize(const String& path, double expectedModificationTime)
138 {
139     // FIXME: Explicit return type here and in all the other cases like this below is a workaround for a deficiency
140     // in the Windows compiler at the time of this writing. Could remove it if that is resolved.
141     perform([path = path.isolatedCopy(), expectedModificationTime](FileStream& stream) -> WTF::Function<void(FileStreamClient&)> {
142         long long size = stream.getSize(path, expectedModificationTime);
143         return [size](FileStreamClient& client) {
144             client.didGetSize(size);
145         };
146     });
147 }
148
149 void AsyncFileStream::openForRead(const String& path, long long offset, long long length)
150 {
151     // FIXME: Explicit return type here is a workaround for a deficiency in the Windows compiler at the time of this writing.
152     perform([path = path.isolatedCopy(), offset, length](FileStream& stream) -> WTF::Function<void(FileStreamClient&)> {
153         bool success = stream.openForRead(path, offset, length);
154         return [success](FileStreamClient& client) {
155             client.didOpen(success);
156         };
157     });
158 }
159
160 void AsyncFileStream::close()
161 {
162     auto& internals = *m_internals;
163     callOnFileThread([&internals] {
164         internals.stream.close();
165     });
166 }
167
168 void AsyncFileStream::read(char* buffer, int length)
169 {
170     perform([buffer, length](FileStream& stream) -> WTF::Function<void(FileStreamClient&)> {
171         int bytesRead = stream.read(buffer, length);
172         return [bytesRead](FileStreamClient& client) {
173             client.didRead(bytesRead);
174         };
175     });
176 }
177
178 } // namespace WebCore