| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/memory/shared_memory.h" | 5 #include "base/memory/shared_memory.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "build/build_config.h" | 26 #include "build/build_config.h" |
| 27 | 27 |
| 28 #if defined(OS_ANDROID) | 28 #if defined(OS_ANDROID) |
| 29 #include "base/os_compat_android.h" | 29 #include "base/os_compat_android.h" |
| 30 #include "third_party/ashmem/ashmem.h" | 30 #include "third_party/ashmem/ashmem.h" |
| 31 #endif | 31 #endif |
| 32 | 32 |
| 33 namespace base { | 33 namespace base { |
| 34 | 34 |
| 35 SharedMemory::SharedMemory() | 35 SharedMemory::SharedMemory() |
| 36 : readonly_mapped_file_(-1), | 36 : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {} |
| 37 mapped_size_(0), | |
| 38 memory_(NULL), | |
| 39 read_only_(false), | |
| 40 requested_size_(0) {} | |
| 41 | 37 |
| 42 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) | 38 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) |
| 43 : shm_(handle), | 39 : shm_(handle), |
| 44 readonly_mapped_file_(-1), | 40 |
| 45 mapped_size_(0), | 41 mapped_size_(0), |
| 46 memory_(NULL), | 42 memory_(NULL), |
| 47 read_only_(read_only), | 43 read_only_(read_only), |
| 48 requested_size_(0) {} | 44 requested_size_(0) {} |
| 49 | 45 |
| 50 SharedMemory::~SharedMemory() { | 46 SharedMemory::~SharedMemory() { |
| 51 Unmap(); | 47 Unmap(); |
| 52 Close(); | 48 Close(); |
| 53 } | 49 } |
| 54 | 50 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 "Invalid owner when opening existing shared memory file."; | 162 "Invalid owner when opening existing shared memory file."; |
| 167 close(fd); | 163 close(fd); |
| 168 return false; | 164 return false; |
| 169 } | 165 } |
| 170 | 166 |
| 171 // An existing file was opened, so its size should not be fixed. | 167 // An existing file was opened, so its size should not be fixed. |
| 172 fix_size = false; | 168 fix_size = false; |
| 173 } | 169 } |
| 174 | 170 |
| 175 if (options.share_read_only) { | 171 if (options.share_read_only) { |
| 176 // Also open as readonly so that we can ShareReadOnlyToProcess. | 172 // Also open as readonly so that we can GetReadOnlyHandle. |
| 177 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 173 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
| 178 if (!readonly_fd.is_valid()) { | 174 if (!readonly_fd.is_valid()) { |
| 179 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 175 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
| 180 close(fd); | 176 close(fd); |
| 181 fd = -1; | 177 fd = -1; |
| 182 return false; | 178 return false; |
| 183 } | 179 } |
| 184 } | 180 } |
| 185 if (fd >= 0) { | 181 if (fd >= 0) { |
| 186 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. | 182 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 206 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); | 202 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); |
| 207 if (dir.value() == "/dev/shm") { | 203 if (dir.value() == "/dev/shm") { |
| 208 LOG(FATAL) << "This is frequently caused by incorrect permissions on " | 204 LOG(FATAL) << "This is frequently caused by incorrect permissions on " |
| 209 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; | 205 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; |
| 210 } | 206 } |
| 211 } | 207 } |
| 212 return false; | 208 return false; |
| 213 } | 209 } |
| 214 | 210 |
| 215 int mapped_file = -1; | 211 int mapped_file = -1; |
| 212 int readonly_mapped_file = -1; |
| 216 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), | 213 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), |
| 217 &mapped_file, &readonly_mapped_file_); | 214 &mapped_file, &readonly_mapped_file); |
| 218 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); | 215 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); |
| 216 readonly_shm_ = SharedMemoryHandle::ImportHandle(readonly_mapped_file); |
| 219 return result; | 217 return result; |
| 220 } | 218 } |
| 221 | 219 |
| 222 // Our current implementation of shmem is with mmap()ing of files. | 220 // Our current implementation of shmem is with mmap()ing of files. |
| 223 // These files need to be deleted explicitly. | 221 // These files need to be deleted explicitly. |
| 224 // In practice this call is only needed for unit tests. | 222 // In practice this call is only needed for unit tests. |
| 225 bool SharedMemory::Delete(const std::string& name) { | 223 bool SharedMemory::Delete(const std::string& name) { |
| 226 FilePath path; | 224 FilePath path; |
| 227 if (!FilePathForMemoryName(name, &path)) | 225 if (!FilePathForMemoryName(name, &path)) |
| 228 return false; | 226 return false; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 242 read_only_ = read_only; | 240 read_only_ = read_only; |
| 243 | 241 |
| 244 const char *mode = read_only ? "r" : "r+"; | 242 const char *mode = read_only ? "r" : "r+"; |
| 245 ScopedFILE fp(base::OpenFile(path, mode)); | 243 ScopedFILE fp(base::OpenFile(path, mode)); |
| 246 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 244 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
| 247 if (!readonly_fd.is_valid()) { | 245 if (!readonly_fd.is_valid()) { |
| 248 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 246 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
| 249 return false; | 247 return false; |
| 250 } | 248 } |
| 251 int mapped_file = -1; | 249 int mapped_file = -1; |
| 250 int readonly_mapped_file = -1; |
| 252 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), | 251 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), |
| 253 &mapped_file, &readonly_mapped_file_); | 252 &mapped_file, &readonly_mapped_file); |
| 254 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); | 253 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); |
| 254 readonly_shm_ = SharedMemoryHandle::ImportHandle(readonly_mapped_file); |
| 255 return result; | 255 return result; |
| 256 } | 256 } |
| 257 #endif // !defined(OS_ANDROID) | 257 #endif // !defined(OS_ANDROID) |
| 258 | 258 |
| 259 bool SharedMemory::MapAt(off_t offset, size_t bytes) { | 259 bool SharedMemory::MapAt(off_t offset, size_t bytes) { |
| 260 if (!shm_.IsValid()) | 260 if (!shm_.IsValid()) |
| 261 return false; | 261 return false; |
| 262 | 262 |
| 263 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) | 263 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) |
| 264 return false; | 264 return false; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 memory_ = nullptr; | 317 memory_ = nullptr; |
| 318 mapped_size_ = 0; | 318 mapped_size_ = 0; |
| 319 return handle_copy; | 319 return handle_copy; |
| 320 } | 320 } |
| 321 | 321 |
| 322 void SharedMemory::Close() { | 322 void SharedMemory::Close() { |
| 323 if (shm_.IsValid()) { | 323 if (shm_.IsValid()) { |
| 324 shm_.Close(); | 324 shm_.Close(); |
| 325 shm_ = SharedMemoryHandle(); | 325 shm_ = SharedMemoryHandle(); |
| 326 } | 326 } |
| 327 if (readonly_mapped_file_ > 0) { | 327 if (readonly_shm_.IsValid()) { |
| 328 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0) | 328 readonly_shm_.Close(); |
| 329 PLOG(ERROR) << "close"; | 329 readonly_shm_ = SharedMemoryHandle(); |
| 330 readonly_mapped_file_ = -1; | |
| 331 } | 330 } |
| 332 } | 331 } |
| 333 | 332 |
| 334 #if !defined(OS_ANDROID) | 333 #if !defined(OS_ANDROID) |
| 335 // For the given shmem named |mem_name|, return a filename to mmap() | 334 // For the given shmem named |mem_name|, return a filename to mmap() |
| 336 // (and possibly create). Modifies |filename|. Return false on | 335 // (and possibly create). Modifies |filename|. Return false on |
| 337 // error, or true of we are happy. | 336 // error, or true of we are happy. |
| 338 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, | 337 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, |
| 339 FilePath* path) { | 338 FilePath* path) { |
| 340 // mem_name will be used for a filename; make sure it doesn't | 339 // mem_name will be used for a filename; make sure it doesn't |
| 341 // contain anything which will confuse us. | 340 // contain anything which will confuse us. |
| 342 DCHECK_EQ(std::string::npos, mem_name.find('/')); | 341 DCHECK_EQ(std::string::npos, mem_name.find('/')); |
| 343 DCHECK_EQ(std::string::npos, mem_name.find('\0')); | 342 DCHECK_EQ(std::string::npos, mem_name.find('\0')); |
| 344 | 343 |
| 345 FilePath temp_dir; | 344 FilePath temp_dir; |
| 346 if (!GetShmemTempDir(false, &temp_dir)) | 345 if (!GetShmemTempDir(false, &temp_dir)) |
| 347 return false; | 346 return false; |
| 348 | 347 |
| 349 #if defined(GOOGLE_CHROME_BUILD) | 348 #if defined(GOOGLE_CHROME_BUILD) |
| 350 std::string name_base = std::string("com.google.Chrome"); | 349 std::string name_base = std::string("com.google.Chrome"); |
| 351 #else | 350 #else |
| 352 std::string name_base = std::string("org.chromium.Chromium"); | 351 std::string name_base = std::string("org.chromium.Chromium"); |
| 353 #endif | 352 #endif |
| 354 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); | 353 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); |
| 355 return true; | 354 return true; |
| 356 } | 355 } |
| 357 #endif // !defined(OS_ANDROID) | 356 #endif // !defined(OS_ANDROID) |
| 358 | 357 |
| 358 SharedMemoryHandle SharedMemory::GetReadOnlyHandle() { |
| 359 CHECK(readonly_shm_.IsValid()); |
| 360 return readonly_shm_.Duplicate(); |
| 361 } |
| 362 |
| 359 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, | 363 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, |
| 360 SharedMemoryHandle* new_handle, | 364 SharedMemoryHandle* new_handle, |
| 361 bool close_self, | 365 bool close_self) { |
| 362 ShareMode share_mode) { | 366 *new_handle = shm_.Duplicate(); |
| 363 int handle_to_dup = -1; | |
| 364 switch(share_mode) { | |
| 365 case SHARE_CURRENT_MODE: | |
| 366 handle_to_dup = shm_.GetHandle(); | |
| 367 break; | |
| 368 case SHARE_READONLY: | |
| 369 // We could imagine re-opening the file from /dev/fd, but that can't make | |
| 370 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10 | |
| 371 CHECK_GE(readonly_mapped_file_, 0); | |
| 372 handle_to_dup = readonly_mapped_file_; | |
| 373 break; | |
| 374 } | |
| 375 | |
| 376 const int new_fd = HANDLE_EINTR(dup(handle_to_dup)); | |
| 377 if (new_fd < 0) { | |
| 378 if (close_self) { | |
| 379 Unmap(); | |
| 380 Close(); | |
| 381 } | |
| 382 DPLOG(ERROR) << "dup() failed."; | |
| 383 return false; | |
| 384 } | |
| 385 | |
| 386 new_handle->SetHandle(new_fd); | |
| 387 new_handle->SetOwnershipPassesToIPC(true); | |
| 388 | |
| 389 if (close_self) { | 367 if (close_self) { |
| 390 Unmap(); | 368 Unmap(); |
| 391 Close(); | 369 Close(); |
| 392 } | 370 } |
| 393 | 371 return new_handle->IsValid(); |
| 394 return true; | |
| 395 } | 372 } |
| 396 | 373 |
| 397 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { | 374 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { |
| 398 // This function is called just after mmap. fstat is a system call that might | 375 // This function is called just after mmap. fstat is a system call that might |
| 399 // cause I/O. It's safe to call fstat here because mmap for shared memory is | 376 // cause I/O. It's safe to call fstat here because mmap for shared memory is |
| 400 // called in two cases: | 377 // called in two cases: |
| 401 // 1) To handle file-mapped memory | 378 // 1) To handle file-mapped memory |
| 402 // 2) To handle annonymous shared memory | 379 // 2) To handle annonymous shared memory |
| 403 // In 1), I/O is already permitted. In 2), the backend is on page cache and | 380 // In 1), I/O is already permitted. In 2), the backend is on page cache and |
| 404 // fstat doesn't cause I/O access to the disk. See the discussion at | 381 // fstat doesn't cause I/O access to the disk. See the discussion at |
| 405 // crbug.com/604726#c41. | 382 // crbug.com/604726#c41. |
| 406 base::ThreadRestrictions::ScopedAllowIO allow_io; | 383 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 407 struct stat file_stat; | 384 struct stat file_stat; |
| 408 if (HANDLE_EINTR( | 385 if (HANDLE_EINTR( |
| 409 ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0) | 386 ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0) |
| 410 return false; | 387 return false; |
| 411 id->first = file_stat.st_dev; | 388 id->first = file_stat.st_dev; |
| 412 id->second = file_stat.st_ino; | 389 id->second = file_stat.st_ino; |
| 413 return true; | 390 return true; |
| 414 } | 391 } |
| 415 | 392 |
| 416 } // namespace base | 393 } // namespace base |
| OLD | NEW |