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

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

Issue 2843113002: make base::SharedMemoryHandle a class on POSIX. (Closed)
Patch Set: Fixes for ChromeOS. Created 3 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
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>
(...skipping 15 matching lines...) Expand all
26 #include "build/build_config.h" 26 #include "build/build_config.h"
27 27
28 #if defined(OS_ANDROID) 28 #if defined(OS_ANDROID)
29 #include "base/os_compat_android.h" 29 #include "base/os_compat_android.h"
30 #include "third_party/ashmem/ashmem.h" 30 #include "third_party/ashmem/ashmem.h"
31 #endif 31 #endif
32 32
33 namespace base { 33 namespace base {
34 34
35 SharedMemory::SharedMemory() 35 SharedMemory::SharedMemory()
36 : mapped_file_(-1), 36 : readonly_mapped_file_(-1),
37 readonly_mapped_file_(-1),
38 mapped_size_(0), 37 mapped_size_(0),
39 memory_(NULL), 38 memory_(NULL),
40 read_only_(false), 39 read_only_(false),
41 requested_size_(0) { 40 requested_size_(0) {}
42 }
43 41
44 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) 42 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
45 : mapped_file_(handle.fd), 43 : shm_(handle),
Nico 2017/04/27 16:24:44 This file seems to ignore shm_.file_descriptor.aut
erikchen 2017/04/27 17:08:10 Yes, that's only used by ipc_message_utils.cc
46 readonly_mapped_file_(-1), 44 readonly_mapped_file_(-1),
47 mapped_size_(0), 45 mapped_size_(0),
48 memory_(NULL), 46 memory_(NULL),
49 read_only_(read_only), 47 read_only_(read_only),
50 requested_size_(0) { 48 requested_size_(0) {}
51 }
52 49
53 SharedMemory::~SharedMemory() { 50 SharedMemory::~SharedMemory() {
54 Unmap(); 51 Unmap();
55 Close(); 52 Close();
56 } 53 }
57 54
58 // static 55 // static
59 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 56 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
60 return handle.fd >= 0; 57 return handle.IsValid();
61 } 58 }
62 59
63 // static 60 // static
64 SharedMemoryHandle SharedMemory::NULLHandle() { 61 SharedMemoryHandle SharedMemory::NULLHandle() {
65 return SharedMemoryHandle(); 62 return SharedMemoryHandle();
66 } 63 }
67 64
68 // static 65 // static
69 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { 66 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
70 DCHECK_GE(handle.fd, 0); 67 DCHECK(handle.IsValid());
71 if (IGNORE_EINTR(close(handle.fd)) < 0) 68 handle.Close();
72 DPLOG(ERROR) << "close";
73 } 69 }
74 70
75 // static 71 // static
76 size_t SharedMemory::GetHandleLimit() { 72 size_t SharedMemory::GetHandleLimit() {
77 return base::GetMaxFds(); 73 return base::GetMaxFds();
78 } 74 }
79 75
80 // static 76 // static
81 SharedMemoryHandle SharedMemory::DuplicateHandle( 77 SharedMemoryHandle SharedMemory::DuplicateHandle(
82 const SharedMemoryHandle& handle) { 78 const SharedMemoryHandle& handle) {
83 int duped_handle = HANDLE_EINTR(dup(handle.fd)); 79 return handle.Duplicate();
84 if (duped_handle < 0)
85 return base::SharedMemory::NULLHandle();
86 return base::FileDescriptor(duped_handle, true);
87 } 80 }
88 81
89 // static 82 // static
90 int SharedMemory::GetFdFromSharedMemoryHandle( 83 int SharedMemory::GetFdFromSharedMemoryHandle(
91 const SharedMemoryHandle& handle) { 84 const SharedMemoryHandle& handle) {
92 return handle.fd; 85 return handle.file_descriptor.fd;
93 } 86 }
94 87
95 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 88 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
96 return CreateAnonymous(size) && Map(size); 89 return CreateAnonymous(size) && Map(size);
97 } 90 }
98 91
99 #if !defined(OS_ANDROID) 92 #if !defined(OS_ANDROID)
100 // static 93 // static
101 bool SharedMemory::GetSizeFromSharedMemoryHandle( 94 bool SharedMemory::GetSizeFromSharedMemoryHandle(
102 const SharedMemoryHandle& handle, 95 const SharedMemoryHandle& handle,
103 size_t* size) { 96 size_t* size) {
104 struct stat st; 97 struct stat st;
105 if (fstat(handle.fd, &st) != 0) 98 if (fstat(handle.file_descriptor.fd, &st) != 0)
106 return false; 99 return false;
107 if (st.st_size < 0) 100 if (st.st_size < 0)
108 return false; 101 return false;
109 *size = st.st_size; 102 *size = st.st_size;
110 return true; 103 return true;
111 } 104 }
112 105
113 // Chromium mostly only uses the unique/private shmem as specified by 106 // Chromium mostly only uses the unique/private shmem as specified by
114 // "name == L"". The exception is in the StatsTable. 107 // "name == L"". The exception is in the StatsTable.
115 // TODO(jrg): there is no way to "clean up" all unused named shmem if 108 // TODO(jrg): there is no way to "clean up" all unused named shmem if
116 // we restart from a crash. (That isn't a new problem, but it is a problem.) 109 // we restart from a crash. (That isn't a new problem, but it is a problem.)
117 // In case we want to delete it later, it may be useful to save the value 110 // In case we want to delete it later, it may be useful to save the value
118 // of mem_filename after FilePathForMemoryName(). 111 // of mem_filename after FilePathForMemoryName().
119 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 112 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
120 DCHECK_EQ(-1, mapped_file_); 113 DCHECK(!shm_.IsValid());
121 if (options.size == 0) return false; 114 if (options.size == 0) return false;
122 115
123 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) 116 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
124 return false; 117 return false;
125 118
126 // This function theoretically can block on the disk, but realistically 119 // This function theoretically can block on the disk, but realistically
127 // the temporary files we create will just go into the buffer cache 120 // the temporary files we create will just go into the buffer cache
128 // and be deleted before they ever make it out to disk. 121 // and be deleted before they ever make it out to disk.
129 base::ThreadRestrictions::ScopedAllowIO allow_io; 122 base::ThreadRestrictions::ScopedAllowIO allow_io;
130 123
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { 210 if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
218 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); 211 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
219 if (dir.value() == "/dev/shm") { 212 if (dir.value() == "/dev/shm") {
220 LOG(FATAL) << "This is frequently caused by incorrect permissions on " 213 LOG(FATAL) << "This is frequently caused by incorrect permissions on "
221 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; 214 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
222 } 215 }
223 } 216 }
224 return false; 217 return false;
225 } 218 }
226 219
227 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_, 220 return PrepareMapFile(std::move(fp), std::move(readonly_fd),
228 &readonly_mapped_file_); 221 &shm_.file_descriptor.fd, &readonly_mapped_file_);
229 } 222 }
230 223
231 // Our current implementation of shmem is with mmap()ing of files. 224 // Our current implementation of shmem is with mmap()ing of files.
232 // These files need to be deleted explicitly. 225 // These files need to be deleted explicitly.
233 // In practice this call is only needed for unit tests. 226 // In practice this call is only needed for unit tests.
234 bool SharedMemory::Delete(const std::string& name) { 227 bool SharedMemory::Delete(const std::string& name) {
235 FilePath path; 228 FilePath path;
236 if (!FilePathForMemoryName(name, &path)) 229 if (!FilePathForMemoryName(name, &path))
237 return false; 230 return false;
238 231
(...skipping 11 matching lines...) Expand all
250 243
251 read_only_ = read_only; 244 read_only_ = read_only;
252 245
253 const char *mode = read_only ? "r" : "r+"; 246 const char *mode = read_only ? "r" : "r+";
254 ScopedFILE fp(base::OpenFile(path, mode)); 247 ScopedFILE fp(base::OpenFile(path, mode));
255 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)));
256 if (!readonly_fd.is_valid()) { 249 if (!readonly_fd.is_valid()) {
257 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; 250 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
258 return false; 251 return false;
259 } 252 }
260 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_, 253 return PrepareMapFile(std::move(fp), std::move(readonly_fd),
261 &readonly_mapped_file_); 254 &shm_.file_descriptor.fd, &readonly_mapped_file_);
262 } 255 }
263 #endif // !defined(OS_ANDROID) 256 #endif // !defined(OS_ANDROID)
264 257
265 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 258 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
266 if (mapped_file_ == -1) 259 if (!shm_.IsValid())
267 return false; 260 return false;
268 261
269 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 262 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
270 return false; 263 return false;
271 264
272 if (memory_) 265 if (memory_)
273 return false; 266 return false;
274 267
275 #if defined(OS_ANDROID) 268 #if defined(OS_ANDROID)
276 // On Android, Map can be called with a size and offset of zero to use the 269 // On Android, Map can be called with a size and offset of zero to use the
277 // ashmem-determined size. 270 // ashmem-determined size.
278 if (bytes == 0) { 271 if (bytes == 0) {
279 DCHECK_EQ(0, offset); 272 DCHECK_EQ(0, offset);
280 int ashmem_bytes = ashmem_get_size_region(mapped_file_); 273 int ashmem_bytes = ashmem_get_size_region(shm_.file_descriptor.fd);
281 if (ashmem_bytes < 0) 274 if (ashmem_bytes < 0)
282 return false; 275 return false;
283 bytes = ashmem_bytes; 276 bytes = ashmem_bytes;
284 } 277 }
285 #endif 278 #endif
286 279
287 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), 280 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
288 MAP_SHARED, mapped_file_, offset); 281 MAP_SHARED, shm_.file_descriptor.fd, offset);
289 282
290 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL; 283 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
291 if (mmap_succeeded) { 284 if (mmap_succeeded) {
292 mapped_size_ = bytes; 285 mapped_size_ = bytes;
293 DCHECK_EQ(0U, 286 DCHECK_EQ(0U,
294 reinterpret_cast<uintptr_t>(memory_) & 287 reinterpret_cast<uintptr_t>(memory_) &
295 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 288 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
296 SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this); 289 SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
297 } else { 290 } else {
298 memory_ = NULL; 291 memory_ = NULL;
299 } 292 }
300 293
301 return mmap_succeeded; 294 return mmap_succeeded;
302 } 295 }
303 296
304 bool SharedMemory::Unmap() { 297 bool SharedMemory::Unmap() {
305 if (memory_ == NULL) 298 if (memory_ == NULL)
306 return false; 299 return false;
307 300
308 munmap(memory_, mapped_size_); 301 munmap(memory_, mapped_size_);
309 SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this); 302 SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
310 memory_ = NULL; 303 memory_ = NULL;
311 mapped_size_ = 0; 304 mapped_size_ = 0;
312 return true; 305 return true;
313 } 306 }
314 307
315 SharedMemoryHandle SharedMemory::handle() const { 308 SharedMemoryHandle SharedMemory::handle() const {
316 return FileDescriptor(mapped_file_, false); 309 return shm_;
317 } 310 }
318 311
319 SharedMemoryHandle SharedMemory::TakeHandle() { 312 SharedMemoryHandle SharedMemory::TakeHandle() {
320 FileDescriptor handle(mapped_file_, true); 313 SharedMemoryHandle handle_copy = shm_;
321 mapped_file_ = -1; 314 handle_copy.file_descriptor.auto_close = true;
315 shm_ = SharedMemoryHandle();
322 memory_ = nullptr; 316 memory_ = nullptr;
323 mapped_size_ = 0; 317 mapped_size_ = 0;
324 return handle; 318 return handle_copy;
325 } 319 }
326 320
327 void SharedMemory::Close() { 321 void SharedMemory::Close() {
328 if (mapped_file_ > 0) { 322 if (shm_.IsValid()) {
329 if (IGNORE_EINTR(close(mapped_file_)) < 0) 323 shm_.Close();
330 PLOG(ERROR) << "close"; 324 shm_ = SharedMemoryHandle();
331 mapped_file_ = -1;
332 } 325 }
333 if (readonly_mapped_file_ > 0) { 326 if (readonly_mapped_file_ > 0) {
334 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0) 327 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
335 PLOG(ERROR) << "close"; 328 PLOG(ERROR) << "close";
336 readonly_mapped_file_ = -1; 329 readonly_mapped_file_ = -1;
337 } 330 }
338 } 331 }
339 332
340 #if !defined(OS_ANDROID) 333 #if !defined(OS_ANDROID)
341 // For the given shmem named |mem_name|, return a filename to mmap() 334 // For the given shmem named |mem_name|, return a filename to mmap()
(...skipping 20 matching lines...) Expand all
362 } 355 }
363 #endif // !defined(OS_ANDROID) 356 #endif // !defined(OS_ANDROID)
364 357
365 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 358 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
366 SharedMemoryHandle* new_handle, 359 SharedMemoryHandle* new_handle,
367 bool close_self, 360 bool close_self,
368 ShareMode share_mode) { 361 ShareMode share_mode) {
369 int handle_to_dup = -1; 362 int handle_to_dup = -1;
370 switch(share_mode) { 363 switch(share_mode) {
371 case SHARE_CURRENT_MODE: 364 case SHARE_CURRENT_MODE:
372 handle_to_dup = mapped_file_; 365 handle_to_dup = shm_.file_descriptor.fd;
373 break; 366 break;
374 case SHARE_READONLY: 367 case SHARE_READONLY:
375 // We could imagine re-opening the file from /dev/fd, but that can't make 368 // We could imagine re-opening the file from /dev/fd, but that can't make
376 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10 369 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
377 CHECK_GE(readonly_mapped_file_, 0); 370 CHECK_GE(readonly_mapped_file_, 0);
378 handle_to_dup = readonly_mapped_file_; 371 handle_to_dup = readonly_mapped_file_;
379 break; 372 break;
380 } 373 }
381 374
382 const int new_fd = HANDLE_EINTR(dup(handle_to_dup)); 375 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
383 if (new_fd < 0) { 376 if (new_fd < 0) {
384 if (close_self) { 377 if (close_self) {
385 Unmap(); 378 Unmap();
386 Close(); 379 Close();
387 } 380 }
388 DPLOG(ERROR) << "dup() failed."; 381 DPLOG(ERROR) << "dup() failed.";
389 return false; 382 return false;
390 } 383 }
391 384
392 new_handle->fd = new_fd; 385 new_handle->file_descriptor.fd = new_fd;
393 new_handle->auto_close = true; 386 new_handle->file_descriptor.auto_close = true;
394 387
395 if (close_self) { 388 if (close_self) {
396 Unmap(); 389 Unmap();
397 Close(); 390 Close();
398 } 391 }
399 392
400 return true; 393 return true;
401 } 394 }
402 395
403 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { 396 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const {
404 // This function is called just after mmap. fstat is a system call that might 397 // This function is called just after mmap. fstat is a system call that might
405 // cause I/O. It's safe to call fstat here because mmap for shared memory is 398 // cause I/O. It's safe to call fstat here because mmap for shared memory is
406 // called in two cases: 399 // called in two cases:
407 // 1) To handle file-mapped memory 400 // 1) To handle file-mapped memory
408 // 2) To handle annonymous shared memory 401 // 2) To handle annonymous shared memory
409 // In 1), I/O is already permitted. In 2), the backend is on page cache and 402 // In 1), I/O is already permitted. In 2), the backend is on page cache and
410 // fstat doesn't cause I/O access to the disk. See the discussion at 403 // fstat doesn't cause I/O access to the disk. See the discussion at
411 // crbug.com/604726#c41. 404 // crbug.com/604726#c41.
412 base::ThreadRestrictions::ScopedAllowIO allow_io; 405 base::ThreadRestrictions::ScopedAllowIO allow_io;
413 struct stat file_stat; 406 struct stat file_stat;
414 if (HANDLE_EINTR(::fstat(static_cast<int>(handle().fd), &file_stat)) != 0) 407 if (HANDLE_EINTR(::fstat(static_cast<int>(handle().file_descriptor.fd),
408 &file_stat)) != 0)
415 return false; 409 return false;
416 id->first = file_stat.st_dev; 410 id->first = file_stat.st_dev;
417 id->second = file_stat.st_ino; 411 id->second = file_stat.st_ino;
418 return true; 412 return true;
419 } 413 }
420 414
421 } // namespace base 415 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698