| 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> | |
| 8 #include <fcntl.h> | 7 #include <fcntl.h> |
| 9 #include <sys/mman.h> | 8 #include <sys/mman.h> |
| 10 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 11 #include <sys/types.h> | |
| 12 #include <unistd.h> | 10 #include <unistd.h> |
| 13 | 11 |
| 14 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 15 #include "base/files/scoped_file.h" | 13 #include "base/files/scoped_file.h" |
| 16 #include "base/lazy_instance.h" | |
| 17 #include "base/logging.h" | 14 #include "base/logging.h" |
| 18 #include "base/posix/eintr_wrapper.h" | 15 #include "base/posix/eintr_wrapper.h" |
| 19 #include "base/posix/safe_strerror.h" | 16 #include "base/posix/safe_strerror.h" |
| 20 #include "base/process/process_metrics.h" | 17 #include "base/process/process_metrics.h" |
| 21 #include "base/profiler/scoped_tracker.h" | 18 #include "base/profiler/scoped_tracker.h" |
| 22 #include "base/scoped_generic.h" | 19 #include "base/scoped_generic.h" |
| 23 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 24 #include "base/synchronization/lock.h" | |
| 25 #include "base/threading/platform_thread.h" | |
| 26 #include "base/threading/thread_restrictions.h" | |
| 27 | |
| 28 #if defined(OS_MACOSX) | |
| 29 #include "base/mac/foundation_util.h" | |
| 30 #endif // OS_MACOSX | |
| 31 | 21 |
| 32 #if defined(OS_ANDROID) | 22 #if defined(OS_ANDROID) |
| 33 #include "base/os_compat_android.h" | 23 #include "base/os_compat_android.h" |
| 34 #include "third_party/ashmem/ashmem.h" | 24 #include "third_party/ashmem/ashmem.h" |
| 35 #endif | 25 #endif |
| 36 | 26 |
| 37 namespace base { | 27 namespace base { |
| 38 | 28 |
| 39 namespace { | 29 namespace { |
| 40 | 30 |
| 41 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; | |
| 42 | |
| 43 struct ScopedPathUnlinkerTraits { | 31 struct ScopedPathUnlinkerTraits { |
| 44 static FilePath* InvalidValue() { return nullptr; } | 32 static FilePath* InvalidValue() { return nullptr; } |
| 45 | 33 |
| 46 static void Free(FilePath* path) { | 34 static void Free(FilePath* path) { |
| 47 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437 | 35 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437 |
| 48 // is fixed. | 36 // is fixed. |
| 49 tracked_objects::ScopedTracker tracking_profile( | 37 tracked_objects::ScopedTracker tracking_profile( |
| 50 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 38 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 51 "466437 SharedMemory::Create::Unlink")); | 39 "466437 SharedMemory::Create::Unlink")); |
| 52 if (unlink(path->value().c_str())) | 40 if (unlink(path->value().c_str())) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 | 99 |
| 112 SharedMemory::SharedMemory() | 100 SharedMemory::SharedMemory() |
| 113 : mapped_file_(-1), | 101 : mapped_file_(-1), |
| 114 readonly_mapped_file_(-1), | 102 readonly_mapped_file_(-1), |
| 115 mapped_size_(0), | 103 mapped_size_(0), |
| 116 memory_(NULL), | 104 memory_(NULL), |
| 117 read_only_(false), | 105 read_only_(false), |
| 118 requested_size_(0) { | 106 requested_size_(0) { |
| 119 } | 107 } |
| 120 | 108 |
| 121 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) | 109 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) |
| 122 : mapped_file_(handle.fd), | 110 : mapped_file_(handle.fd), |
| 123 readonly_mapped_file_(-1), | 111 readonly_mapped_file_(-1), |
| 124 mapped_size_(0), | 112 mapped_size_(0), |
| 125 memory_(NULL), | 113 memory_(NULL), |
| 126 read_only_(read_only), | 114 read_only_(read_only), |
| 127 requested_size_(0) { | 115 requested_size_(0) {} |
| 128 } | |
| 129 | 116 |
| 130 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, | 117 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, |
| 118 bool read_only, |
| 131 ProcessHandle process) | 119 ProcessHandle process) |
| 132 : mapped_file_(handle.fd), | 120 : mapped_file_(handle.fd), |
| 133 readonly_mapped_file_(-1), | 121 readonly_mapped_file_(-1), |
| 134 mapped_size_(0), | 122 mapped_size_(0), |
| 135 memory_(NULL), | 123 memory_(NULL), |
| 136 read_only_(read_only), | 124 read_only_(read_only), |
| 137 requested_size_(0) { | 125 requested_size_(0) { |
| 138 // We don't handle this case yet (note the ignored parameter); let's die if | 126 // We don't handle this case yet (note the ignored parameter); let's die if |
| 139 // someone comes calling. | 127 // someone comes calling. |
| 140 NOTREACHED(); | 128 NOTREACHED(); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 if (fstat(fileno(fp.get()), &stat) != 0) | 279 if (fstat(fileno(fp.get()), &stat) != 0) |
| 292 return false; | 280 return false; |
| 293 const size_t current_size = stat.st_size; | 281 const size_t current_size = stat.st_size; |
| 294 if (current_size != options.size) { | 282 if (current_size != options.size) { |
| 295 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0) | 283 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0) |
| 296 return false; | 284 return false; |
| 297 } | 285 } |
| 298 requested_size_ = options.size; | 286 requested_size_ = options.size; |
| 299 } | 287 } |
| 300 if (fp == NULL) { | 288 if (fp == NULL) { |
| 301 #if !defined(OS_MACOSX) | |
| 302 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; | 289 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; |
| 303 FilePath dir = path.DirName(); | 290 FilePath dir = path.DirName(); |
| 304 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { | 291 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { |
| 305 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); | 292 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); |
| 306 if (dir.value() == "/dev/shm") { | 293 if (dir.value() == "/dev/shm") { |
| 307 LOG(FATAL) << "This is frequently caused by incorrect permissions on " | 294 LOG(FATAL) << "This is frequently caused by incorrect permissions on " |
| 308 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; | 295 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; |
| 309 } | 296 } |
| 310 } | 297 } |
| 311 #else | |
| 312 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; | |
| 313 #endif | |
| 314 return false; | 298 return false; |
| 315 } | 299 } |
| 316 | 300 |
| 317 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); | 301 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); |
| 318 } | 302 } |
| 319 | 303 |
| 320 // Our current implementation of shmem is with mmap()ing of files. | 304 // Our current implementation of shmem is with mmap()ing of files. |
| 321 // These files need to be deleted explicitly. | 305 // These files need to be deleted explicitly. |
| 322 // In practice this call is only needed for unit tests. | 306 // In practice this call is only needed for unit tests. |
| 323 bool SharedMemory::Delete(const std::string& name) { | 307 bool SharedMemory::Delete(const std::string& name) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 PLOG(ERROR) << "close"; | 391 PLOG(ERROR) << "close"; |
| 408 mapped_file_ = -1; | 392 mapped_file_ = -1; |
| 409 } | 393 } |
| 410 if (readonly_mapped_file_ > 0) { | 394 if (readonly_mapped_file_ > 0) { |
| 411 if (close(readonly_mapped_file_) < 0) | 395 if (close(readonly_mapped_file_) < 0) |
| 412 PLOG(ERROR) << "close"; | 396 PLOG(ERROR) << "close"; |
| 413 readonly_mapped_file_ = -1; | 397 readonly_mapped_file_ = -1; |
| 414 } | 398 } |
| 415 } | 399 } |
| 416 | 400 |
| 417 void SharedMemory::LockDeprecated() { | |
| 418 g_thread_lock_.Get().Acquire(); | |
| 419 LockOrUnlockCommon(F_LOCK); | |
| 420 } | |
| 421 | |
| 422 void SharedMemory::UnlockDeprecated() { | |
| 423 LockOrUnlockCommon(F_ULOCK); | |
| 424 g_thread_lock_.Get().Release(); | |
| 425 } | |
| 426 | |
| 427 #if !defined(OS_ANDROID) | 401 #if !defined(OS_ANDROID) |
| 428 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) { | 402 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) { |
| 429 DCHECK_EQ(-1, mapped_file_); | 403 DCHECK_EQ(-1, mapped_file_); |
| 430 DCHECK_EQ(-1, readonly_mapped_file_); | 404 DCHECK_EQ(-1, readonly_mapped_file_); |
| 431 if (fp == NULL) | 405 if (fp == NULL) |
| 432 return false; | 406 return false; |
| 433 | 407 |
| 434 // This function theoretically can block on the disk, but realistically | 408 // This function theoretically can block on the disk, but realistically |
| 435 // the temporary files we create will just go into the buffer cache | 409 // the temporary files we create will just go into the buffer cache |
| 436 // and be deleted before they ever make it out to disk. | 410 // and be deleted before they ever make it out to disk. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 FilePath* path) { | 444 FilePath* path) { |
| 471 // mem_name will be used for a filename; make sure it doesn't | 445 // mem_name will be used for a filename; make sure it doesn't |
| 472 // contain anything which will confuse us. | 446 // contain anything which will confuse us. |
| 473 DCHECK_EQ(std::string::npos, mem_name.find('/')); | 447 DCHECK_EQ(std::string::npos, mem_name.find('/')); |
| 474 DCHECK_EQ(std::string::npos, mem_name.find('\0')); | 448 DCHECK_EQ(std::string::npos, mem_name.find('\0')); |
| 475 | 449 |
| 476 FilePath temp_dir; | 450 FilePath temp_dir; |
| 477 if (!GetShmemTempDir(false, &temp_dir)) | 451 if (!GetShmemTempDir(false, &temp_dir)) |
| 478 return false; | 452 return false; |
| 479 | 453 |
| 480 #if !defined(OS_MACOSX) | |
| 481 #if defined(GOOGLE_CHROME_BUILD) | 454 #if defined(GOOGLE_CHROME_BUILD) |
| 482 std::string name_base = std::string("com.google.Chrome"); | 455 std::string name_base = std::string("com.google.Chrome"); |
| 483 #else | 456 #else |
| 484 std::string name_base = std::string("org.chromium.Chromium"); | 457 std::string name_base = std::string("org.chromium.Chromium"); |
| 485 #endif | 458 #endif |
| 486 #else // OS_MACOSX | |
| 487 std::string name_base = std::string(base::mac::BaseBundleID()); | |
| 488 #endif // OS_MACOSX | |
| 489 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); | 459 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); |
| 490 return true; | 460 return true; |
| 491 } | 461 } |
| 492 #endif // !defined(OS_ANDROID) | 462 #endif // !defined(OS_ANDROID) |
| 493 | 463 |
| 494 void SharedMemory::LockOrUnlockCommon(int function) { | |
| 495 DCHECK_GE(mapped_file_, 0); | |
| 496 while (lockf(mapped_file_, function, 0) < 0) { | |
| 497 if (errno == EINTR) { | |
| 498 continue; | |
| 499 } else if (errno == ENOLCK) { | |
| 500 // temporary kernel resource exaustion | |
| 501 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); | |
| 502 continue; | |
| 503 } else { | |
| 504 NOTREACHED() << "lockf() failed." | |
| 505 << " function:" << function | |
| 506 << " fd:" << mapped_file_ | |
| 507 << " errno:" << errno | |
| 508 << " msg:" << base::safe_strerror(errno); | |
| 509 } | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, | 464 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, |
| 514 SharedMemoryHandle* new_handle, | 465 SharedMemoryHandle* new_handle, |
| 515 bool close_self, | 466 bool close_self, |
| 516 ShareMode share_mode) { | 467 ShareMode share_mode) { |
| 517 int handle_to_dup = -1; | 468 int handle_to_dup = -1; |
| 518 switch(share_mode) { | 469 switch(share_mode) { |
| 519 case SHARE_CURRENT_MODE: | 470 case SHARE_CURRENT_MODE: |
| 520 handle_to_dup = mapped_file_; | 471 handle_to_dup = mapped_file_; |
| 521 break; | 472 break; |
| 522 case SHARE_READONLY: | 473 case SHARE_READONLY: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 538 | 489 |
| 539 if (close_self) { | 490 if (close_self) { |
| 540 Unmap(); | 491 Unmap(); |
| 541 Close(); | 492 Close(); |
| 542 } | 493 } |
| 543 | 494 |
| 544 return true; | 495 return true; |
| 545 } | 496 } |
| 546 | 497 |
| 547 } // namespace base | 498 } // namespace base |
| OLD | NEW |