Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: base/memory/shared_memory_posix.cc

Issue 1180693002: Update from https://crrev.com/333737 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebased Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/memory/shared_memory_nacl.cc ('k') | base/memory/shared_memory_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <sys/mman.h> 9 #include <sys/mman.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
11 #include <sys/types.h> 11 #include <sys/types.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include "base/files/file_util.h" 14 #include "base/files/file_util.h"
15 #include "base/files/scoped_file.h" 15 #include "base/files/scoped_file.h"
16 #include "base/lazy_instance.h" 16 #include "base/lazy_instance.h"
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "base/posix/safe_strerror.h"
18 #include "base/process/process_metrics.h" 20 #include "base/process/process_metrics.h"
19 #include "base/profiler/scoped_tracker.h" 21 #include "base/profiler/scoped_tracker.h"
20 #include "base/safe_strerror_posix.h" 22 #include "base/scoped_generic.h"
21 #include "base/strings/utf_string_conversions.h" 23 #include "base/strings/utf_string_conversions.h"
22 #include "base/synchronization/lock.h" 24 #include "base/synchronization/lock.h"
23 #include "base/threading/platform_thread.h" 25 #include "base/threading/platform_thread.h"
24 #include "base/threading/thread_restrictions.h" 26 #include "base/threading/thread_restrictions.h"
25 27
26 #if defined(OS_MACOSX) 28 #if defined(OS_MACOSX)
27 #include "base/mac/foundation_util.h" 29 #include "base/mac/foundation_util.h"
28 #endif // OS_MACOSX 30 #endif // OS_MACOSX
29 31
30 #if defined(OS_ANDROID) 32 #if defined(OS_ANDROID)
31 #include "base/os_compat_android.h" 33 #include "base/os_compat_android.h"
32 #include "third_party/ashmem/ashmem.h" 34 #include "third_party/ashmem/ashmem.h"
33 #endif 35 #endif
34 36
35 namespace base { 37 namespace base {
36 38
37 namespace { 39 namespace {
38 40
39 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; 41 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
40 42
43 struct ScopedPathUnlinkerTraits {
44 static FilePath* InvalidValue() { return nullptr; }
45
46 static void Free(FilePath* path) {
47 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
48 // is fixed.
49 tracked_objects::ScopedTracker tracking_profile(
50 FROM_HERE_WITH_EXPLICIT_FUNCTION(
51 "466437 SharedMemory::Create::Unlink"));
52 if (unlink(path->value().c_str()))
53 PLOG(WARNING) << "unlink";
54 }
55 };
56
57 // Unlinks the FilePath when the object is destroyed.
58 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
59
60 #if !defined(OS_ANDROID)
61 // Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
62 // with the fdopened FILE. |readonly_fd| is populated with the opened fd if
63 // options.share_read_only is true. |path| is populated with the location of
64 // the file before it was unlinked.
65 // Returns false if there's an unhandled failure.
66 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
67 ScopedFILE* fp,
68 ScopedFD* readonly_fd,
69 FilePath* path) {
70 // It doesn't make sense to have a open-existing private piece of shmem
71 DCHECK(!options.open_existing_deprecated);
72 // Q: Why not use the shm_open() etc. APIs?
73 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
74 FilePath directory;
75 ScopedPathUnlinker path_unlinker;
76 if (GetShmemTempDir(options.executable, &directory)) {
77 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
78 // is fixed.
79 tracked_objects::ScopedTracker tracking_profile(
80 FROM_HERE_WITH_EXPLICIT_FUNCTION(
81 "466437 SharedMemory::Create::OpenTemporaryFile"));
82 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
83
84 // Deleting the file prevents anyone else from mapping it in (making it
85 // private), and prevents the need for cleanup (once the last fd is
86 // closed, it is truly freed).
87 if (*fp)
88 path_unlinker.reset(path);
89 }
90
91 if (*fp) {
92 if (options.share_read_only) {
93 // TODO(erikchen): Remove ScopedTracker below once
94 // http://crbug.com/466437 is fixed.
95 tracked_objects::ScopedTracker tracking_profile(
96 FROM_HERE_WITH_EXPLICIT_FUNCTION(
97 "466437 SharedMemory::Create::OpenReadonly"));
98 // Also open as readonly so that we can ShareReadOnlyToProcess.
99 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
100 if (!readonly_fd->is_valid()) {
101 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
102 fp->reset();
103 return false;
104 }
105 }
106 }
107 return true;
108 }
109 #endif // !defined(OS_ANDROID)
41 } 110 }
42 111
43 SharedMemory::SharedMemory() 112 SharedMemory::SharedMemory()
44 : mapped_file_(-1), 113 : mapped_file_(-1),
45 readonly_mapped_file_(-1), 114 readonly_mapped_file_(-1),
46 inode_(0),
47 mapped_size_(0), 115 mapped_size_(0),
48 memory_(NULL), 116 memory_(NULL),
49 read_only_(false), 117 read_only_(false),
50 requested_size_(0) { 118 requested_size_(0) {
51 } 119 }
52 120
53 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) 121 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
54 : mapped_file_(handle.fd), 122 : mapped_file_(handle.fd),
55 readonly_mapped_file_(-1), 123 readonly_mapped_file_(-1),
56 inode_(0),
57 mapped_size_(0), 124 mapped_size_(0),
58 memory_(NULL), 125 memory_(NULL),
59 read_only_(read_only), 126 read_only_(read_only),
60 requested_size_(0) { 127 requested_size_(0) {
61 struct stat st;
62 if (fstat(handle.fd, &st) == 0) {
63 // If fstat fails, then the file descriptor is invalid and we'll learn this
64 // fact when Map() fails.
65 inode_ = st.st_ino;
66 }
67 } 128 }
68 129
69 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, 130 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
70 ProcessHandle process) 131 ProcessHandle process)
71 : mapped_file_(handle.fd), 132 : mapped_file_(handle.fd),
72 readonly_mapped_file_(-1), 133 readonly_mapped_file_(-1),
73 inode_(0),
74 mapped_size_(0), 134 mapped_size_(0),
75 memory_(NULL), 135 memory_(NULL),
76 read_only_(read_only), 136 read_only_(read_only),
77 requested_size_(0) { 137 requested_size_(0) {
78 // We don't handle this case yet (note the ignored parameter); let's die if 138 // We don't handle this case yet (note the ignored parameter); let's die if
79 // someone comes calling. 139 // someone comes calling.
80 NOTREACHED(); 140 NOTREACHED();
81 } 141 }
82 142
83 SharedMemory::~SharedMemory() { 143 SharedMemory::~SharedMemory() {
(...skipping 16 matching lines...) Expand all
100 DCHECK_GE(handle.fd, 0); 160 DCHECK_GE(handle.fd, 0);
101 if (close(handle.fd) < 0) 161 if (close(handle.fd) < 0)
102 DPLOG(ERROR) << "close"; 162 DPLOG(ERROR) << "close";
103 } 163 }
104 164
105 // static 165 // static
106 size_t SharedMemory::GetHandleLimit() { 166 size_t SharedMemory::GetHandleLimit() {
107 return base::GetMaxFds(); 167 return base::GetMaxFds();
108 } 168 }
109 169
170 // static
171 SharedMemoryHandle SharedMemory::DuplicateHandle(
172 const SharedMemoryHandle& handle) {
173 int duped_handle = HANDLE_EINTR(dup(handle.fd));
174 if (duped_handle < 0)
175 return base::SharedMemory::NULLHandle();
176 return base::FileDescriptor(duped_handle, true);
177 }
178
179 // static
180 int SharedMemory::GetFdFromSharedMemoryHandle(
181 const SharedMemoryHandle& handle) {
182 return handle.fd;
183 }
184
110 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 185 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
111 return CreateAnonymous(size) && Map(size); 186 return CreateAnonymous(size) && Map(size);
112 } 187 }
113 188
114 #if !defined(OS_ANDROID) 189 #if !defined(OS_ANDROID)
190 // static
191 int SharedMemory::GetSizeFromSharedMemoryHandle(
192 const SharedMemoryHandle& handle) {
193 struct stat st;
194 if (fstat(handle.fd, &st) != 0)
195 return -1;
196 return st.st_size;
197 }
198
115 // Chromium mostly only uses the unique/private shmem as specified by 199 // Chromium mostly only uses the unique/private shmem as specified by
116 // "name == L"". The exception is in the StatsTable. 200 // "name == L"". The exception is in the StatsTable.
117 // TODO(jrg): there is no way to "clean up" all unused named shmem if 201 // TODO(jrg): there is no way to "clean up" all unused named shmem if
118 // we restart from a crash. (That isn't a new problem, but it is a problem.) 202 // we restart from a crash. (That isn't a new problem, but it is a problem.)
119 // In case we want to delete it later, it may be useful to save the value 203 // In case we want to delete it later, it may be useful to save the value
120 // of mem_filename after FilePathForMemoryName(). 204 // of mem_filename after FilePathForMemoryName().
121 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 205 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
122 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437 206 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
123 // is fixed. 207 // is fixed.
124 tracked_objects::ScopedTracker tracking_profile1( 208 tracked_objects::ScopedTracker tracking_profile1(
125 FROM_HERE_WITH_EXPLICIT_FUNCTION( 209 FROM_HERE_WITH_EXPLICIT_FUNCTION(
126 "466437 SharedMemory::Create::Start")); 210 "466437 SharedMemory::Create::Start"));
127 DCHECK_EQ(-1, mapped_file_); 211 DCHECK_EQ(-1, mapped_file_);
128 if (options.size == 0) return false; 212 if (options.size == 0) return false;
129 213
130 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) 214 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
131 return false; 215 return false;
132 216
133 // This function theoretically can block on the disk, but realistically 217 // This function theoretically can block on the disk, but realistically
134 // the temporary files we create will just go into the buffer cache 218 // the temporary files we create will just go into the buffer cache
135 // and be deleted before they ever make it out to disk. 219 // and be deleted before they ever make it out to disk.
136 base::ThreadRestrictions::ScopedAllowIO allow_io; 220 base::ThreadRestrictions::ScopedAllowIO allow_io;
137 221
138 ScopedFILE fp; 222 ScopedFILE fp;
139 bool fix_size = true; 223 bool fix_size = true;
140 ScopedFD readonly_fd; 224 ScopedFD readonly_fd;
141 225
142 FilePath path; 226 FilePath path;
143 if (options.name_deprecated == NULL || options.name_deprecated->empty()) { 227 if (options.name_deprecated == NULL || options.name_deprecated->empty()) {
144 // It doesn't make sense to have a open-existing private piece of shmem 228 bool result =
145 DCHECK(!options.open_existing_deprecated); 229 CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
146 // Q: Why not use the shm_open() etc. APIs? 230 if (!result)
147 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU 231 return false;
148 FilePath directory;
149 if (GetShmemTempDir(options.executable, &directory)) {
150 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
151 // is fixed.
152 tracked_objects::ScopedTracker tracking_profile2(
153 FROM_HERE_WITH_EXPLICIT_FUNCTION(
154 "466437 SharedMemory::Create::OpenTemporaryFile"));
155 fp.reset(CreateAndOpenTemporaryFileInDir(directory, &path));
156 }
157
158 if (fp) {
159 if (options.share_read_only) {
160 // TODO(erikchen): Remove ScopedTracker below once
161 // http://crbug.com/466437 is fixed.
162 tracked_objects::ScopedTracker tracking_profile3(
163 FROM_HERE_WITH_EXPLICIT_FUNCTION(
164 "466437 SharedMemory::Create::OpenReadonly"));
165 // Also open as readonly so that we can ShareReadOnlyToProcess.
166 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
167 if (!readonly_fd.is_valid()) {
168 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
169 fp.reset();
170 return false;
171 }
172 }
173
174 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
175 // is fixed.
176 tracked_objects::ScopedTracker tracking_profile4(
177 FROM_HERE_WITH_EXPLICIT_FUNCTION(
178 "466437 SharedMemory::Create::Unlink"));
179 // Deleting the file prevents anyone else from mapping it in (making it
180 // private), and prevents the need for cleanup (once the last fd is
181 // closed, it is truly freed).
182 if (unlink(path.value().c_str()))
183 PLOG(WARNING) << "unlink";
184 }
185 } else { 232 } else {
186 if (!FilePathForMemoryName(*options.name_deprecated, &path)) 233 if (!FilePathForMemoryName(*options.name_deprecated, &path))
187 return false; 234 return false;
188 235
189 // Make sure that the file is opened without any permission 236 // Make sure that the file is opened without any permission
190 // to other users on the system. 237 // to other users on the system.
191 const mode_t kOwnerOnly = S_IRUSR | S_IWUSR; 238 const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
192 239
193 // First, try to create the file. 240 // First, try to create the file.
194 int fd = HANDLE_EINTR( 241 int fd = HANDLE_EINTR(
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 if (readonly_fd.is_valid()) { 442 if (readonly_fd.is_valid()) {
396 struct stat readonly_st = {}; 443 struct stat readonly_st = {};
397 if (fstat(readonly_fd.get(), &readonly_st)) 444 if (fstat(readonly_fd.get(), &readonly_st))
398 NOTREACHED(); 445 NOTREACHED();
399 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { 446 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
400 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; 447 LOG(ERROR) << "writable and read-only inodes don't match; bailing";
401 return false; 448 return false;
402 } 449 }
403 } 450 }
404 451
405 mapped_file_ = dup(fileno(fp.get())); 452 mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
406 if (mapped_file_ == -1) { 453 if (mapped_file_ == -1) {
407 if (errno == EMFILE) { 454 if (errno == EMFILE) {
408 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; 455 LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
409 return false; 456 return false;
410 } else { 457 } else {
411 NOTREACHED() << "Call to dup failed, errno=" << errno; 458 NOTREACHED() << "Call to dup failed, errno=" << errno;
412 } 459 }
413 } 460 }
414 inode_ = st.st_ino;
415 readonly_mapped_file_ = readonly_fd.release(); 461 readonly_mapped_file_ = readonly_fd.release();
416 462
417 return true; 463 return true;
418 } 464 }
419 465
420 // For the given shmem named |mem_name|, return a filename to mmap() 466 // For the given shmem named |mem_name|, return a filename to mmap()
421 // (and possibly create). Modifies |filename|. Return false on 467 // (and possibly create). Modifies |filename|. Return false on
422 // error, or true of we are happy. 468 // error, or true of we are happy.
423 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, 469 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
424 FilePath* path) { 470 FilePath* path) {
(...skipping 27 matching lines...) Expand all
452 continue; 498 continue;
453 } else if (errno == ENOLCK) { 499 } else if (errno == ENOLCK) {
454 // temporary kernel resource exaustion 500 // temporary kernel resource exaustion
455 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); 501 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
456 continue; 502 continue;
457 } else { 503 } else {
458 NOTREACHED() << "lockf() failed." 504 NOTREACHED() << "lockf() failed."
459 << " function:" << function 505 << " function:" << function
460 << " fd:" << mapped_file_ 506 << " fd:" << mapped_file_
461 << " errno:" << errno 507 << " errno:" << errno
462 << " msg:" << safe_strerror(errno); 508 << " msg:" << base::safe_strerror(errno);
463 } 509 }
464 } 510 }
465 } 511 }
466 512
467 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 513 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
468 SharedMemoryHandle* new_handle, 514 SharedMemoryHandle* new_handle,
469 bool close_self, 515 bool close_self,
470 ShareMode share_mode) { 516 ShareMode share_mode) {
471 int handle_to_dup = -1; 517 int handle_to_dup = -1;
472 switch(share_mode) { 518 switch(share_mode) {
473 case SHARE_CURRENT_MODE: 519 case SHARE_CURRENT_MODE:
474 handle_to_dup = mapped_file_; 520 handle_to_dup = mapped_file_;
475 break; 521 break;
476 case SHARE_READONLY: 522 case SHARE_READONLY:
477 // We could imagine re-opening the file from /dev/fd, but that can't make 523 // We could imagine re-opening the file from /dev/fd, but that can't make
478 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10 524 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
479 CHECK_GE(readonly_mapped_file_, 0); 525 CHECK_GE(readonly_mapped_file_, 0);
480 handle_to_dup = readonly_mapped_file_; 526 handle_to_dup = readonly_mapped_file_;
481 break; 527 break;
482 } 528 }
483 529
484 const int new_fd = dup(handle_to_dup); 530 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
485 if (new_fd < 0) { 531 if (new_fd < 0) {
486 DPLOG(ERROR) << "dup() failed."; 532 DPLOG(ERROR) << "dup() failed.";
487 return false; 533 return false;
488 } 534 }
489 535
490 new_handle->fd = new_fd; 536 new_handle->fd = new_fd;
491 new_handle->auto_close = true; 537 new_handle->auto_close = true;
492 538
493 if (close_self) { 539 if (close_self) {
494 Unmap(); 540 Unmap();
495 Close(); 541 Close();
496 } 542 }
497 543
498 return true; 544 return true;
499 } 545 }
500 546
501 } // namespace base 547 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/shared_memory_nacl.cc ('k') | base/memory/shared_memory_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698