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

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

Issue 1896443002: Revert of mac: Remove POSIX shared memory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@temp50_base
Patch Set: Created 4 years, 8 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_handle_mac.cc ('k') | base/memory/shared_memory_unittest.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>
8 #include <fcntl.h>
7 #include <mach/mach_vm.h> 9 #include <mach/mach_vm.h>
10 #include <stddef.h>
11 #include <sys/mman.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
8 14
9 #include "base/files/file_util.h" 15 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h" 16 #include "base/files/scoped_file.h"
11 #include "base/logging.h" 17 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_util.h" 18 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_mach_vm.h" 19 #include "base/mac/scoped_mach_vm.h"
15 #include "base/metrics/field_trial.h" 20 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram_macros.h" 21 #include "base/metrics/histogram_macros.h"
22 #include "base/posix/eintr_wrapper.h"
23 #include "base/posix/safe_strerror.h"
17 #include "base/process/process_metrics.h" 24 #include "base/process/process_metrics.h"
18 #include "base/profiler/scoped_tracker.h" 25 #include "base/profiler/scoped_tracker.h"
19 #include "base/scoped_generic.h" 26 #include "base/scoped_generic.h"
20 #include "base/strings/utf_string_conversions.h" 27 #include "base/strings/utf_string_conversions.h"
21 #include "build/build_config.h" 28 #include "build/build_config.h"
22 29
30 #if defined(OS_MACOSX)
31 #include "base/mac/foundation_util.h"
32 #endif // OS_MACOSX
33
23 namespace base { 34 namespace base {
24 35
25 namespace { 36 namespace {
26 37
27 // Returns whether the operation succeeded. 38 // Returns whether the operation succeeded.
28 // |new_handle| is an output variable, populated on success. The caller takes 39 // |new_handle| is an output variable, populated on success. The caller takes
29 // ownership of the underlying memory object. 40 // ownership of the underlying memory object.
30 // |handle| is the handle to copy. 41 // |handle| is the handle to copy.
31 // If |handle| is already mapped, |mapped_addr| is its mapped location. 42 // If |handle| is already mapped, |mapped_addr| is its mapped location.
32 // Otherwise, |mapped_addr| should be |nullptr|. 43 // Otherwise, |mapped_addr| should be |nullptr|.
(...skipping 27 matching lines...) Expand all
60 mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size), 71 mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
61 reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ, 72 reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
62 &named_right, MACH_PORT_NULL); 73 &named_right, MACH_PORT_NULL);
63 if (kr != KERN_SUCCESS) 74 if (kr != KERN_SUCCESS)
64 return false; 75 return false;
65 76
66 *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId()); 77 *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
67 return true; 78 return true;
68 } 79 }
69 80
81 struct ScopedPathUnlinkerTraits {
82 static FilePath* InvalidValue() { return nullptr; }
83
84 static void Free(FilePath* path) {
85 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
86 // is fixed.
87 tracked_objects::ScopedTracker tracking_profile(
88 FROM_HERE_WITH_EXPLICIT_FUNCTION(
89 "466437 SharedMemory::Create::Unlink"));
90 if (unlink(path->value().c_str()))
91 PLOG(WARNING) << "unlink";
92 }
93 };
94
95 // Unlinks the FilePath when the object is destroyed.
96 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
97
98 // Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
99 // with the fdopened FILE. |readonly_fd| is populated with the opened fd if
100 // options.share_read_only is true. |path| is populated with the location of
101 // the file before it was unlinked.
102 // Returns false if there's an unhandled failure.
103 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
104 ScopedFILE* fp,
105 ScopedFD* readonly_fd,
106 FilePath* path) {
107 // Q: Why not use the shm_open() etc. APIs?
108 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
109 FilePath directory;
110 ScopedPathUnlinker path_unlinker;
111 if (GetShmemTempDir(options.executable, &directory)) {
112 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
113 // is fixed.
114 tracked_objects::ScopedTracker tracking_profile(
115 FROM_HERE_WITH_EXPLICIT_FUNCTION(
116 "466437 SharedMemory::Create::OpenTemporaryFile"));
117 fp->reset(CreateAndOpenTemporaryFileInDir(directory, path));
118
119 // Deleting the file prevents anyone else from mapping it in (making it
120 // private), and prevents the need for cleanup (once the last fd is
121 // closed, it is truly freed).
122 if (*fp)
123 path_unlinker.reset(path);
124 }
125
126 if (*fp) {
127 if (options.share_read_only) {
128 // TODO(erikchen): Remove ScopedTracker below once
129 // http://crbug.com/466437 is fixed.
130 tracked_objects::ScopedTracker tracking_profile(
131 FROM_HERE_WITH_EXPLICIT_FUNCTION(
132 "466437 SharedMemory::Create::OpenReadonly"));
133 // Also open as readonly so that we can ShareReadOnlyToProcess.
134 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
135 if (!readonly_fd->is_valid()) {
136 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
137 fp->reset();
138 return false;
139 }
140 }
141 }
142 return true;
143 }
144
70 } // namespace 145 } // namespace
71 146
72 SharedMemoryCreateOptions::SharedMemoryCreateOptions() 147 SharedMemoryCreateOptions::SharedMemoryCreateOptions()
73 : size(0), 148 : type(SharedMemoryHandle::MACH),
149 size(0),
74 executable(false), 150 executable(false),
75 share_read_only(false) {} 151 share_read_only(false) {}
76 152
77 SharedMemory::SharedMemory() 153 SharedMemory::SharedMemory()
78 : readonly_mapped_file_(-1), 154 : mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
155 readonly_mapped_file_(-1),
79 mapped_size_(0), 156 mapped_size_(0),
80 memory_(NULL), 157 memory_(NULL),
81 read_only_(false), 158 read_only_(false),
82 requested_size_(0) {} 159 requested_size_(0) {}
83 160
84 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) 161 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
85 : shm_(handle), 162 : shm_(handle),
163 mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
86 readonly_mapped_file_(-1), 164 readonly_mapped_file_(-1),
87 mapped_size_(0), 165 mapped_size_(0),
88 memory_(NULL), 166 memory_(NULL),
89 read_only_(read_only), 167 read_only_(read_only),
90 requested_size_(0) {} 168 requested_size_(0) {}
91 169
92 SharedMemory::~SharedMemory() { 170 SharedMemory::~SharedMemory() {
93 Unmap(); 171 Unmap();
94 Close(); 172 Close();
95 } 173 }
96 174
97 // static 175 // static
98 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 176 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
99 return handle.IsValid(); 177 return handle.IsValid();
100 } 178 }
101 179
102 // static 180 // static
103 SharedMemoryHandle SharedMemory::NULLHandle() { 181 SharedMemoryHandle SharedMemory::NULLHandle() {
104 return SharedMemoryHandle(); 182 return SharedMemoryHandle();
105 } 183 }
106 184
107 // static 185 // static
108 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { 186 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
109 handle.Close(); 187 handle.Close();
110 } 188 }
111 189
112 // static 190 // static
113 size_t SharedMemory::GetHandleLimit() { 191 size_t SharedMemory::GetHandleLimit() {
114 // This should be effectively unlimited on OS X. 192 return GetMaxFds();
115 return 10000;
116 } 193 }
117 194
118 // static 195 // static
119 SharedMemoryHandle SharedMemory::DuplicateHandle( 196 SharedMemoryHandle SharedMemory::DuplicateHandle(
120 const SharedMemoryHandle& handle) { 197 const SharedMemoryHandle& handle) {
121 return handle.Duplicate(); 198 return handle.Duplicate();
122 } 199 }
123 200
201 // static
202 int SharedMemory::GetFdFromSharedMemoryHandle(
203 const SharedMemoryHandle& handle) {
204 return handle.GetFileDescriptor().fd;
205 }
206
124 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 207 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
125 return CreateAnonymous(size) && Map(size); 208 return CreateAnonymous(size) && Map(size);
126 } 209 }
127 210
211 bool SharedMemory::CreateAndMapAnonymousPosix(size_t size) {
212 return CreateAnonymousPosix(size) && Map(size);
213 }
214
215 bool SharedMemory::CreateAnonymousPosix(size_t size) {
216 SharedMemoryCreateOptions options;
217 options.type = SharedMemoryHandle::POSIX;
218 options.size = size;
219 return Create(options);
220 }
221
128 // static 222 // static
129 bool SharedMemory::GetSizeFromSharedMemoryHandle( 223 bool SharedMemory::GetSizeFromSharedMemoryHandle(
130 const SharedMemoryHandle& handle, 224 const SharedMemoryHandle& handle,
131 size_t* size) { 225 size_t* size) {
132 return handle.GetSize(size); 226 return handle.GetSize(size);
133 } 227 }
134 228
135 // Chromium mostly only uses the unique/private shmem as specified by 229 // Chromium mostly only uses the unique/private shmem as specified by
136 // "name == L"". The exception is in the StatsTable. 230 // "name == L"". The exception is in the StatsTable.
137 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 231 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
138 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437 232 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
139 // is fixed. 233 // is fixed.
140 tracked_objects::ScopedTracker tracking_profile1( 234 tracked_objects::ScopedTracker tracking_profile1(
141 FROM_HERE_WITH_EXPLICIT_FUNCTION( 235 FROM_HERE_WITH_EXPLICIT_FUNCTION(
142 "466437 SharedMemory::Create::Start")); 236 "466437 SharedMemory::Create::Start"));
143 DCHECK(!shm_.IsValid()); 237 DCHECK(!shm_.IsValid());
144 if (options.size == 0) return false; 238 if (options.size == 0) return false;
145 239
146 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) 240 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
147 return false; 241 return false;
148 242
149 shm_ = SharedMemoryHandle(options.size); 243 if (options.type == SharedMemoryHandle::MACH) {
244 shm_ = SharedMemoryHandle(options.size);
245 requested_size_ = options.size;
246 return shm_.IsValid();
247 }
248
249 // This function theoretically can block on the disk. Both profiling of real
250 // users and local instrumentation shows that this is a real problem.
251 // https://code.google.com/p/chromium/issues/detail?id=466437
252 base::ThreadRestrictions::ScopedAllowIO allow_io;
253
254 ScopedFILE fp;
255 ScopedFD readonly_fd;
256
257 FilePath path;
258 bool result = CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
259 if (!result)
260 return false;
261
262 if (!fp) {
263 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
264 return false;
265 }
266
267 // Get current size.
268 struct stat stat;
269 if (fstat(fileno(fp.get()), &stat) != 0)
270 return false;
271 const size_t current_size = stat.st_size;
272 if (current_size != options.size) {
273 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
274 return false;
275 }
150 requested_size_ = options.size; 276 requested_size_ = options.size;
151 return shm_.IsValid(); 277
278 return PrepareMapFile(std::move(fp), std::move(readonly_fd));
152 } 279 }
153 280
154 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 281 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
155 if (!shm_.IsValid()) 282 if (!shm_.IsValid())
156 return false; 283 return false;
157 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 284 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
158 return false; 285 return false;
159 if (memory_) 286 if (memory_)
160 return false; 287 return false;
161 288
162 bool success = shm_.MapAt(offset, bytes, &memory_, read_only_); 289 bool success = shm_.MapAt(offset, bytes, &memory_, read_only_);
163 if (success) { 290 if (success) {
164 mapped_size_ = bytes; 291 mapped_size_ = bytes;
165 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & 292 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
166 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 293 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
294 mapped_memory_mechanism_ = shm_.GetType();
167 } else { 295 } else {
168 memory_ = NULL; 296 memory_ = NULL;
169 } 297 }
170 298
171 return success; 299 return success;
172 } 300 }
173 301
174 bool SharedMemory::Unmap() { 302 bool SharedMemory::Unmap() {
175 if (memory_ == NULL) 303 if (memory_ == NULL)
176 return false; 304 return false;
177 305
178 mach_vm_deallocate(mach_task_self(), 306 switch (mapped_memory_mechanism_) {
179 reinterpret_cast<mach_vm_address_t>(memory_), 307 case SharedMemoryHandle::POSIX:
180 mapped_size_); 308 munmap(memory_, mapped_size_);
309 break;
310 case SharedMemoryHandle::MACH:
311 mach_vm_deallocate(mach_task_self(),
312 reinterpret_cast<mach_vm_address_t>(memory_),
313 mapped_size_);
314 break;
315 }
316
181 memory_ = NULL; 317 memory_ = NULL;
182 mapped_size_ = 0; 318 mapped_size_ = 0;
183 return true; 319 return true;
184 } 320 }
185 321
186 SharedMemoryHandle SharedMemory::handle() const { 322 SharedMemoryHandle SharedMemory::handle() const {
187 return shm_; 323 switch (shm_.GetType()) {
324 case SharedMemoryHandle::POSIX:
325 return SharedMemoryHandle(shm_.GetFileDescriptor().fd, false);
326 case SharedMemoryHandle::MACH:
327 return shm_;
328 }
188 } 329 }
189 330
190 void SharedMemory::Close() { 331 void SharedMemory::Close() {
191 shm_.Close(); 332 shm_.Close();
192 shm_ = SharedMemoryHandle(); 333 shm_ = SharedMemoryHandle();
334 if (shm_.GetType() == SharedMemoryHandle::POSIX) {
335 if (readonly_mapped_file_ > 0) {
336 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
337 PLOG(ERROR) << "close";
338 readonly_mapped_file_ = -1;
339 }
340 }
341 }
342
343 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
344 DCHECK(!shm_.IsValid());
345 DCHECK_EQ(-1, readonly_mapped_file_);
346 if (fp == NULL)
347 return false;
348
349 // This function theoretically can block on the disk, but realistically
350 // the temporary files we create will just go into the buffer cache
351 // and be deleted before they ever make it out to disk.
352 base::ThreadRestrictions::ScopedAllowIO allow_io;
353
354 struct stat st = {};
355 if (fstat(fileno(fp.get()), &st))
356 NOTREACHED();
357 if (readonly_fd.is_valid()) {
358 struct stat readonly_st = {};
359 if (fstat(readonly_fd.get(), &readonly_st))
360 NOTREACHED();
361 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
362 LOG(ERROR) << "writable and read-only inodes don't match; bailing";
363 return false;
364 }
365 }
366
367 int mapped_file = HANDLE_EINTR(dup(fileno(fp.get())));
368 if (mapped_file == -1) {
369 if (errno == EMFILE) {
370 LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
371 return false;
372 } else {
373 NOTREACHED() << "Call to dup failed, errno=" << errno;
374 }
375 }
376 shm_ = SharedMemoryHandle(mapped_file, false);
377 readonly_mapped_file_ = readonly_fd.release();
378
379 return true;
193 } 380 }
194 381
195 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 382 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
196 SharedMemoryHandle* new_handle, 383 SharedMemoryHandle* new_handle,
197 bool close_self, 384 bool close_self,
198 ShareMode share_mode) { 385 ShareMode share_mode) {
199 DCHECK(shm_.IsValid()); 386 if (shm_.GetType() == SharedMemoryHandle::MACH) {
387 DCHECK(shm_.IsValid());
200 388
201 bool success = false; 389 bool success = false;
390 switch (share_mode) {
391 case SHARE_CURRENT_MODE:
392 *new_handle = shm_.Duplicate();
393 success = true;
394 break;
395 case SHARE_READONLY:
396 success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
397 break;
398 }
399
400 if (success)
401 new_handle->SetOwnershipPassesToIPC(true);
402
403 if (close_self) {
404 Unmap();
405 Close();
406 }
407
408 return success;
409 }
410
411 int handle_to_dup = -1;
202 switch (share_mode) { 412 switch (share_mode) {
203 case SHARE_CURRENT_MODE: 413 case SHARE_CURRENT_MODE:
204 *new_handle = shm_.Duplicate(); 414 handle_to_dup = shm_.GetFileDescriptor().fd;
205 success = true;
206 break; 415 break;
207 case SHARE_READONLY: 416 case SHARE_READONLY:
208 success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_); 417 // We could imagine re-opening the file from /dev/fd, but that can't make
418 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
419 CHECK_GE(readonly_mapped_file_, 0);
420 handle_to_dup = readonly_mapped_file_;
209 break; 421 break;
210 } 422 }
211 423
212 if (success) 424 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
213 new_handle->SetOwnershipPassesToIPC(true); 425 if (new_fd < 0) {
426 if (close_self) {
427 Unmap();
428 Close();
429 }
430 DPLOG(ERROR) << "dup() failed.";
431 return false;
432 }
433
434 new_handle->SetFileHandle(new_fd, true);
214 435
215 if (close_self) { 436 if (close_self) {
216 Unmap(); 437 Unmap();
217 Close(); 438 Close();
218 } 439 }
219 440
220 return success; 441 return true;
221 } 442 }
222 443
223 } // namespace base 444 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/shared_memory_handle_mac.cc ('k') | base/memory/shared_memory_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698