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