OLD | NEW |
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 12 matching lines...) Expand all Loading... |
23 | 23 |
24 #if defined(OS_MACOSX) | 24 #if defined(OS_MACOSX) |
25 #include "base/mac/foundation_util.h" | 25 #include "base/mac/foundation_util.h" |
26 #endif // OS_MACOSX | 26 #endif // OS_MACOSX |
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 using file_util::ScopedFD; | |
34 using file_util::ScopedFILE; | 33 using file_util::ScopedFILE; |
35 | 34 |
36 namespace base { | 35 namespace base { |
37 | 36 |
38 namespace { | 37 namespace { |
39 | 38 |
40 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; | 39 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; |
41 | 40 |
42 } | 41 } |
43 | 42 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) | 124 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) |
126 return false; | 125 return false; |
127 | 126 |
128 // This function theoretically can block on the disk, but realistically | 127 // This function theoretically can block on the disk, but realistically |
129 // the temporary files we create will just go into the buffer cache | 128 // the temporary files we create will just go into the buffer cache |
130 // and be deleted before they ever make it out to disk. | 129 // and be deleted before they ever make it out to disk. |
131 base::ThreadRestrictions::ScopedAllowIO allow_io; | 130 base::ThreadRestrictions::ScopedAllowIO allow_io; |
132 | 131 |
133 ScopedFILE fp; | 132 ScopedFILE fp; |
134 bool fix_size = true; | 133 bool fix_size = true; |
135 int readonly_fd_storage = -1; | 134 ScopedFD readonly_fd; |
136 ScopedFD readonly_fd(&readonly_fd_storage); | |
137 | 135 |
138 FilePath path; | 136 FilePath path; |
139 if (options.name_deprecated == NULL || options.name_deprecated->empty()) { | 137 if (options.name_deprecated == NULL || options.name_deprecated->empty()) { |
140 // It doesn't make sense to have a open-existing private piece of shmem | 138 // It doesn't make sense to have a open-existing private piece of shmem |
141 DCHECK(!options.open_existing_deprecated); | 139 DCHECK(!options.open_existing_deprecated); |
142 // Q: Why not use the shm_open() etc. APIs? | 140 // Q: Why not use the shm_open() etc. APIs? |
143 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU | 141 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU |
144 fp.reset(base::CreateAndOpenTemporaryShmemFile(&path, options.executable)); | 142 fp.reset(base::CreateAndOpenTemporaryShmemFile(&path, options.executable)); |
145 | 143 |
146 if (fp) { | 144 if (fp) { |
147 // Also open as readonly so that we can ShareReadOnlyToProcess. | 145 // Also open as readonly so that we can ShareReadOnlyToProcess. |
148 *readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)); | 146 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
149 if (*readonly_fd < 0) { | 147 if (!readonly_fd.is_valid()) { |
150 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 148 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
151 fp.reset(); | 149 fp.reset(); |
152 } | 150 } |
153 // Deleting the file prevents anyone else from mapping it in (making it | 151 // Deleting the file prevents anyone else from mapping it in (making it |
154 // private), and prevents the need for cleanup (once the last fd is | 152 // private), and prevents the need for cleanup (once the last fd is |
155 // closed, it is truly freed). | 153 // closed, it is truly freed). |
156 if (unlink(path.value().c_str())) | 154 if (unlink(path.value().c_str())) |
157 PLOG(WARNING) << "unlink"; | 155 PLOG(WARNING) << "unlink"; |
158 } | 156 } |
159 } else { | 157 } else { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 "Invalid owner when opening existing shared memory file."; | 189 "Invalid owner when opening existing shared memory file."; |
192 close(fd); | 190 close(fd); |
193 return false; | 191 return false; |
194 } | 192 } |
195 | 193 |
196 // An existing file was opened, so its size should not be fixed. | 194 // An existing file was opened, so its size should not be fixed. |
197 fix_size = false; | 195 fix_size = false; |
198 } | 196 } |
199 | 197 |
200 // Also open as readonly so that we can ShareReadOnlyToProcess. | 198 // Also open as readonly so that we can ShareReadOnlyToProcess. |
201 *readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)); | 199 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
202 if (*readonly_fd < 0) { | 200 if (!readonly_fd.is_valid()) { |
203 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 201 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
204 close(fd); | 202 close(fd); |
205 fd = -1; | 203 fd = -1; |
206 } | 204 } |
207 if (fd >= 0) { | 205 if (fd >= 0) { |
208 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. | 206 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. |
209 fp.reset(fdopen(fd, "a+")); | 207 fp.reset(fdopen(fd, "a+")); |
210 } | 208 } |
211 } | 209 } |
212 if (fp && fix_size) { | 210 if (fp && fix_size) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 | 256 |
259 bool SharedMemory::Open(const std::string& name, bool read_only) { | 257 bool SharedMemory::Open(const std::string& name, bool read_only) { |
260 FilePath path; | 258 FilePath path; |
261 if (!FilePathForMemoryName(name, &path)) | 259 if (!FilePathForMemoryName(name, &path)) |
262 return false; | 260 return false; |
263 | 261 |
264 read_only_ = read_only; | 262 read_only_ = read_only; |
265 | 263 |
266 const char *mode = read_only ? "r" : "r+"; | 264 const char *mode = read_only ? "r" : "r+"; |
267 ScopedFILE fp(base::OpenFile(path, mode)); | 265 ScopedFILE fp(base::OpenFile(path, mode)); |
268 int readonly_fd_storage = -1; | 266 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
269 ScopedFD readonly_fd(&readonly_fd_storage); | 267 if (!readonly_fd.is_valid()) { |
270 *readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)); | |
271 if (*readonly_fd < 0) { | |
272 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 268 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
273 } | 269 } |
274 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); | 270 return PrepareMapFile(fp.Pass(), readonly_fd.Pass()); |
275 } | 271 } |
276 | 272 |
277 #endif // !defined(OS_ANDROID) | 273 #endif // !defined(OS_ANDROID) |
278 | 274 |
279 bool SharedMemory::MapAt(off_t offset, size_t bytes) { | 275 bool SharedMemory::MapAt(off_t offset, size_t bytes) { |
280 if (mapped_file_ == -1) | 276 if (mapped_file_ == -1) |
281 return false; | 277 return false; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 | 342 |
347 void SharedMemory::UnlockDeprecated() { | 343 void SharedMemory::UnlockDeprecated() { |
348 LockOrUnlockCommon(F_ULOCK); | 344 LockOrUnlockCommon(F_ULOCK); |
349 g_thread_lock_.Get().Release(); | 345 g_thread_lock_.Get().Release(); |
350 } | 346 } |
351 | 347 |
352 #if !defined(OS_ANDROID) | 348 #if !defined(OS_ANDROID) |
353 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) { | 349 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) { |
354 DCHECK_EQ(-1, mapped_file_); | 350 DCHECK_EQ(-1, mapped_file_); |
355 DCHECK_EQ(-1, readonly_mapped_file_); | 351 DCHECK_EQ(-1, readonly_mapped_file_); |
356 if (fp == NULL || *readonly_fd < 0) return false; | 352 if (fp == NULL || !readonly_fd.is_valid()) return false; |
357 | 353 |
358 // This function theoretically can block on the disk, but realistically | 354 // This function theoretically can block on the disk, but realistically |
359 // the temporary files we create will just go into the buffer cache | 355 // the temporary files we create will just go into the buffer cache |
360 // and be deleted before they ever make it out to disk. | 356 // and be deleted before they ever make it out to disk. |
361 base::ThreadRestrictions::ScopedAllowIO allow_io; | 357 base::ThreadRestrictions::ScopedAllowIO allow_io; |
362 | 358 |
363 struct stat st = {}; | 359 struct stat st = {}; |
364 struct stat readonly_st = {}; | 360 struct stat readonly_st = {}; |
365 if (fstat(fileno(fp.get()), &st)) | 361 if (fstat(fileno(fp.get()), &st)) |
366 NOTREACHED(); | 362 NOTREACHED(); |
367 if (fstat(*readonly_fd, &readonly_st)) | 363 if (fstat(readonly_fd.get(), &readonly_st)) |
368 NOTREACHED(); | 364 NOTREACHED(); |
369 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { | 365 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { |
370 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; | 366 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; |
371 return false; | 367 return false; |
372 } | 368 } |
373 | 369 |
374 mapped_file_ = dup(fileno(fp.get())); | 370 mapped_file_ = dup(fileno(fp.get())); |
375 if (mapped_file_ == -1) { | 371 if (mapped_file_ == -1) { |
376 if (errno == EMFILE) { | 372 if (errno == EMFILE) { |
377 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; | 373 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; |
378 return false; | 374 return false; |
379 } else { | 375 } else { |
380 NOTREACHED() << "Call to dup failed, errno=" << errno; | 376 NOTREACHED() << "Call to dup failed, errno=" << errno; |
381 } | 377 } |
382 } | 378 } |
383 inode_ = st.st_ino; | 379 inode_ = st.st_ino; |
384 readonly_mapped_file_ = *readonly_fd.release(); | 380 readonly_mapped_file_ = readonly_fd.release(); |
385 | 381 |
386 return true; | 382 return true; |
387 } | 383 } |
388 #endif | 384 #endif |
389 | 385 |
390 // For the given shmem named |mem_name|, return a filename to mmap() | 386 // For the given shmem named |mem_name|, return a filename to mmap() |
391 // (and possibly create). Modifies |filename|. Return false on | 387 // (and possibly create). Modifies |filename|. Return false on |
392 // error, or true of we are happy. | 388 // error, or true of we are happy. |
393 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, | 389 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, |
394 FilePath* path) { | 390 FilePath* path) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 new_handle->fd = new_fd; | 455 new_handle->fd = new_fd; |
460 new_handle->auto_close = true; | 456 new_handle->auto_close = true; |
461 | 457 |
462 if (close_self) | 458 if (close_self) |
463 Close(); | 459 Close(); |
464 | 460 |
465 return true; | 461 return true; |
466 } | 462 } |
467 | 463 |
468 } // namespace base | 464 } // namespace base |
OLD | NEW |