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

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

Issue 1163943004: Make SharedMemoryHandle a class on Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shared_memory_make_class3_base
Patch Set: Fix logic error. 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
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>
(...skipping 11 matching lines...) Expand all
22 #include "base/scoped_generic.h" 22 #include "base/scoped_generic.h"
23 #include "base/strings/utf_string_conversions.h" 23 #include "base/strings/utf_string_conversions.h"
24 #include "base/synchronization/lock.h" 24 #include "base/synchronization/lock.h"
25 #include "base/threading/platform_thread.h" 25 #include "base/threading/platform_thread.h"
26 #include "base/threading/thread_restrictions.h" 26 #include "base/threading/thread_restrictions.h"
27 27
28 #if defined(OS_MACOSX) 28 #if defined(OS_MACOSX)
29 #include "base/mac/foundation_util.h" 29 #include "base/mac/foundation_util.h"
30 #endif // OS_MACOSX 30 #endif // OS_MACOSX
31 31
32 #if defined(OS_ANDROID)
33 #include "base/os_compat_android.h"
34 #include "third_party/ashmem/ashmem.h"
35 #endif
36
37 namespace base { 32 namespace base {
38 33
39 namespace { 34 namespace {
40 35
41 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; 36 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
42 37
43 struct ScopedPathUnlinkerTraits { 38 struct ScopedPathUnlinkerTraits {
44 static FilePath* InvalidValue() { return nullptr; } 39 static FilePath* InvalidValue() { return nullptr; }
45 40
46 static void Free(FilePath* path) { 41 static void Free(FilePath* path) {
47 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437 42 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
48 // is fixed. 43 // is fixed.
49 tracked_objects::ScopedTracker tracking_profile( 44 tracked_objects::ScopedTracker tracking_profile(
50 FROM_HERE_WITH_EXPLICIT_FUNCTION( 45 FROM_HERE_WITH_EXPLICIT_FUNCTION(
51 "466437 SharedMemory::Create::Unlink")); 46 "466437 SharedMemory::Create::Unlink"));
52 if (unlink(path->value().c_str())) 47 if (unlink(path->value().c_str()))
53 PLOG(WARNING) << "unlink"; 48 PLOG(WARNING) << "unlink";
54 } 49 }
55 }; 50 };
56 51
57 // Unlinks the FilePath when the object is destroyed. 52 // Unlinks the FilePath when the object is destroyed.
58 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker; 53 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
59 54
60 #if !defined(OS_ANDROID)
61 // Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated 55 // 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 56 // 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 57 // options.share_read_only is true. |path| is populated with the location of
64 // the file before it was unlinked. 58 // the file before it was unlinked.
65 // Returns false if there's an unhandled failure. 59 // Returns false if there's an unhandled failure.
66 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options, 60 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
67 ScopedFILE* fp, 61 ScopedFILE* fp,
68 ScopedFD* readonly_fd, 62 ScopedFD* readonly_fd,
69 FilePath* path) { 63 FilePath* path) {
70 // It doesn't make sense to have a open-existing private piece of shmem 64 // It doesn't make sense to have a open-existing private piece of shmem
(...skipping 28 matching lines...) Expand all
99 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); 93 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
100 if (!readonly_fd->is_valid()) { 94 if (!readonly_fd->is_valid()) {
101 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; 95 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
102 fp->reset(); 96 fp->reset();
103 return false; 97 return false;
104 } 98 }
105 } 99 }
106 } 100 }
107 return true; 101 return true;
108 } 102 }
109 #endif // !defined(OS_ANDROID)
110 } 103 }
111 104
112 SharedMemory::SharedMemory() 105 SharedMemory::SharedMemory()
113 : mapped_file_(-1), 106 : mapped_file_(-1),
114 readonly_mapped_file_(-1), 107 readonly_mapped_file_(-1),
115 mapped_size_(0), 108 mapped_size_(0),
116 memory_(NULL), 109 memory_(NULL),
117 read_only_(false), 110 read_only_(false),
118 requested_size_(0) { 111 requested_size_(0) {
119 } 112 }
120 113
121 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) 114 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
122 : mapped_file_(handle.fd), 115 : mapped_file_(GetFdFromSharedMemoryHandle(handle)),
123 readonly_mapped_file_(-1), 116 readonly_mapped_file_(-1),
124 mapped_size_(0), 117 mapped_size_(0),
125 memory_(NULL), 118 memory_(NULL),
126 read_only_(read_only), 119 read_only_(read_only),
127 requested_size_(0) { 120 requested_size_(0) {
128 } 121 }
129 122
130 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, 123 SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
124 bool read_only,
131 ProcessHandle process) 125 ProcessHandle process)
132 : mapped_file_(handle.fd), 126 : mapped_file_(GetFdFromSharedMemoryHandle(handle)),
133 readonly_mapped_file_(-1), 127 readonly_mapped_file_(-1),
134 mapped_size_(0), 128 mapped_size_(0),
135 memory_(NULL), 129 memory_(NULL),
136 read_only_(read_only), 130 read_only_(read_only),
137 requested_size_(0) { 131 requested_size_(0) {
138 // We don't handle this case yet (note the ignored parameter); let's die if 132 // We don't handle this case yet (note the ignored parameter); let's die if
139 // someone comes calling. 133 // someone comes calling.
140 NOTREACHED(); 134 NOTREACHED();
141 } 135 }
142 136
143 SharedMemory::~SharedMemory() { 137 SharedMemory::~SharedMemory() {
144 Unmap(); 138 Unmap();
145 Close(); 139 Close();
146 } 140 }
147 141
148 // static 142 // static
149 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 143 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
150 return handle.fd >= 0; 144 return GetFdFromSharedMemoryHandle(handle) >= 0;
151 } 145 }
152 146
153 // static 147 // static
154 SharedMemoryHandle SharedMemory::NULLHandle() { 148 SharedMemoryHandle SharedMemory::NULLHandle() {
155 return SharedMemoryHandle(); 149 return SharedMemoryHandle();
156 } 150 }
157 151
158 // static 152 // static
159 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { 153 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
160 DCHECK_GE(handle.fd, 0); 154 DCHECK_GE(GetFdFromSharedMemoryHandle(handle), 0);
161 if (close(handle.fd) < 0) 155 if (close(GetFdFromSharedMemoryHandle(handle)) < 0)
162 DPLOG(ERROR) << "close"; 156 DPLOG(ERROR) << "close";
163 } 157 }
164 158
165 // static 159 // static
166 size_t SharedMemory::GetHandleLimit() { 160 size_t SharedMemory::GetHandleLimit() {
167 return base::GetMaxFds(); 161 return base::GetMaxFds();
168 } 162 }
169 163
170 // static 164 // static
171 SharedMemoryHandle SharedMemory::DuplicateHandle( 165 SharedMemoryHandle SharedMemory::DuplicateHandle(
172 const SharedMemoryHandle& handle) { 166 const SharedMemoryHandle& handle) {
173 int duped_handle = HANDLE_EINTR(dup(handle.fd)); 167 return handle.Duplicate();
174 if (duped_handle < 0)
175 return base::SharedMemory::NULLHandle();
176 return base::FileDescriptor(duped_handle, true);
177 } 168 }
178 169
179 // static 170 // static
180 int SharedMemory::GetFdFromSharedMemoryHandle( 171 int SharedMemory::GetFdFromSharedMemoryHandle(
181 const SharedMemoryHandle& handle) { 172 const SharedMemoryHandle& handle) {
182 return handle.fd; 173 return handle.GetFileDescriptor()->fd;
183 } 174 }
184 175
185 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 176 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
186 return CreateAnonymous(size) && Map(size); 177 return CreateAnonymous(size) && Map(size);
187 } 178 }
188 179
189 #if !defined(OS_ANDROID)
190 // static 180 // static
191 int SharedMemory::GetSizeFromSharedMemoryHandle( 181 int SharedMemory::GetSizeFromSharedMemoryHandle(
192 const SharedMemoryHandle& handle) { 182 const SharedMemoryHandle& handle) {
193 struct stat st; 183 struct stat st;
194 if (fstat(handle.fd, &st) != 0) 184 if (fstat(GetFdFromSharedMemoryHandle(handle), &st) != 0)
195 return -1; 185 return -1;
196 return st.st_size; 186 return st.st_size;
197 } 187 }
198 188
199 // Chromium mostly only uses the unique/private shmem as specified by 189 // Chromium mostly only uses the unique/private shmem as specified by
200 // "name == L"". The exception is in the StatsTable. 190 // "name == L"". The exception is in the StatsTable.
201 // TODO(jrg): there is no way to "clean up" all unused named shmem if 191 // TODO(jrg): there is no way to "clean up" all unused named shmem if
202 // we restart from a crash. (That isn't a new problem, but it is a problem.) 192 // we restart from a crash. (That isn't a new problem, but it is a problem.)
203 // In case we want to delete it later, it may be useful to save the value 193 // In case we want to delete it later, it may be useful to save the value
204 // of mem_filename after FilePathForMemoryName(). 194 // of mem_filename after FilePathForMemoryName().
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 if (fstat(fileno(fp.get()), &stat) != 0) 281 if (fstat(fileno(fp.get()), &stat) != 0)
292 return false; 282 return false;
293 const size_t current_size = stat.st_size; 283 const size_t current_size = stat.st_size;
294 if (current_size != options.size) { 284 if (current_size != options.size) {
295 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0) 285 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
296 return false; 286 return false;
297 } 287 }
298 requested_size_ = options.size; 288 requested_size_ = options.size;
299 } 289 }
300 if (fp == NULL) { 290 if (fp == NULL) {
301 #if !defined(OS_MACOSX)
302 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; 291 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
303 FilePath dir = path.DirName();
304 if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
305 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
306 if (dir.value() == "/dev/shm") {
307 LOG(FATAL) << "This is frequently caused by incorrect permissions on "
308 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
309 }
310 }
311 #else
312 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
313 #endif
314 return false; 292 return false;
315 } 293 }
316 294
317 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); 295 return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
318 } 296 }
319 297
320 // Our current implementation of shmem is with mmap()ing of files. 298 // Our current implementation of shmem is with mmap()ing of files.
321 // These files need to be deleted explicitly. 299 // These files need to be deleted explicitly.
322 // In practice this call is only needed for unit tests. 300 // In practice this call is only needed for unit tests.
323 bool SharedMemory::Delete(const std::string& name) { 301 bool SharedMemory::Delete(const std::string& name) {
(...skipping 17 matching lines...) Expand all
341 319
342 const char *mode = read_only ? "r" : "r+"; 320 const char *mode = read_only ? "r" : "r+";
343 ScopedFILE fp(base::OpenFile(path, mode)); 321 ScopedFILE fp(base::OpenFile(path, mode));
344 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); 322 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
345 if (!readonly_fd.is_valid()) { 323 if (!readonly_fd.is_valid()) {
346 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; 324 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
347 return false; 325 return false;
348 } 326 }
349 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); 327 return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
350 } 328 }
351 #endif // !defined(OS_ANDROID)
352 329
353 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 330 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
354 if (mapped_file_ == -1) 331 if (mapped_file_ == -1)
355 return false; 332 return false;
356 333
357 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 334 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
358 return false; 335 return false;
359 336
360 if (memory_) 337 if (memory_)
361 return false; 338 return false;
362 339
363 #if defined(OS_ANDROID)
364 // On Android, Map can be called with a size and offset of zero to use the
365 // ashmem-determined size.
366 if (bytes == 0) {
367 DCHECK_EQ(0, offset);
368 int ashmem_bytes = ashmem_get_size_region(mapped_file_);
369 if (ashmem_bytes < 0)
370 return false;
371 bytes = ashmem_bytes;
372 }
373 #endif
374
375 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), 340 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
376 MAP_SHARED, mapped_file_, offset); 341 MAP_SHARED, mapped_file_, offset);
377 342
378 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL; 343 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
379 if (mmap_succeeded) { 344 if (mmap_succeeded) {
380 mapped_size_ = bytes; 345 mapped_size_ = bytes;
381 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & 346 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
382 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 347 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
383 } else { 348 } else {
384 memory_ = NULL; 349 memory_ = NULL;
385 } 350 }
386 351
387 return mmap_succeeded; 352 return mmap_succeeded;
388 } 353 }
389 354
390 bool SharedMemory::Unmap() { 355 bool SharedMemory::Unmap() {
391 if (memory_ == NULL) 356 if (memory_ == NULL)
392 return false; 357 return false;
393 358
394 munmap(memory_, mapped_size_); 359 munmap(memory_, mapped_size_);
395 memory_ = NULL; 360 memory_ = NULL;
396 mapped_size_ = 0; 361 mapped_size_ = 0;
397 return true; 362 return true;
398 } 363 }
399 364
400 SharedMemoryHandle SharedMemory::handle() const { 365 SharedMemoryHandle SharedMemory::handle() const {
401 return FileDescriptor(mapped_file_, false); 366 return SharedMemoryHandle(FileDescriptor(mapped_file_, false));
402 } 367 }
403 368
404 void SharedMemory::Close() { 369 void SharedMemory::Close() {
405 if (mapped_file_ > 0) { 370 if (mapped_file_ > 0) {
406 if (close(mapped_file_) < 0) 371 if (close(mapped_file_) < 0)
407 PLOG(ERROR) << "close"; 372 PLOG(ERROR) << "close";
408 mapped_file_ = -1; 373 mapped_file_ = -1;
409 } 374 }
410 if (readonly_mapped_file_ > 0) { 375 if (readonly_mapped_file_ > 0) {
411 if (close(readonly_mapped_file_) < 0) 376 if (close(readonly_mapped_file_) < 0)
412 PLOG(ERROR) << "close"; 377 PLOG(ERROR) << "close";
413 readonly_mapped_file_ = -1; 378 readonly_mapped_file_ = -1;
414 } 379 }
415 } 380 }
416 381
417 void SharedMemory::LockDeprecated() { 382 void SharedMemory::LockDeprecated() {
418 g_thread_lock_.Get().Acquire(); 383 g_thread_lock_.Get().Acquire();
419 LockOrUnlockCommon(F_LOCK); 384 LockOrUnlockCommon(F_LOCK);
420 } 385 }
421 386
422 void SharedMemory::UnlockDeprecated() { 387 void SharedMemory::UnlockDeprecated() {
423 LockOrUnlockCommon(F_ULOCK); 388 LockOrUnlockCommon(F_ULOCK);
424 g_thread_lock_.Get().Release(); 389 g_thread_lock_.Get().Release();
425 } 390 }
426 391
427 #if !defined(OS_ANDROID)
428 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) { 392 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
Nico 2015/06/17 04:03:21 There's a lot of code in this file that's just cop
erikchen 2015/06/17 17:38:55 I don't have a preview to show you, but pretty muc
429 DCHECK_EQ(-1, mapped_file_); 393 DCHECK_EQ(-1, mapped_file_);
430 DCHECK_EQ(-1, readonly_mapped_file_); 394 DCHECK_EQ(-1, readonly_mapped_file_);
431 if (fp == NULL) 395 if (fp == NULL)
432 return false; 396 return false;
433 397
434 // This function theoretically can block on the disk, but realistically 398 // This function theoretically can block on the disk, but realistically
435 // the temporary files we create will just go into the buffer cache 399 // the temporary files we create will just go into the buffer cache
436 // and be deleted before they ever make it out to disk. 400 // and be deleted before they ever make it out to disk.
437 base::ThreadRestrictions::ScopedAllowIO allow_io; 401 base::ThreadRestrictions::ScopedAllowIO allow_io;
438 402
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 FilePath* path) { 434 FilePath* path) {
471 // mem_name will be used for a filename; make sure it doesn't 435 // mem_name will be used for a filename; make sure it doesn't
472 // contain anything which will confuse us. 436 // contain anything which will confuse us.
473 DCHECK_EQ(std::string::npos, mem_name.find('/')); 437 DCHECK_EQ(std::string::npos, mem_name.find('/'));
474 DCHECK_EQ(std::string::npos, mem_name.find('\0')); 438 DCHECK_EQ(std::string::npos, mem_name.find('\0'));
475 439
476 FilePath temp_dir; 440 FilePath temp_dir;
477 if (!GetShmemTempDir(false, &temp_dir)) 441 if (!GetShmemTempDir(false, &temp_dir))
478 return false; 442 return false;
479 443
480 #if !defined(OS_MACOSX)
481 #if defined(GOOGLE_CHROME_BUILD)
482 std::string name_base = std::string("com.google.Chrome");
483 #else
484 std::string name_base = std::string("org.chromium.Chromium");
485 #endif
486 #else // OS_MACOSX
487 std::string name_base = std::string(base::mac::BaseBundleID()); 444 std::string name_base = std::string(base::mac::BaseBundleID());
488 #endif // OS_MACOSX
489 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); 445 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
490 return true; 446 return true;
491 } 447 }
492 #endif // !defined(OS_ANDROID)
493 448
494 void SharedMemory::LockOrUnlockCommon(int function) { 449 void SharedMemory::LockOrUnlockCommon(int function) {
495 DCHECK_GE(mapped_file_, 0); 450 DCHECK_GE(mapped_file_, 0);
496 while (lockf(mapped_file_, function, 0) < 0) { 451 while (lockf(mapped_file_, function, 0) < 0) {
497 if (errno == EINTR) { 452 if (errno == EINTR) {
498 continue; 453 continue;
499 } else if (errno == ENOLCK) { 454 } else if (errno == ENOLCK) {
500 // temporary kernel resource exaustion 455 // temporary kernel resource exaustion
501 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); 456 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
502 continue; 457 continue;
(...skipping 23 matching lines...) Expand all
526 handle_to_dup = readonly_mapped_file_; 481 handle_to_dup = readonly_mapped_file_;
527 break; 482 break;
528 } 483 }
529 484
530 const int new_fd = HANDLE_EINTR(dup(handle_to_dup)); 485 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
531 if (new_fd < 0) { 486 if (new_fd < 0) {
532 DPLOG(ERROR) << "dup() failed."; 487 DPLOG(ERROR) << "dup() failed.";
533 return false; 488 return false;
534 } 489 }
535 490
536 new_handle->fd = new_fd; 491 new_handle->SetFileHandle(new_fd, true);
537 new_handle->auto_close = true;
538 492
539 if (close_self) { 493 if (close_self) {
540 Unmap(); 494 Unmap();
541 Close(); 495 Close();
542 } 496 }
543 497
544 return true; 498 return true;
545 } 499 }
546 500
547 } // namespace base 501 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698