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 <stddef.h> | 9 #include <stddef.h> |
10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
(...skipping 15 matching lines...) Expand all Loading... |
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 : readonly_mapped_file_(-1), | 36 : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {} |
37 mapped_size_(0), | |
38 memory_(NULL), | |
39 read_only_(false), | |
40 requested_size_(0) {} | |
41 | 37 |
42 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) | 38 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) |
43 : shm_(handle), | 39 : shm_(handle), |
44 readonly_mapped_file_(-1), | 40 |
45 mapped_size_(0), | 41 mapped_size_(0), |
46 memory_(NULL), | 42 memory_(NULL), |
47 read_only_(read_only), | 43 read_only_(read_only), |
48 requested_size_(0) {} | 44 requested_size_(0) {} |
49 | 45 |
50 SharedMemory::~SharedMemory() { | 46 SharedMemory::~SharedMemory() { |
51 Unmap(); | 47 Unmap(); |
52 Close(); | 48 Close(); |
53 } | 49 } |
54 | 50 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 "Invalid owner when opening existing shared memory file."; | 162 "Invalid owner when opening existing shared memory file."; |
167 close(fd); | 163 close(fd); |
168 return false; | 164 return false; |
169 } | 165 } |
170 | 166 |
171 // An existing file was opened, so its size should not be fixed. | 167 // An existing file was opened, so its size should not be fixed. |
172 fix_size = false; | 168 fix_size = false; |
173 } | 169 } |
174 | 170 |
175 if (options.share_read_only) { | 171 if (options.share_read_only) { |
176 // Also open as readonly so that we can ShareReadOnlyToProcess. | 172 // Also open as readonly so that we can GetReadOnlyHandle. |
177 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 173 readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
178 if (!readonly_fd.is_valid()) { | 174 if (!readonly_fd.is_valid()) { |
179 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 175 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
180 close(fd); | 176 close(fd); |
181 fd = -1; | 177 fd = -1; |
182 return false; | 178 return false; |
183 } | 179 } |
184 } | 180 } |
185 if (fd >= 0) { | 181 if (fd >= 0) { |
186 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. | 182 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. |
(...skipping 19 matching lines...) Expand all Loading... |
206 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); | 202 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); |
207 if (dir.value() == "/dev/shm") { | 203 if (dir.value() == "/dev/shm") { |
208 LOG(FATAL) << "This is frequently caused by incorrect permissions on " | 204 LOG(FATAL) << "This is frequently caused by incorrect permissions on " |
209 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; | 205 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; |
210 } | 206 } |
211 } | 207 } |
212 return false; | 208 return false; |
213 } | 209 } |
214 | 210 |
215 int mapped_file = -1; | 211 int mapped_file = -1; |
| 212 int readonly_mapped_file = -1; |
216 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), | 213 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), |
217 &mapped_file, &readonly_mapped_file_); | 214 &mapped_file, &readonly_mapped_file); |
218 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); | 215 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); |
| 216 readonly_shm_ = SharedMemoryHandle::ImportHandle(readonly_mapped_file); |
219 return result; | 217 return result; |
220 } | 218 } |
221 | 219 |
222 // Our current implementation of shmem is with mmap()ing of files. | 220 // Our current implementation of shmem is with mmap()ing of files. |
223 // These files need to be deleted explicitly. | 221 // These files need to be deleted explicitly. |
224 // In practice this call is only needed for unit tests. | 222 // In practice this call is only needed for unit tests. |
225 bool SharedMemory::Delete(const std::string& name) { | 223 bool SharedMemory::Delete(const std::string& name) { |
226 FilePath path; | 224 FilePath path; |
227 if (!FilePathForMemoryName(name, &path)) | 225 if (!FilePathForMemoryName(name, &path)) |
228 return false; | 226 return false; |
(...skipping 13 matching lines...) Expand all Loading... |
242 read_only_ = read_only; | 240 read_only_ = read_only; |
243 | 241 |
244 const char *mode = read_only ? "r" : "r+"; | 242 const char *mode = read_only ? "r" : "r+"; |
245 ScopedFILE fp(base::OpenFile(path, mode)); | 243 ScopedFILE fp(base::OpenFile(path, mode)); |
246 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 244 ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
247 if (!readonly_fd.is_valid()) { | 245 if (!readonly_fd.is_valid()) { |
248 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; | 246 DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed"; |
249 return false; | 247 return false; |
250 } | 248 } |
251 int mapped_file = -1; | 249 int mapped_file = -1; |
| 250 int readonly_mapped_file = -1; |
252 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), | 251 bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd), |
253 &mapped_file, &readonly_mapped_file_); | 252 &mapped_file, &readonly_mapped_file); |
254 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); | 253 shm_ = SharedMemoryHandle::ImportHandle(mapped_file); |
| 254 readonly_shm_ = SharedMemoryHandle::ImportHandle(readonly_mapped_file); |
255 return result; | 255 return result; |
256 } | 256 } |
257 #endif // !defined(OS_ANDROID) | 257 #endif // !defined(OS_ANDROID) |
258 | 258 |
259 bool SharedMemory::MapAt(off_t offset, size_t bytes) { | 259 bool SharedMemory::MapAt(off_t offset, size_t bytes) { |
260 if (!shm_.IsValid()) | 260 if (!shm_.IsValid()) |
261 return false; | 261 return false; |
262 | 262 |
263 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) | 263 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) |
264 return false; | 264 return false; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 memory_ = nullptr; | 317 memory_ = nullptr; |
318 mapped_size_ = 0; | 318 mapped_size_ = 0; |
319 return handle_copy; | 319 return handle_copy; |
320 } | 320 } |
321 | 321 |
322 void SharedMemory::Close() { | 322 void SharedMemory::Close() { |
323 if (shm_.IsValid()) { | 323 if (shm_.IsValid()) { |
324 shm_.Close(); | 324 shm_.Close(); |
325 shm_ = SharedMemoryHandle(); | 325 shm_ = SharedMemoryHandle(); |
326 } | 326 } |
327 if (readonly_mapped_file_ > 0) { | 327 if (readonly_shm_.IsValid()) { |
328 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0) | 328 readonly_shm_.Close(); |
329 PLOG(ERROR) << "close"; | 329 readonly_shm_ = SharedMemoryHandle(); |
330 readonly_mapped_file_ = -1; | |
331 } | 330 } |
332 } | 331 } |
333 | 332 |
334 #if !defined(OS_ANDROID) | 333 #if !defined(OS_ANDROID) |
335 // 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() |
336 // (and possibly create). Modifies |filename|. Return false on | 335 // (and possibly create). Modifies |filename|. Return false on |
337 // error, or true of we are happy. | 336 // error, or true of we are happy. |
338 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, | 337 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, |
339 FilePath* path) { | 338 FilePath* path) { |
340 // mem_name will be used for a filename; make sure it doesn't | 339 // mem_name will be used for a filename; make sure it doesn't |
341 // contain anything which will confuse us. | 340 // contain anything which will confuse us. |
342 DCHECK_EQ(std::string::npos, mem_name.find('/')); | 341 DCHECK_EQ(std::string::npos, mem_name.find('/')); |
343 DCHECK_EQ(std::string::npos, mem_name.find('\0')); | 342 DCHECK_EQ(std::string::npos, mem_name.find('\0')); |
344 | 343 |
345 FilePath temp_dir; | 344 FilePath temp_dir; |
346 if (!GetShmemTempDir(false, &temp_dir)) | 345 if (!GetShmemTempDir(false, &temp_dir)) |
347 return false; | 346 return false; |
348 | 347 |
349 #if defined(GOOGLE_CHROME_BUILD) | 348 #if defined(GOOGLE_CHROME_BUILD) |
350 std::string name_base = std::string("com.google.Chrome"); | 349 std::string name_base = std::string("com.google.Chrome"); |
351 #else | 350 #else |
352 std::string name_base = std::string("org.chromium.Chromium"); | 351 std::string name_base = std::string("org.chromium.Chromium"); |
353 #endif | 352 #endif |
354 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); | 353 *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); |
355 return true; | 354 return true; |
356 } | 355 } |
357 #endif // !defined(OS_ANDROID) | 356 #endif // !defined(OS_ANDROID) |
358 | 357 |
| 358 SharedMemoryHandle SharedMemory::GetReadOnlyHandle() { |
| 359 CHECK(readonly_shm_.IsValid()); |
| 360 return readonly_shm_.Duplicate(); |
| 361 } |
| 362 |
359 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, | 363 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, |
360 SharedMemoryHandle* new_handle, | 364 SharedMemoryHandle* new_handle, |
361 bool close_self, | 365 bool close_self) { |
362 ShareMode share_mode) { | 366 *new_handle = shm_.Duplicate(); |
363 int handle_to_dup = -1; | |
364 switch(share_mode) { | |
365 case SHARE_CURRENT_MODE: | |
366 handle_to_dup = shm_.GetHandle(); | |
367 break; | |
368 case SHARE_READONLY: | |
369 // We could imagine re-opening the file from /dev/fd, but that can't make | |
370 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10 | |
371 CHECK_GE(readonly_mapped_file_, 0); | |
372 handle_to_dup = readonly_mapped_file_; | |
373 break; | |
374 } | |
375 | |
376 const int new_fd = HANDLE_EINTR(dup(handle_to_dup)); | |
377 if (new_fd < 0) { | |
378 if (close_self) { | |
379 Unmap(); | |
380 Close(); | |
381 } | |
382 DPLOG(ERROR) << "dup() failed."; | |
383 return false; | |
384 } | |
385 | |
386 new_handle->SetHandle(new_fd); | |
387 new_handle->SetOwnershipPassesToIPC(true); | |
388 | |
389 if (close_self) { | 367 if (close_self) { |
390 Unmap(); | 368 Unmap(); |
391 Close(); | 369 Close(); |
392 } | 370 } |
393 | 371 return new_handle->IsValid(); |
394 return true; | |
395 } | 372 } |
396 | 373 |
397 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { | 374 bool SharedMemory::GetUniqueId(SharedMemory::UniqueId* id) const { |
398 // This function is called just after mmap. fstat is a system call that might | 375 // This function is called just after mmap. fstat is a system call that might |
399 // cause I/O. It's safe to call fstat here because mmap for shared memory is | 376 // cause I/O. It's safe to call fstat here because mmap for shared memory is |
400 // called in two cases: | 377 // called in two cases: |
401 // 1) To handle file-mapped memory | 378 // 1) To handle file-mapped memory |
402 // 2) To handle annonymous shared memory | 379 // 2) To handle annonymous shared memory |
403 // In 1), I/O is already permitted. In 2), the backend is on page cache and | 380 // In 1), I/O is already permitted. In 2), the backend is on page cache and |
404 // fstat doesn't cause I/O access to the disk. See the discussion at | 381 // fstat doesn't cause I/O access to the disk. See the discussion at |
405 // crbug.com/604726#c41. | 382 // crbug.com/604726#c41. |
406 base::ThreadRestrictions::ScopedAllowIO allow_io; | 383 base::ThreadRestrictions::ScopedAllowIO allow_io; |
407 struct stat file_stat; | 384 struct stat file_stat; |
408 if (HANDLE_EINTR( | 385 if (HANDLE_EINTR( |
409 ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0) | 386 ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0) |
410 return false; | 387 return false; |
411 id->first = file_stat.st_dev; | 388 id->first = file_stat.st_dev; |
412 id->second = file_stat.st_ino; | 389 id->second = file_stat.st_ino; |
413 return true; | 390 return true; |
414 } | 391 } |
415 | 392 |
416 } // namespace base | 393 } // namespace base |
OLD | NEW |