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

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

Issue 2843113002: make base::SharedMemoryHandle a class on POSIX. (Closed)
Patch Set: Fix test error. Created 3 years, 7 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),
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.GetHandle();
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.GetHandle(), &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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { 205 if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
213 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); 206 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
214 if (dir.value() == "/dev/shm") { 207 if (dir.value() == "/dev/shm") {
215 LOG(FATAL) << "This is frequently caused by incorrect permissions on " 208 LOG(FATAL) << "This is frequently caused by incorrect permissions on "
216 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; 209 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
217 } 210 }
218 } 211 }
219 return false; 212 return false;
220 } 213 }
221 214
222 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_, 215 int mapped_file = -1;
223 &readonly_mapped_file_); 216 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd),
217 &mapped_file, &readonly_mapped_file_);
218 shm_ = SharedMemoryHandle::ImportHandle(mapped_file);
219 return result;
224 } 220 }
225 221
226 // Our current implementation of shmem is with mmap()ing of files. 222 // Our current implementation of shmem is with mmap()ing of files.
227 // These files need to be deleted explicitly. 223 // These files need to be deleted explicitly.
228 // In practice this call is only needed for unit tests. 224 // In practice this call is only needed for unit tests.
229 bool SharedMemory::Delete(const std::string& name) { 225 bool SharedMemory::Delete(const std::string& name) {
230 FilePath path; 226 FilePath path;
231 if (!FilePathForMemoryName(name, &path)) 227 if (!FilePathForMemoryName(name, &path))
232 return false; 228 return false;
233 229
(...skipping 11 matching lines...) Expand all
245 241
246 read_only_ = read_only; 242 read_only_ = read_only;
247 243
248 const char *mode = read_only ? "r" : "r+"; 244 const char *mode = read_only ? "r" : "r+";
249 ScopedFILE fp(base::OpenFile(path, mode)); 245 ScopedFILE fp(base::OpenFile(path, mode));
250 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); 246 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
251 if (!readonly_fd.is_valid()) { 247 if (!readonly_fd.is_valid()) {
252 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; 248 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
253 return false; 249 return false;
254 } 250 }
255 return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_, 251 int mapped_file = -1;
256 &readonly_mapped_file_); 252 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd),
253 &mapped_file, &readonly_mapped_file_);
254 shm_ = SharedMemoryHandle::ImportHandle(mapped_file);
255 return result;
257 } 256 }
258 #endif // !defined(OS_ANDROID) 257 #endif // !defined(OS_ANDROID)
259 258
260 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 259 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
261 if (mapped_file_ == -1) 260 if (!shm_.IsValid())
262 return false; 261 return false;
263 262
264 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 263 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
265 return false; 264 return false;
266 265
267 if (memory_) 266 if (memory_)
268 return false; 267 return false;
269 268
270 #if defined(OS_ANDROID) 269 #if defined(OS_ANDROID)
271 // On Android, Map can be called with a size and offset of zero to use the 270 // On Android, Map can be called with a size and offset of zero to use the
272 // ashmem-determined size. 271 // ashmem-determined size.
273 if (bytes == 0) { 272 if (bytes == 0) {
274 DCHECK_EQ(0, offset); 273 DCHECK_EQ(0, offset);
275 int ashmem_bytes = ashmem_get_size_region(mapped_file_); 274 int ashmem_bytes = ashmem_get_size_region(shm_.GetHandle());
276 if (ashmem_bytes < 0) 275 if (ashmem_bytes < 0)
277 return false; 276 return false;
278 bytes = ashmem_bytes; 277 bytes = ashmem_bytes;
279 } 278 }
280 #endif 279 #endif
281 280
282 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), 281 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
283 MAP_SHARED, mapped_file_, offset); 282 MAP_SHARED, shm_.GetHandle(), offset);
284 283
285 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL; 284 bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
286 if (mmap_succeeded) { 285 if (mmap_succeeded) {
287 mapped_size_ = bytes; 286 mapped_size_ = bytes;
288 DCHECK_EQ(0U, 287 DCHECK_EQ(0U,
289 reinterpret_cast<uintptr_t>(memory_) & 288 reinterpret_cast<uintptr_t>(memory_) &
290 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 289 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
291 SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this); 290 SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
292 } else { 291 } else {
293 memory_ = NULL; 292 memory_ = NULL;
294 } 293 }
295 294
296 return mmap_succeeded; 295 return mmap_succeeded;
297 } 296 }
298 297
299 bool SharedMemory::Unmap() { 298 bool SharedMemory::Unmap() {
300 if (memory_ == NULL) 299 if (memory_ == NULL)
301 return false; 300 return false;
302 301
303 munmap(memory_, mapped_size_); 302 munmap(memory_, mapped_size_);
304 SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this); 303 SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
305 memory_ = NULL; 304 memory_ = NULL;
306 mapped_size_ = 0; 305 mapped_size_ = 0;
307 return true; 306 return true;
308 } 307 }
309 308
310 SharedMemoryHandle SharedMemory::handle() const { 309 SharedMemoryHandle SharedMemory::handle() const {
311 return FileDescriptor(mapped_file_, false); 310 return shm_;
312 } 311 }
313 312
314 SharedMemoryHandle SharedMemory::TakeHandle() { 313 SharedMemoryHandle SharedMemory::TakeHandle() {
315 FileDescriptor handle(mapped_file_, true); 314 SharedMemoryHandle handle_copy = shm_;
316 mapped_file_ = -1; 315 handle_copy.SetOwnershipPassesToIPC(true);
316 shm_ = SharedMemoryHandle();
317 memory_ = nullptr; 317 memory_ = nullptr;
318 mapped_size_ = 0; 318 mapped_size_ = 0;
319 return handle; 319 return handle_copy;
320 } 320 }
321 321
322 void SharedMemory::Close() { 322 void SharedMemory::Close() {
323 if (mapped_file_ > 0) { 323 if (shm_.IsValid()) {
324 if (IGNORE_EINTR(close(mapped_file_)) < 0) 324 shm_.Close();
325 PLOG(ERROR) << "close"; 325 shm_ = SharedMemoryHandle();
326 mapped_file_ = -1;
327 } 326 }
328 if (readonly_mapped_file_ > 0) { 327 if (readonly_mapped_file_ > 0) {
329 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0) 328 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
330 PLOG(ERROR) << "close"; 329 PLOG(ERROR) << "close";
331 readonly_mapped_file_ = -1; 330 readonly_mapped_file_ = -1;
332 } 331 }
333 } 332 }
334 333
335 #if !defined(OS_ANDROID) 334 #if !defined(OS_ANDROID)
336 // For the given shmem named |mem_name|, return a filename to mmap() 335 // For the given shmem named |mem_name|, return a filename to mmap()
(...skipping 20 matching lines...) Expand all
357 } 356 }
358 #endif // !defined(OS_ANDROID) 357 #endif // !defined(OS_ANDROID)
359 358
360 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 359 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
361 SharedMemoryHandle* new_handle, 360 SharedMemoryHandle* new_handle,
362 bool close_self, 361 bool close_self,
363 ShareMode share_mode) { 362 ShareMode share_mode) {
364 int handle_to_dup = -1; 363 int handle_to_dup = -1;
365 switch(share_mode) { 364 switch(share_mode) {
366 case SHARE_CURRENT_MODE: 365 case SHARE_CURRENT_MODE:
367 handle_to_dup = mapped_file_; 366 handle_to_dup = shm_.GetHandle();
368 break; 367 break;
369 case SHARE_READONLY: 368 case SHARE_READONLY:
370 // We could imagine re-opening the file from /dev/fd, but that can't make 369 // We could imagine re-opening the file from /dev/fd, but that can't make
371 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10 370 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
372 CHECK_GE(readonly_mapped_file_, 0); 371 CHECK_GE(readonly_mapped_file_, 0);
373 handle_to_dup = readonly_mapped_file_; 372 handle_to_dup = readonly_mapped_file_;
374 break; 373 break;
375 } 374 }
376 375
377 const int new_fd = HANDLE_EINTR(dup(handle_to_dup)); 376 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
378 if (new_fd < 0) { 377 if (new_fd < 0) {
379 if (close_self) { 378 if (close_self) {
380 Unmap(); 379 Unmap();
381 Close(); 380 Close();
382 } 381 }
383 DPLOG(ERROR) << "dup() failed."; 382 DPLOG(ERROR) << "dup() failed.";
384 return false; 383 return false;
385 } 384 }
386 385
387 new_handle->fd = new_fd; 386 new_handle->SetHandle(new_fd);
388 new_handle->auto_close = true; 387 new_handle->SetOwnershipPassesToIPC(true);
389 388
390 if (close_self) { 389 if (close_self) {
391 Unmap(); 390 Unmap();
392 Close(); 391 Close();
393 } 392 }
394 393
395 return true; 394 return true;
396 } 395 }
397 396
398 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { 397 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const {
399 // This function is called just after mmap. fstat is a system call that might 398 // This function is called just after mmap. fstat is a system call that might
400 // cause I/O. It's safe to call fstat here because mmap for shared memory is 399 // cause I/O. It's safe to call fstat here because mmap for shared memory is
401 // called in two cases: 400 // called in two cases:
402 // 1) To handle file-mapped memory 401 // 1) To handle file-mapped memory
403 // 2) To handle annonymous shared memory 402 // 2) To handle annonymous shared memory
404 // In 1), I/O is already permitted. In 2), the backend is on page cache and 403 // In 1), I/O is already permitted. In 2), the backend is on page cache and
405 // fstat doesn't cause I/O access to the disk. See the discussion at 404 // fstat doesn't cause I/O access to the disk. See the discussion at
406 // crbug.com/604726#c41. 405 // crbug.com/604726#c41.
407 base::ThreadRestrictions::ScopedAllowIO allow_io; 406 base::ThreadRestrictions::ScopedAllowIO allow_io;
408 struct stat file_stat; 407 struct stat file_stat;
409 if (HANDLE_EINTR(::fstat(static_cast<int>(handle().fd), &file_stat)) != 0) 408 if (HANDLE_EINTR(
409 ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0)
410 return false; 410 return false;
411 id->first = file_stat.st_dev; 411 id->first = file_stat.st_dev;
412 id->second = file_stat.st_ino; 412 id->second = file_stat.st_ino;
413 return true; 413 return true;
414 } 414 }
415 415
416 } // namespace base 416 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698