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#if USE(UNIX_DOMAIN_SOCKETS) 30#include "SharedMemory.h" 31 32#include "ArgumentDecoder.h" 33#include "ArgumentEncoder.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#include <wtf/RandomNumber.h> 44#include <wtf/text/CString.h> 45 46namespace WebKit { 47 48SharedMemory::Handle::Handle() 49 : m_fileDescriptor(-1) 50 , m_size(0) 51{ 52} 53 54SharedMemory::Handle::~Handle() 55{ 56 if (!isNull()) 57 while (close(m_fileDescriptor) == -1 && errno == EINTR) { } 58} 59 60bool SharedMemory::Handle::isNull() const 61{ 62 return m_fileDescriptor == -1; 63} 64 65void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder& encoder) const 66{ 67 encoder << releaseToAttachment(); 68} 69 70bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder& decoder, Handle& handle) 71{ 72 ASSERT_ARG(handle, !handle.m_size); 73 ASSERT_ARG(handle, handle.isNull()); 74 75 CoreIPC::Attachment attachment; 76 if (!decoder.decode(attachment)) 77 return false; 78 79 handle.adoptFromAttachment(attachment.releaseFileDescriptor(), attachment.size()); 80 return true; 81} 82 83CoreIPC::Attachment SharedMemory::Handle::releaseToAttachment() const 84{ 85 int temp = m_fileDescriptor; 86 m_fileDescriptor = -1; 87 return CoreIPC::Attachment(temp, m_size); 88} 89 90void SharedMemory::Handle::adoptFromAttachment(int fileDescriptor, size_t size) 91{ 92 ASSERT(!m_size); 93 ASSERT(isNull()); 94 95 m_fileDescriptor = fileDescriptor; 96 m_size = size; 97} 98 99PassRefPtr<SharedMemory> SharedMemory::create(size_t size) 100{ 101 CString tempName; 102 103 int fileDescriptor = -1; 104 for (int tries = 0; fileDescriptor == -1 && tries < 10; ++tries) { 105 String name = String("/WK2SharedMemory.") + String::number(static_cast<unsigned>(WTF::randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))); 106 tempName = name.utf8(); 107 108 do { 109 fileDescriptor = shm_open(tempName.data(), O_CREAT | O_CLOEXEC | O_RDWR, S_IRUSR | S_IWUSR); 110 } while (fileDescriptor == -1 && errno == EINTR); 111 } 112 if (fileDescriptor == -1) { 113 WTFLogAlways("Failed to create shared memory file %s", tempName.data()); 114 return 0; 115 } 116 117 while (ftruncate(fileDescriptor, size) == -1) { 118 if (errno != EINTR) { 119 while (close(fileDescriptor) == -1 && errno == EINTR) { } 120 shm_unlink(tempName.data()); 121 return 0; 122 } 123 } 124 125 void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0); 126 if (data == MAP_FAILED) { 127 while (close(fileDescriptor) == -1 && errno == EINTR) { } 128 shm_unlink(tempName.data()); 129 return 0; 130 } 131 132 shm_unlink(tempName.data()); 133 134 RefPtr<SharedMemory> instance = adoptRef(new SharedMemory()); 135 instance->m_data = data; 136 instance->m_fileDescriptor = fileDescriptor; 137 instance->m_size = size; 138 return instance.release(); 139} 140 141static inline int accessModeMMap(SharedMemory::Protection protection) 142{ 143 switch (protection) { 144 case SharedMemory::ReadOnly: 145 return PROT_READ; 146 case SharedMemory::ReadWrite: 147 return PROT_READ | PROT_WRITE; 148 } 149 150 ASSERT_NOT_REACHED(); 151 return PROT_READ | PROT_WRITE; 152} 153 154PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) 155{ 156 ASSERT(!handle.isNull()); 157 158 void* data = mmap(0, handle.m_size, accessModeMMap(protection), MAP_SHARED, handle.m_fileDescriptor, 0); 159 if (data == MAP_FAILED) 160 return 0; 161 162 RefPtr<SharedMemory> instance = adoptRef(new SharedMemory()); 163 instance->m_data = data; 164 instance->m_fileDescriptor = handle.m_fileDescriptor; 165 instance->m_size = handle.m_size; 166 handle.m_fileDescriptor = -1; 167 return instance; 168} 169 170SharedMemory::~SharedMemory() 171{ 172 munmap(m_data, m_size); 173 while (close(m_fileDescriptor) == -1 && errno == EINTR) { } 174} 175 176static inline int accessModeFile(SharedMemory::Protection protection) 177{ 178 switch (protection) { 179 case SharedMemory::ReadOnly: 180 return O_RDONLY; 181 case SharedMemory::ReadWrite: 182 return O_RDWR; 183 } 184 185 ASSERT_NOT_REACHED(); 186 return O_RDWR; 187} 188 189bool SharedMemory::createHandle(Handle& handle, Protection protection) 190{ 191 ASSERT_ARG(handle, !handle.m_size); 192 ASSERT_ARG(handle, handle.isNull()); 193 194 int duplicatedHandle; 195 while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) { 196 if (errno != EINTR) { 197 ASSERT_NOT_REACHED(); 198 return false; 199 } 200 } 201 202 while ((fcntl(duplicatedHandle, F_SETFD, FD_CLOEXEC | accessModeFile(protection)) == -1)) { 203 if (errno != EINTR) { 204 ASSERT_NOT_REACHED(); 205 while (close(duplicatedHandle) == -1 && errno == EINTR) { } 206 return false; 207 } 208 } 209 handle.m_fileDescriptor = duplicatedHandle; 210 handle.m_size = m_size; 211 return true; 212} 213 214unsigned SharedMemory::systemPageSize() 215{ 216 static unsigned pageSize = 0; 217 218 if (!pageSize) 219 pageSize = getpagesize(); 220 221 return pageSize; 222} 223 224} // namespace WebKit 225 226#endif 227 228