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

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

Issue 2555483002: Add POSIX shared memory support for Mac (Closed)
Patch Set: Restructure CreateAnonymousSharedMemory Created 4 years 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
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 <stddef.h> 9 #include <stddef.h>
10 #include <sys/mman.h> 10 #include <sys/mman.h>
11 #include <sys/stat.h> 11 #include <sys/stat.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/logging.h" 16 #include "base/logging.h"
17 #include "base/memory/shared_memory_helper.h"
17 #include "base/posix/eintr_wrapper.h" 18 #include "base/posix/eintr_wrapper.h"
18 #include "base/posix/safe_strerror.h" 19 #include "base/posix/safe_strerror.h"
19 #include "base/process/process_metrics.h" 20 #include "base/process/process_metrics.h"
20 #include "base/profiler/scoped_tracker.h"
21 #include "base/scoped_generic.h" 21 #include "base/scoped_generic.h"
22 #include "base/strings/utf_string_conversions.h" 22 #include "base/strings/utf_string_conversions.h"
23 #include "base/threading/thread_restrictions.h"
23 #include "build/build_config.h" 24 #include "build/build_config.h"
24 25
25 #if defined(OS_ANDROID) 26 #if defined(OS_ANDROID)
26 #include "base/os_compat_android.h" 27 #include "base/os_compat_android.h"
27 #include "third_party/ashmem/ashmem.h" 28 #include "third_party/ashmem/ashmem.h"
28 #endif 29 #endif
29 30
30 namespace base { 31 namespace base {
31 32
32 namespace {
33
34 struct ScopedPathUnlinkerTraits {
35 static FilePath* InvalidValue() { return nullptr; }
36
37 static void Free(FilePath* path) {
38 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
39 // is fixed.
40 tracked_objects::ScopedTracker tracking_profile(
41 FROM_HERE_WITH_EXPLICIT_FUNCTION(
42 "466437 SharedMemory::Create::Unlink"));
43 if (unlink(path->value().c_str()))
44 PLOG(WARNING) << "unlink";
45 }
46 };
47
48 // Unlinks the FilePath when the object is destroyed.
49 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
50
51 #if !defined(OS_ANDROID)
52 // Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
53 // with the fdopened FILE. |readonly_fd| is populated with the opened fd if
54 // options.share_read_only is true. |path| is populated with the location of
55 // the file before it was unlinked.
56 // Returns false if there's an unhandled failure.
57 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
58 ScopedFILE* fp,
59 ScopedFD* readonly_fd,
60 FilePath* path) {
61 // It doesn't make sense to have a open-existing private piece of shmem
62 DCHECK(!options.open_existing_deprecated);
63 // Q: Why not use the shm_open() etc. APIs?
64 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
65 FilePath directory;
66 ScopedPathUnlinker path_unlinker;
67 if (GetShmemTempDir(options.executable, &directory)) {
68 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
69 // is fixed.
70 tracked_objects::ScopedTracker tracking_profile(
71 FROM_HERE_WITH_EXPLICIT_FUNCTION(
72 "466437 SharedMemory::Create::OpenTemporaryFile"));
73 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
74
75 // Deleting the file prevents anyone else from mapping it in (making it
76 // private), and prevents the need for cleanup (once the last fd is
77 // closed, it is truly freed).
78 if (*fp)
79 path_unlinker.reset(path);
80 }
81
82 if (*fp) {
83 if (options.share_read_only) {
84 // TODO(erikchen): Remove ScopedTracker below once
85 // http://crbug.com/466437 is fixed.
86 tracked_objects::ScopedTracker tracking_profile(
87 FROM_HERE_WITH_EXPLICIT_FUNCTION(
88 "466437 SharedMemory::Create::OpenReadonly"));
89 // Also open as readonly so that we can ShareReadOnlyToProcess.
90 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
91 if (!readonly_fd->is_valid()) {
92 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
93 fp->reset();
94 return false;
95 }
96 }
97 }
98 return true;
99 }
100 #endif // !defined(OS_ANDROID)
101 }
102
103 SharedMemory::SharedMemory() 33 SharedMemory::SharedMemory()
104 : mapped_file_(-1), 34 : mapped_file_(-1),
105 readonly_mapped_file_(-1), 35 readonly_mapped_file_(-1),
106 mapped_size_(0), 36 mapped_size_(0),
107 memory_(NULL), 37 memory_(NULL),
108 read_only_(false), 38 read_only_(false),
109 requested_size_(0) { 39 requested_size_(0) {
110 } 40 }
111 41
112 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) 42 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 return true; 108 return true;
179 } 109 }
180 110
181 // Chromium mostly only uses the unique/private shmem as specified by 111 // Chromium mostly only uses the unique/private shmem as specified by
182 // "name == L"". The exception is in the StatsTable. 112 // "name == L"". The exception is in the StatsTable.
183 // TODO(jrg): there is no way to "clean up" all unused named shmem if 113 // TODO(jrg): there is no way to "clean up" all unused named shmem if
184 // we restart from a crash. (That isn't a new problem, but it is a problem.) 114 // we restart from a crash. (That isn't a new problem, but it is a problem.)
185 // In case we want to delete it later, it may be useful to save the value 115 // In case we want to delete it later, it may be useful to save the value
186 // of mem_filename after FilePathForMemoryName(). 116 // of mem_filename after FilePathForMemoryName().
187 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 117 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
188 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
189 // is fixed.
190 tracked_objects::ScopedTracker tracking_profile1(
191 FROM_HERE_WITH_EXPLICIT_FUNCTION(
192 "466437 SharedMemory::Create::Start"));
193 DCHECK_EQ(-1, mapped_file_); 118 DCHECK_EQ(-1, mapped_file_);
194 if (options.size == 0) return false; 119 if (options.size == 0) return false;
195 120
196 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) 121 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
197 return false; 122 return false;
198 123
199 // This function theoretically can block on the disk, but realistically 124 // This function theoretically can block on the disk, but realistically
200 // the temporary files we create will just go into the buffer cache 125 // the temporary files we create will just go into the buffer cache
201 // and be deleted before they ever make it out to disk. 126 // and be deleted before they ever make it out to disk.
202 base::ThreadRestrictions::ScopedAllowIO allow_io; 127 base::ThreadRestrictions::ScopedAllowIO allow_io;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { 210 if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
286 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); 211 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
287 if (dir.value() == "/dev/shm") { 212 if (dir.value() == "/dev/shm") {
288 LOG(FATAL) << "This is frequently caused by incorrect permissions on " 213 LOG(FATAL) << "This is frequently caused by incorrect permissions on "
289 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; 214 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
290 } 215 }
291 } 216 }
292 return false; 217 return false;
293 } 218 }
294 219
295 return PrepareMapFile(std::move(fp), std::move(readonly_fd)); 220 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
221 &readonly_mapped_file_);
296 } 222 }
297 223
298 // Our current implementation of shmem is with mmap()ing of files. 224 // Our current implementation of shmem is with mmap()ing of files.
299 // These files need to be deleted explicitly. 225 // These files need to be deleted explicitly.
300 // In practice this call is only needed for unit tests. 226 // In practice this call is only needed for unit tests.
301 bool SharedMemory::Delete(const std::string& name) { 227 bool SharedMemory::Delete(const std::string& name) {
302 FilePath path; 228 FilePath path;
303 if (!FilePathForMemoryName(name, &path)) 229 if (!FilePathForMemoryName(name, &path))
304 return false; 230 return false;
305 231
(...skipping 11 matching lines...) Expand all
317 243
318 read_only_ = read_only; 244 read_only_ = read_only;
319 245
320 const char *mode = read_only ? "r" : "r+"; 246 const char *mode = read_only ? "r" : "r+";
321 ScopedFILE fp(base::OpenFile(path, mode)); 247 ScopedFILE fp(base::OpenFile(path, mode));
322 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); 248 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
323 if (!readonly_fd.is_valid()) { 249 if (!readonly_fd.is_valid()) {
324 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; 250 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
325 return false; 251 return false;
326 } 252 }
327 return PrepareMapFile(std::move(fp), std::move(readonly_fd)); 253 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
254 &readonly_mapped_file_);
328 } 255 }
329 #endif // !defined(OS_ANDROID) 256 #endif // !defined(OS_ANDROID)
330 257
331 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 258 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
332 if (mapped_file_ == -1) 259 if (mapped_file_ == -1)
333 return false; 260 return false;
334 261
335 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 262 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
336 return false; 263 return false;
337 264
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 mapped_file_ = -1; 321 mapped_file_ = -1;
395 } 322 }
396 if (readonly_mapped_file_ > 0) { 323 if (readonly_mapped_file_ > 0) {
397 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0) 324 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
398 PLOG(ERROR) << "close"; 325 PLOG(ERROR) << "close";
399 readonly_mapped_file_ = -1; 326 readonly_mapped_file_ = -1;
400 } 327 }
401 } 328 }
402 329
403 #if !defined(OS_ANDROID) 330 #if !defined(OS_ANDROID)
404 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
405 DCHECK_EQ(-1, mapped_file_);
406 DCHECK_EQ(-1, readonly_mapped_file_);
407 if (fp == NULL)
408 return false;
409
410 // This function theoretically can block on the disk, but realistically
411 // the temporary files we create will just go into the buffer cache
412 // and be deleted before they ever make it out to disk.
413 base::ThreadRestrictions::ScopedAllowIO allow_io;
414
415 struct stat st = {};
416 if (fstat(fileno(fp.get()), &st))
417 NOTREACHED();
418 if (readonly_fd.is_valid()) {
419 struct stat readonly_st = {};
420 if (fstat(readonly_fd.get(), &readonly_st))
421 NOTREACHED();
422 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
423 LOG(ERROR) << "writable and read-only inodes don't match; bailing";
424 return false;
425 }
426 }
427
428 mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
429 if (mapped_file_ == -1) {
430 if (errno == EMFILE) {
431 LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
432 return false;
433 } else {
434 NOTREACHED() << "Call to dup failed, errno=" << errno;
435 }
436 }
437 readonly_mapped_file_ = readonly_fd.release();
438
439 return true;
440 }
441
442 // For the given shmem named |mem_name|, return a filename to mmap() 331 // For the given shmem named |mem_name|, return a filename to mmap()
443 // (and possibly create). Modifies |filename|. Return false on 332 // (and possibly create). Modifies |filename|. Return false on
444 // error, or true of we are happy. 333 // error, or true of we are happy.
445 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, 334 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
446 FilePath* path) { 335 FilePath* path) {
447 // mem_name will be used for a filename; make sure it doesn't 336 // mem_name will be used for a filename; make sure it doesn't
448 // contain anything which will confuse us. 337 // contain anything which will confuse us.
449 DCHECK_EQ(std::string::npos, mem_name.find('/')); 338 DCHECK_EQ(std::string::npos, mem_name.find('/'));
450 DCHECK_EQ(std::string::npos, mem_name.find('\0')); 339 DCHECK_EQ(std::string::npos, mem_name.find('\0'));
451 340
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 384
496 if (close_self) { 385 if (close_self) {
497 Unmap(); 386 Unmap();
498 Close(); 387 Close();
499 } 388 }
500 389
501 return true; 390 return true;
502 } 391 }
503 392
504 } // namespace base 393 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698