Use WTF::Function instead of std::function in NetworkProcess code
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / cache / NetworkCacheIOChannelCocoa.mm
1 /*
2  * Copyright (C) 2014-2015 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkCacheIOChannel.h"
28
29 #if ENABLE(NETWORK_CACHE)
30
31 #include "NetworkCacheFileSystem.h"
32 #include <dispatch/dispatch.h>
33 #include <mach/vm_param.h>
34 #include <sys/mman.h>
35 #include <sys/stat.h>
36 #include <wtf/BlockPtr.h>
37 #include <wtf/text/CString.h>
38
39 namespace WebKit {
40 namespace NetworkCache {
41
42 IOChannel::IOChannel(const String& filePath, Type type)
43     : m_path(filePath)
44     , m_type(type)
45 {
46     auto path = WebCore::fileSystemRepresentation(filePath);
47     int oflag;
48     mode_t mode;
49     bool useLowIOPriority = false;
50
51     switch (m_type) {
52     case Type::Create:
53         // We don't want to truncate any existing file (with O_TRUNC) as another thread might be mapping it.
54         unlink(path.data());
55         oflag = O_RDWR | O_CREAT | O_NONBLOCK;
56         mode = S_IRUSR | S_IWUSR;
57         useLowIOPriority = true;
58         break;
59     case Type::Write:
60         oflag = O_WRONLY | O_NONBLOCK;
61         mode = S_IRUSR | S_IWUSR;
62         useLowIOPriority = true;
63         break;
64     case Type::Read:
65         oflag = O_RDONLY | O_NONBLOCK;
66         mode = 0;
67     }
68
69     int fd = ::open(path.data(), oflag, mode);
70     m_fileDescriptor = fd;
71
72     m_dispatchIO = adoptDispatch(dispatch_io_create(DISPATCH_IO_RANDOM, fd, dispatch_get_global_queue(useLowIOPriority ? DISPATCH_QUEUE_PRIORITY_BACKGROUND : DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [fd](int) {
73         close(fd);
74     }));
75     ASSERT(m_dispatchIO.get());
76
77     // This makes the channel read/write all data before invoking the handlers.
78     dispatch_io_set_low_water(m_dispatchIO.get(), std::numeric_limits<size_t>::max());
79
80     if (useLowIOPriority) {
81         // The target queue of a dispatch I/O channel specifies the priority of the global queue where its I/O operations are executed.
82         dispatch_set_target_queue(m_dispatchIO.get(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
83     }
84 }
85
86 IOChannel::~IOChannel()
87 {
88     RELEASE_ASSERT(!m_wasDeleted.exchange(true));
89 }
90
91 Ref<IOChannel> IOChannel::open(const String& filePath, IOChannel::Type type)
92 {
93     return adoptRef(*new IOChannel(filePath, type));
94 }
95
96 void IOChannel::read(size_t offset, size_t size, WorkQueue* queue, Function<void (Data&, int error)>&& completionHandler)
97 {
98     RefPtr<IOChannel> channel(this);
99     bool didCallCompletionHandler = false;
100     auto dispatchQueue = queue ? queue->dispatchQueue() : dispatch_get_main_queue();
101     dispatch_io_read(m_dispatchIO.get(), offset, size, dispatchQueue, BlockPtr<void(bool, dispatch_data_t, int)>::fromCallable([channel, completionHandler = WTFMove(completionHandler), didCallCompletionHandler](bool done, dispatch_data_t fileData, int error) mutable {
102         ASSERT_UNUSED(done, done || !didCallCompletionHandler);
103         if (didCallCompletionHandler)
104             return;
105         DispatchPtr<dispatch_data_t> fileDataPtr(fileData);
106         Data data(fileDataPtr);
107         completionHandler(data, error);
108         didCallCompletionHandler = true;
109     }).get());
110 }
111
112 void IOChannel::write(size_t offset, const Data& data, WorkQueue* queue, Function<void (int error)>&& completionHandler)
113 {
114     RefPtr<IOChannel> channel(this);
115     auto dispatchData = data.dispatchData();
116     auto dispatchQueue = queue ? queue->dispatchQueue() : dispatch_get_main_queue();
117     dispatch_io_write(m_dispatchIO.get(), offset, dispatchData, dispatchQueue, BlockPtr<void(bool, dispatch_data_t, int)>::fromCallable([channel, completionHandler = WTFMove(completionHandler)](bool done, dispatch_data_t fileData, int error) {
118         ASSERT_UNUSED(done, done);
119         completionHandler(error);
120     }).get());
121 }
122
123 }
124 }
125
126 #endif