1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/shared_memory_posix.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,344 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/shared_memory.h" 1.9 + 1.10 +#include <errno.h> 1.11 +#include <fcntl.h> 1.12 +#include <sys/mman.h> 1.13 +#include <sys/stat.h> 1.14 +#include <unistd.h> 1.15 + 1.16 +#include "base/file_util.h" 1.17 +#include "base/logging.h" 1.18 +#include "base/platform_thread.h" 1.19 +#include "base/string_util.h" 1.20 + 1.21 +namespace base { 1.22 + 1.23 +SharedMemory::SharedMemory() 1.24 + : mapped_file_(-1), 1.25 + inode_(0), 1.26 + memory_(NULL), 1.27 + read_only_(false), 1.28 + max_size_(0) { 1.29 +} 1.30 + 1.31 +SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) 1.32 + : mapped_file_(handle.fd), 1.33 + inode_(0), 1.34 + memory_(NULL), 1.35 + read_only_(read_only), 1.36 + max_size_(0) { 1.37 + struct stat st; 1.38 + if (fstat(handle.fd, &st) == 0) { 1.39 + // If fstat fails, then the file descriptor is invalid and we'll learn this 1.40 + // fact when Map() fails. 1.41 + inode_ = st.st_ino; 1.42 + } 1.43 +} 1.44 + 1.45 +SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, 1.46 + ProcessHandle process) 1.47 + : mapped_file_(handle.fd), 1.48 + memory_(NULL), 1.49 + read_only_(read_only), 1.50 + max_size_(0) { 1.51 + // We don't handle this case yet (note the ignored parameter); let's die if 1.52 + // someone comes calling. 1.53 + NOTREACHED(); 1.54 +} 1.55 + 1.56 +SharedMemory::~SharedMemory() { 1.57 + Close(); 1.58 +} 1.59 + 1.60 +// static 1.61 +bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 1.62 + return handle.fd >= 0; 1.63 +} 1.64 + 1.65 +// static 1.66 +SharedMemoryHandle SharedMemory::NULLHandle() { 1.67 + return SharedMemoryHandle(); 1.68 +} 1.69 + 1.70 +bool SharedMemory::Create(const std::string &cname, bool read_only, 1.71 + bool open_existing, size_t size) { 1.72 + read_only_ = read_only; 1.73 + 1.74 + std::wstring name = UTF8ToWide(cname); 1.75 + 1.76 + int posix_flags = 0; 1.77 + posix_flags |= read_only ? O_RDONLY : O_RDWR; 1.78 + if (!open_existing || mapped_file_ <= 0) 1.79 + posix_flags |= O_CREAT; 1.80 + 1.81 + if (!CreateOrOpen(name, posix_flags, size)) 1.82 + return false; 1.83 + 1.84 + max_size_ = size; 1.85 + return true; 1.86 +} 1.87 + 1.88 +// Our current implementation of shmem is with mmap()ing of files. 1.89 +// These files need to be deleted explicitly. 1.90 +// In practice this call is only needed for unit tests. 1.91 +bool SharedMemory::Delete(const std::wstring& name) { 1.92 + std::wstring mem_filename; 1.93 + if (FilenameForMemoryName(name, &mem_filename) == false) 1.94 + return false; 1.95 + 1.96 + FilePath path(WideToUTF8(mem_filename)); 1.97 + if (file_util::PathExists(path)) { 1.98 + return file_util::Delete(path, false); 1.99 + } 1.100 + 1.101 + // Doesn't exist, so success. 1.102 + return true; 1.103 +} 1.104 + 1.105 +bool SharedMemory::Open(const std::wstring &name, bool read_only) { 1.106 + read_only_ = read_only; 1.107 + 1.108 + int posix_flags = 0; 1.109 + posix_flags |= read_only ? O_RDONLY : O_RDWR; 1.110 + 1.111 + return CreateOrOpen(name, posix_flags, 0); 1.112 +} 1.113 + 1.114 +// For the given shmem named |memname|, return a filename to mmap() 1.115 +// (and possibly create). Modifies |filename|. Return false on 1.116 +// error, or true of we are happy. 1.117 +bool SharedMemory::FilenameForMemoryName(const std::wstring &memname, 1.118 + std::wstring *filename) { 1.119 + std::wstring mem_filename; 1.120 + 1.121 + // mem_name will be used for a filename; make sure it doesn't 1.122 + // contain anything which will confuse us. 1.123 + DCHECK(memname.find_first_of(L"/") == std::string::npos); 1.124 + DCHECK(memname.find_first_of(L"\0") == std::string::npos); 1.125 + 1.126 + FilePath temp_dir; 1.127 + if (file_util::GetShmemTempDir(&temp_dir) == false) 1.128 + return false; 1.129 + 1.130 + mem_filename = UTF8ToWide(temp_dir.value()); 1.131 + file_util::AppendToPath(&mem_filename, L"com.google.chrome.shmem." + memname); 1.132 + *filename = mem_filename; 1.133 + return true; 1.134 +} 1.135 + 1.136 +namespace { 1.137 + 1.138 +// A class to handle auto-closing of FILE*'s. 1.139 +class ScopedFILEClose { 1.140 + public: 1.141 + inline void operator()(FILE* x) const { 1.142 + if (x) { 1.143 + fclose(x); 1.144 + } 1.145 + } 1.146 +}; 1.147 + 1.148 +typedef scoped_ptr_malloc<FILE, ScopedFILEClose> ScopedFILE; 1.149 + 1.150 +} 1.151 + 1.152 +// Chromium mostly only use the unique/private shmem as specified by 1.153 +// "name == L"". The exception is in the StatsTable. 1.154 +// TODO(jrg): there is no way to "clean up" all unused named shmem if 1.155 +// we restart from a crash. (That isn't a new problem, but it is a problem.) 1.156 +// In case we want to delete it later, it may be useful to save the value 1.157 +// of mem_filename after FilenameForMemoryName(). 1.158 +bool SharedMemory::CreateOrOpen(const std::wstring &name, 1.159 + int posix_flags, size_t size) { 1.160 + DCHECK(mapped_file_ == -1); 1.161 + 1.162 + ScopedFILE file_closer; 1.163 + FILE *fp; 1.164 + 1.165 + if (name == L"") { 1.166 + // It doesn't make sense to have a read-only private piece of shmem 1.167 + DCHECK(posix_flags & (O_RDWR | O_WRONLY)); 1.168 + 1.169 + FilePath path; 1.170 + fp = file_util::CreateAndOpenTemporaryShmemFile(&path); 1.171 + 1.172 + // Deleting the file prevents anyone else from mapping it in 1.173 + // (making it private), and prevents the need for cleanup (once 1.174 + // the last fd is closed, it is truly freed). 1.175 + file_util::Delete(path, false); 1.176 + } else { 1.177 + std::wstring mem_filename; 1.178 + if (FilenameForMemoryName(name, &mem_filename) == false) 1.179 + return false; 1.180 + 1.181 + std::string mode; 1.182 + switch (posix_flags) { 1.183 + case (O_RDWR | O_CREAT): 1.184 + // Careful: "w+" will truncate if it already exists. 1.185 + mode = "a+"; 1.186 + break; 1.187 + case O_RDWR: 1.188 + mode = "r+"; 1.189 + break; 1.190 + case O_RDONLY: 1.191 + mode = "r"; 1.192 + break; 1.193 + default: 1.194 + NOTIMPLEMENTED(); 1.195 + break; 1.196 + } 1.197 + 1.198 + fp = file_util::OpenFile(mem_filename, mode.c_str()); 1.199 + } 1.200 + 1.201 + if (fp == NULL) 1.202 + return false; 1.203 + file_closer.reset(fp); // close when we go out of scope 1.204 + 1.205 + // Make sure the (new) file is the right size. 1.206 + // According to the man page, "Use of truncate() to extend a file is 1.207 + // not portable." 1.208 + if (size && (posix_flags & (O_RDWR | O_CREAT))) { 1.209 + // Get current size. 1.210 + struct stat stat; 1.211 + if (fstat(fileno(fp), &stat) != 0) 1.212 + return false; 1.213 + size_t current_size = stat.st_size; 1.214 + if (current_size != size) { 1.215 + if (ftruncate(fileno(fp), size) != 0) 1.216 + return false; 1.217 + if (fseeko(fp, size, SEEK_SET) != 0) 1.218 + return false; 1.219 + } 1.220 + } 1.221 + 1.222 + mapped_file_ = dup(fileno(fp)); 1.223 + DCHECK(mapped_file_ >= 0); 1.224 + 1.225 + struct stat st; 1.226 + if (fstat(mapped_file_, &st)) 1.227 + NOTREACHED(); 1.228 + inode_ = st.st_ino; 1.229 + 1.230 + return true; 1.231 +} 1.232 + 1.233 +bool SharedMemory::Map(size_t bytes) { 1.234 + if (mapped_file_ == -1) 1.235 + return false; 1.236 + 1.237 + memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), 1.238 + MAP_SHARED, mapped_file_, 0); 1.239 + 1.240 + if (memory_) 1.241 + max_size_ = bytes; 1.242 + 1.243 + bool mmap_succeeded = (memory_ != (void*)-1); 1.244 + DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno; 1.245 + return mmap_succeeded; 1.246 +} 1.247 + 1.248 +bool SharedMemory::Unmap() { 1.249 + if (memory_ == NULL) 1.250 + return false; 1.251 + 1.252 + munmap(memory_, max_size_); 1.253 + memory_ = NULL; 1.254 + max_size_ = 0; 1.255 + return true; 1.256 +} 1.257 + 1.258 +bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 1.259 + SharedMemoryHandle *new_handle, 1.260 + bool close_self) { 1.261 + const int new_fd = dup(mapped_file_); 1.262 + DCHECK(new_fd >= -1); 1.263 + new_handle->fd = new_fd; 1.264 + new_handle->auto_close = true; 1.265 + 1.266 + if (close_self) 1.267 + Close(); 1.268 + 1.269 + return true; 1.270 +} 1.271 + 1.272 + 1.273 +void SharedMemory::Close() { 1.274 + Unmap(); 1.275 + 1.276 + if (mapped_file_ > 0) { 1.277 + close(mapped_file_); 1.278 + mapped_file_ = -1; 1.279 + } 1.280 +} 1.281 + 1.282 +#ifdef ANDROID 1.283 +void SharedMemory::LockOrUnlockCommon(int function) { 1.284 + DCHECK(mapped_file_ >= 0); 1.285 + struct flock lockreq; 1.286 + lockreq.l_type = function; 1.287 + lockreq.l_whence = SEEK_SET; 1.288 + lockreq.l_start = 0; 1.289 + lockreq.l_len = 0; 1.290 + while (fcntl(mapped_file_, F_SETLKW, &lockreq) < 0) { 1.291 + if (errno == EINTR) { 1.292 + continue; 1.293 + } else if (errno == ENOLCK) { 1.294 + // temporary kernel resource exaustion 1.295 + PlatformThread::Sleep(500); 1.296 + continue; 1.297 + } else { 1.298 + NOTREACHED() << "lockf() failed." 1.299 + << " function:" << function 1.300 + << " fd:" << mapped_file_ 1.301 + << " errno:" << errno 1.302 + << " msg:" << strerror(errno); 1.303 + } 1.304 + } 1.305 +} 1.306 + 1.307 +void SharedMemory::Lock() { 1.308 + LockOrUnlockCommon(F_WRLCK); 1.309 +} 1.310 + 1.311 +void SharedMemory::Unlock() { 1.312 + LockOrUnlockCommon(F_UNLCK); 1.313 +} 1.314 +#else 1.315 +void SharedMemory::LockOrUnlockCommon(int function) { 1.316 + DCHECK(mapped_file_ >= 0); 1.317 + while (lockf(mapped_file_, function, 0) < 0) { 1.318 + if (errno == EINTR) { 1.319 + continue; 1.320 + } else if (errno == ENOLCK) { 1.321 + // temporary kernel resource exaustion 1.322 + PlatformThread::Sleep(500); 1.323 + continue; 1.324 + } else { 1.325 + NOTREACHED() << "lockf() failed." 1.326 + << " function:" << function 1.327 + << " fd:" << mapped_file_ 1.328 + << " errno:" << errno 1.329 + << " msg:" << strerror(errno); 1.330 + } 1.331 + } 1.332 +} 1.333 + 1.334 +void SharedMemory::Lock() { 1.335 + LockOrUnlockCommon(F_LOCK); 1.336 +} 1.337 + 1.338 +void SharedMemory::Unlock() { 1.339 + LockOrUnlockCommon(F_ULOCK); 1.340 +} 1.341 +#endif 1.342 + 1.343 +SharedMemoryHandle SharedMemory::handle() const { 1.344 + return FileDescriptor(mapped_file_, false); 1.345 +} 1.346 + 1.347 +} // namespace base