1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (c) 2010 University of Szeged 4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 25 * THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "config.h" 29 #include "SharedMemory.h" 30 31 #include "ArgumentDecoder.h" 32 #include "ArgumentEncoder.h" 33 #include "WebCoreArgumentCoders.h" 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <stdlib.h> 37 #include <sys/mman.h> 38 #include <sys/stat.h> 39 #include <sys/types.h> 40 #include <unistd.h> 41 #include <wtf/Assertions.h> 42 #include <wtf/CurrentTime.h> 43 44 #if PLATFORM(QT) 45 #include <QDir> 46 #elif PLATFORM(GTK) 47 #include <wtf/gobject/GOwnPtr.h> 48 #endif 49 50 namespace WebKit { 51 52 SharedMemory::Handle::Handle() 53 : m_fileDescriptor(-1) 54 , m_size(0) 55 { 56 } 57 58 SharedMemory::Handle::~Handle() 59 { 60 if (!isNull()) 61 while (close(m_fileDescriptor) == -1 && errno == EINTR) { } 62 } 63 64 bool SharedMemory::Handle::isNull() const 65 { 66 return m_fileDescriptor == -1; 67 } 68 69 void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const 70 { 71 ASSERT(!isNull()); 72 73 encoder->encode(releaseToAttachment()); 74 } 75 76 bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) 77 { 78 ASSERT_ARG(handle, !handle.m_size); 79 ASSERT_ARG(handle, handle.isNull()); 80 81 CoreIPC::Attachment attachment; 82 if (!decoder->decode(attachment)) 83 return false; 84 85 handle.adoptFromAttachment(attachment.releaseFileDescriptor(), attachment.size()); 86 return true; 87 } 88 89 CoreIPC::Attachment SharedMemory::Handle::releaseToAttachment() const 90 { 91 ASSERT(!isNull()); 92 93 int temp = m_fileDescriptor; 94 m_fileDescriptor = -1; 95 return CoreIPC::Attachment(temp, m_size); 96 } 97 98 void SharedMemory::Handle::adoptFromAttachment(int fileDescriptor, size_t size) 99 { 100 ASSERT(!m_size); 101 ASSERT(isNull()); 102 103 m_fileDescriptor = fileDescriptor; 104 m_size = size; 105 } 106 107 PassRefPtr<SharedMemory> SharedMemory::create(size_t size) 108 { 109 #if PLATFORM(QT) 110 QString tempName = QDir::temp().filePath(QLatin1String("qwkshm.XXXXXX")); 111 QByteArray tempNameCSTR = tempName.toLocal8Bit(); 112 char* tempNameC = tempNameCSTR.data(); 113 #elif PLATFORM(GTK) 114 GOwnPtr<gchar> tempName(g_build_filename(g_get_tmp_dir(), "WK2SharedMemoryXXXXXX", NULL)); 115 gchar* tempNameC = tempName.get(); 116 #endif 117 118 int fileDescriptor; 119 while ((fileDescriptor = mkstemp(tempNameC)) == -1) { 120 if (errno != EINTR) 121 return 0; 122 } 123 while (fcntl(fileDescriptor, F_SETFD, FD_CLOEXEC) == -1) { 124 if (errno != EINTR) { 125 while (close(fileDescriptor) == -1 && errno == EINTR) { } 126 unlink(tempNameC); 127 return 0; 128 } 129 } 130 131 while (ftruncate(fileDescriptor, size) == -1) { 132 if (errno != EINTR) { 133 while (close(fileDescriptor) == -1 && errno == EINTR) { } 134 unlink(tempNameC); 135 return 0; 136 } 137 } 138 139 void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0); 140 if (data == MAP_FAILED) { 141 while (close(fileDescriptor) == -1 && errno == EINTR) { } 142 unlink(tempNameC); 143 return 0; 144 } 145 146 unlink(tempNameC); 147 148 RefPtr<SharedMemory> instance = adoptRef(new SharedMemory()); 149 instance->m_data = data; 150 instance->m_fileDescriptor = fileDescriptor; 151 instance->m_size = size; 152 return instance.release(); 153 } 154 155 static inline int accessModeMMap(SharedMemory::Protection protection) 156 { 157 switch (protection) { 158 case SharedMemory::ReadOnly: 159 return PROT_READ; 160 case SharedMemory::ReadWrite: 161 return PROT_READ | PROT_WRITE; 162 } 163 164 ASSERT_NOT_REACHED(); 165 return PROT_READ | PROT_WRITE; 166 } 167 168 PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) 169 { 170 ASSERT(!handle.isNull()); 171 172 void* data = mmap(0, handle.m_size, accessModeMMap(protection), MAP_SHARED, handle.m_fileDescriptor, 0); 173 if (data == MAP_FAILED) 174 return 0; 175 176 RefPtr<SharedMemory> instance = adoptRef(new SharedMemory()); 177 instance->m_data = data; 178 instance->m_fileDescriptor = handle.m_fileDescriptor; 179 instance->m_size = handle.m_size; 180 handle.m_fileDescriptor = -1; 181 return instance; 182 } 183 184 SharedMemory::~SharedMemory() 185 { 186 munmap(m_data, m_size); 187 while (close(m_fileDescriptor) == -1 && errno == EINTR) { } 188 } 189 190 static inline int accessModeFile(SharedMemory::Protection protection) 191 { 192 switch (protection) { 193 case SharedMemory::ReadOnly: 194 return O_RDONLY; 195 case SharedMemory::ReadWrite: 196 return O_RDWR; 197 } 198 199 ASSERT_NOT_REACHED(); 200 return O_RDWR; 201 } 202 203 bool SharedMemory::createHandle(Handle& handle, Protection protection) 204 { 205 ASSERT_ARG(handle, !handle.m_size); 206 ASSERT_ARG(handle, handle.isNull()); 207 208 int duplicatedHandle; 209 while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) { 210 if (errno != EINTR) { 211 ASSERT_NOT_REACHED(); 212 return false; 213 } 214 } 215 216 while ((fcntl(duplicatedHandle, F_SETFD, FD_CLOEXEC | accessModeFile(protection)) == -1)) { 217 if (errno != EINTR) { 218 ASSERT_NOT_REACHED(); 219 while (close(duplicatedHandle) == -1 && errno == EINTR) { } 220 return false; 221 } 222 } 223 handle.m_fileDescriptor = duplicatedHandle; 224 handle.m_size = m_size; 225 return true; 226 } 227 228 unsigned SharedMemory::systemPageSize() 229 { 230 static unsigned pageSize = 0; 231 232 if (!pageSize) 233 pageSize = getpagesize(); 234 235 return pageSize; 236 } 237 238 } // namespace WebKit 239