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

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

Issue 27265002: Implement SharedMemory::NewAnonymousReadOnly(contents). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Leave the handle writable on Android Created 7 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « base/memory/shared_memory_nacl.cc ('k') | base/memory/shared_memory_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <sys/mman.h> 9 #include <sys/mman.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
(...skipping 12 matching lines...) Expand all
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;
35
33 namespace base { 36 namespace base {
34 37
35 namespace { 38 namespace {
36 39
37 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; 40 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
38 41
39 } 42 }
40 43
41 SharedMemory::SharedMemory() 44 SharedMemory::SharedMemory()
42 : mapped_file_(-1), 45 : mapped_file_(-1),
46 readonly_mapped_file_(-1),
43 inode_(0), 47 inode_(0),
44 mapped_size_(0), 48 mapped_size_(0),
45 memory_(NULL), 49 memory_(NULL),
46 read_only_(false), 50 read_only_(false),
47 requested_size_(0) { 51 requested_size_(0) {
48 } 52 }
49 53
50 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) 54 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
51 : mapped_file_(handle.fd), 55 : mapped_file_(handle.fd),
56 readonly_mapped_file_(-1),
52 inode_(0), 57 inode_(0),
53 mapped_size_(0), 58 mapped_size_(0),
54 memory_(NULL), 59 memory_(NULL),
55 read_only_(read_only), 60 read_only_(read_only),
56 requested_size_(0) { 61 requested_size_(0) {
57 struct stat st; 62 struct stat st;
58 if (fstat(handle.fd, &st) == 0) { 63 if (fstat(handle.fd, &st) == 0) {
59 // If fstat fails, then the file descriptor is invalid and we'll learn this 64 // If fstat fails, then the file descriptor is invalid and we'll learn this
60 // fact when Map() fails. 65 // fact when Map() fails.
61 inode_ = st.st_ino; 66 inode_ = st.st_ino;
62 } 67 }
63 } 68 }
64 69
65 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, 70 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
66 ProcessHandle process) 71 ProcessHandle process)
67 : mapped_file_(handle.fd), 72 : mapped_file_(handle.fd),
73 readonly_mapped_file_(-1),
68 inode_(0), 74 inode_(0),
69 mapped_size_(0), 75 mapped_size_(0),
70 memory_(NULL), 76 memory_(NULL),
71 read_only_(read_only), 77 read_only_(read_only),
72 requested_size_(0) { 78 requested_size_(0) {
73 // We don't handle this case yet (note the ignored parameter); let's die if 79 // We don't handle this case yet (note the ignored parameter); let's die if
74 // someone comes calling. 80 // someone comes calling.
75 NOTREACHED(); 81 NOTREACHED();
76 } 82 }
77 83
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 if (options.size == 0) return false; 123 if (options.size == 0) return false;
118 124
119 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()))
120 return false; 126 return false;
121 127
122 // This function theoretically can block on the disk, but realistically 128 // This function theoretically can block on the disk, but realistically
123 // 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
124 // and be deleted before they ever make it out to disk. 130 // and be deleted before they ever make it out to disk.
125 base::ThreadRestrictions::ScopedAllowIO allow_io; 131 base::ThreadRestrictions::ScopedAllowIO allow_io;
126 132
127 FILE *fp; 133 ScopedFILE fp;
128 bool fix_size = true; 134 bool fix_size = true;
135 int readonly_fd_storage = -1;
136 ScopedFD readonly_fd(&readonly_fd_storage);
129 137
130 FilePath path; 138 FilePath path;
131 if (options.name == NULL || options.name->empty()) { 139 if (options.name == NULL || options.name->empty()) {
132 // 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
133 DCHECK(!options.open_existing); 141 DCHECK(!options.open_existing);
134 // Q: Why not use the shm_open() etc. APIs? 142 // Q: Why not use the shm_open() etc. APIs?
135 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU 143 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
136 fp = file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable); 144 fp.reset(
145 file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable));
137 146
138 // Deleting the file prevents anyone else from mapping it in (making it
139 // private), and prevents the need for cleanup (once the last fd is closed,
140 // it is truly freed).
141 if (fp) { 147 if (fp) {
148 // Also open as readonly so that we can ShareReadOnlyToProcess.
149 *readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY));
150 if (*readonly_fd < 0) {
151 DPLOG(ERROR) << "open(\"" << path.value().c_str()
152 << "\", O_RDONLY) failed";
153 fp.reset();
154 }
155 // Deleting the file prevents anyone else from mapping it in (making it
156 // private), and prevents the need for cleanup (once the last fd is
157 // closed,
Mark Mentovai 2013/11/20 14:21:41 Reflow this comment, this word doesn’t need to be
Jeffrey Yasskin 2013/11/20 18:02:09 Done.
158 // it is truly freed).
142 if (unlink(path.value().c_str())) 159 if (unlink(path.value().c_str()))
143 PLOG(WARNING) << "unlink"; 160 PLOG(WARNING) << "unlink";
144 } 161 }
145 } else { 162 } else {
146 if (!FilePathForMemoryName(*options.name, &path)) 163 if (!FilePathForMemoryName(*options.name, &path))
147 return false; 164 return false;
148 165
149 // Make sure that the file is opened without any permission 166 // Make sure that the file is opened without any permission
150 // to other users on the system. 167 // to other users on the system.
151 const mode_t kOwnerOnly = S_IRUSR | S_IWUSR; 168 const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
(...skipping 23 matching lines...) Expand all
175 sb.st_uid != effective_uid)) { 192 sb.st_uid != effective_uid)) {
176 LOG(ERROR) << 193 LOG(ERROR) <<
177 "Invalid owner when opening existing shared memory file."; 194 "Invalid owner when opening existing shared memory file.";
178 HANDLE_EINTR(close(fd)); 195 HANDLE_EINTR(close(fd));
179 return false; 196 return false;
180 } 197 }
181 198
182 // An existing file was opened, so its size should not be fixed. 199 // An existing file was opened, so its size should not be fixed.
183 fix_size = false; 200 fix_size = false;
184 } 201 }
185 fp = NULL; 202
203 // Also open as readonly so that we can ShareReadOnlyToProcess.
204 *readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY));
205 if (*readonly_fd < 0) {
206 DPLOG(ERROR) << "open(\"" << path.value().c_str()
207 << "\", O_RDONLY) failed";
208 HANDLE_EINTR(close(fd));
209 fd = -1;
210 }
186 if (fd >= 0) { 211 if (fd >= 0) {
187 // "a+" is always appropriate: if it's a new file, a+ is similar to w+. 212 // "a+" is always appropriate: if it's a new file, a+ is similar to w+.
188 fp = fdopen(fd, "a+"); 213 fp.reset(fdopen(fd, "a+"));
189 } 214 }
190 } 215 }
191 if (fp && fix_size) { 216 if (fp && fix_size) {
192 // Get current size. 217 // Get current size.
193 struct stat stat; 218 struct stat stat;
194 if (fstat(fileno(fp), &stat) != 0) { 219 if (fstat(fileno(fp.get()), &stat) != 0)
195 file_util::CloseFile(fp);
196 return false; 220 return false;
197 }
198 const size_t current_size = stat.st_size; 221 const size_t current_size = stat.st_size;
199 if (current_size != options.size) { 222 if (current_size != options.size) {
200 if (HANDLE_EINTR(ftruncate(fileno(fp), options.size)) != 0) { 223 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
201 file_util::CloseFile(fp);
202 return false; 224 return false;
203 }
204 } 225 }
205 requested_size_ = options.size; 226 requested_size_ = options.size;
206 } 227 }
207 if (fp == NULL) { 228 if (fp == NULL) {
208 #if !defined(OS_MACOSX) 229 #if !defined(OS_MACOSX)
209 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; 230 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
210 FilePath dir = path.DirName(); 231 FilePath dir = path.DirName();
211 if (access(dir.value().c_str(), W_OK | X_OK) < 0) { 232 if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
212 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); 233 PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
213 if (dir.value() == "/dev/shm") { 234 if (dir.value() == "/dev/shm") {
214 LOG(FATAL) << "This is frequently caused by incorrect permissions on " 235 LOG(FATAL) << "This is frequently caused by incorrect permissions on "
215 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; 236 << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
216 } 237 }
217 } 238 }
218 #else 239 #else
219 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; 240 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
220 #endif 241 #endif
221 return false; 242 return false;
222 } 243 }
223 244
224 return PrepareMapFile(fp); 245 return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
225 } 246 }
226 247
227 // Our current implementation of shmem is with mmap()ing of files. 248 // Our current implementation of shmem is with mmap()ing of files.
228 // These files need to be deleted explicitly. 249 // These files need to be deleted explicitly.
229 // In practice this call is only needed for unit tests. 250 // In practice this call is only needed for unit tests.
230 bool SharedMemory::Delete(const std::string& name) { 251 bool SharedMemory::Delete(const std::string& name) {
231 FilePath path; 252 FilePath path;
232 if (!FilePathForMemoryName(name, &path)) 253 if (!FilePathForMemoryName(name, &path))
233 return false; 254 return false;
234 255
235 if (PathExists(path)) 256 if (PathExists(path))
236 return base::DeleteFile(path, false); 257 return base::DeleteFile(path, false);
237 258
238 // Doesn't exist, so success. 259 // Doesn't exist, so success.
239 return true; 260 return true;
240 } 261 }
241 262
242 bool SharedMemory::Open(const std::string& name, bool read_only) { 263 bool SharedMemory::Open(const std::string& name, bool read_only) {
243 FilePath path; 264 FilePath path;
244 if (!FilePathForMemoryName(name, &path)) 265 if (!FilePathForMemoryName(name, &path))
245 return false; 266 return false;
246 267
247 read_only_ = read_only; 268 read_only_ = read_only;
248 269
249 const char *mode = read_only ? "r" : "r+"; 270 const char *mode = read_only ? "r" : "r+";
250 FILE *fp = file_util::OpenFile(path, mode); 271 ScopedFILE fp(file_util::OpenFile(path, mode));
251 return PrepareMapFile(fp); 272 int readonly_fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY));
273 if (readonly_fd < 0) {
274 DPLOG(ERROR) << "open(\"" << path.value().c_str() << "\", O_RDONLY) failed";
275 }
276 return PrepareMapFile(fp.Pass(), ScopedFD(&readonly_fd));
Mark Mentovai 2013/11/20 14:21:41 Move the ScopedFD up (like you did above) to bette
Jeffrey Yasskin 2013/11/20 18:02:09 Done.
252 } 277 }
253 278
254 #endif // !defined(OS_ANDROID) 279 #endif // !defined(OS_ANDROID)
255 280
256 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 281 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
257 if (mapped_file_ == -1) 282 if (mapped_file_ == -1)
258 return false; 283 return false;
259 284
260 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 285 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
261 return false; 286 return false;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 } 327 }
303 328
304 void SharedMemory::Close() { 329 void SharedMemory::Close() {
305 Unmap(); 330 Unmap();
306 331
307 if (mapped_file_ > 0) { 332 if (mapped_file_ > 0) {
308 if (HANDLE_EINTR(close(mapped_file_)) < 0) 333 if (HANDLE_EINTR(close(mapped_file_)) < 0)
309 PLOG(ERROR) << "close"; 334 PLOG(ERROR) << "close";
310 mapped_file_ = -1; 335 mapped_file_ = -1;
311 } 336 }
337 if (readonly_mapped_file_ > 0) {
338 if (HANDLE_EINTR(close(readonly_mapped_file_)) < 0)
Mark Mentovai 2013/11/20 14:21:41 I have determined that it’s never correct to HANDL
Jeffrey Yasskin 2013/11/20 18:02:09 Oh, ok; done. It was very slightly easier to unwra
339 PLOG(ERROR) << "close";
340 readonly_mapped_file_ = -1;
341 }
312 } 342 }
313 343
314 void SharedMemory::Lock() { 344 void SharedMemory::Lock() {
315 g_thread_lock_.Get().Acquire(); 345 g_thread_lock_.Get().Acquire();
316 LockOrUnlockCommon(F_LOCK); 346 LockOrUnlockCommon(F_LOCK);
317 } 347 }
318 348
319 void SharedMemory::Unlock() { 349 void SharedMemory::Unlock() {
320 LockOrUnlockCommon(F_ULOCK); 350 LockOrUnlockCommon(F_ULOCK);
321 g_thread_lock_.Get().Release(); 351 g_thread_lock_.Get().Release();
322 } 352 }
323 353
324 #if !defined(OS_ANDROID) 354 #if !defined(OS_ANDROID)
325 bool SharedMemory::PrepareMapFile(FILE *fp) { 355 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
326 DCHECK_EQ(-1, mapped_file_); 356 DCHECK_EQ(-1, mapped_file_);
327 if (fp == NULL) return false; 357 DCHECK_EQ(-1, readonly_mapped_file_);
358 if (fp == NULL || *readonly_fd < 0) return false;
328 359
329 // This function theoretically can block on the disk, but realistically 360 // This function theoretically can block on the disk, but realistically
330 // the temporary files we create will just go into the buffer cache 361 // the temporary files we create will just go into the buffer cache
331 // and be deleted before they ever make it out to disk. 362 // and be deleted before they ever make it out to disk.
332 base::ThreadRestrictions::ScopedAllowIO allow_io; 363 base::ThreadRestrictions::ScopedAllowIO allow_io;
333 364
334 file_util::ScopedFILE file_closer(fp); 365 struct stat st;
366 struct stat readonly_st;
367 if (fstat(fileno(fp.get()), &st))
368 NOTREACHED();
369 if (fstat(*readonly_fd, &readonly_st))
370 NOTREACHED();
371 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
372 LOG(ERROR) << "writable and read-only inodes don't match; bailing";
373 return false;
374 }
335 375
336 mapped_file_ = dup(fileno(fp)); 376 mapped_file_ = dup(fileno(fp.get()));
337 if (mapped_file_ == -1) { 377 if (mapped_file_ == -1) {
338 if (errno == EMFILE) { 378 if (errno == EMFILE) {
339 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; 379 LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
340 return false; 380 return false;
341 } else { 381 } else {
342 NOTREACHED() << "Call to dup failed, errno=" << errno; 382 NOTREACHED() << "Call to dup failed, errno=" << errno;
343 } 383 }
344 } 384 }
345
346 struct stat st;
347 if (fstat(mapped_file_, &st))
348 NOTREACHED();
349 inode_ = st.st_ino; 385 inode_ = st.st_ino;
386 readonly_mapped_file_ = *readonly_fd.release();
350 387
351 return true; 388 return true;
352 } 389 }
353 #endif 390 #endif
354 391
355 // For the given shmem named |mem_name|, return a filename to mmap() 392 // For the given shmem named |mem_name|, return a filename to mmap()
356 // (and possibly create). Modifies |filename|. Return false on 393 // (and possibly create). Modifies |filename|. Return false on
357 // error, or true of we are happy. 394 // error, or true of we are happy.
358 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, 395 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
359 FilePath* path) { 396 FilePath* path) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 NOTREACHED() << "lockf() failed." 429 NOTREACHED() << "lockf() failed."
393 << " function:" << function 430 << " function:" << function
394 << " fd:" << mapped_file_ 431 << " fd:" << mapped_file_
395 << " errno:" << errno 432 << " errno:" << errno
396 << " msg:" << safe_strerror(errno); 433 << " msg:" << safe_strerror(errno);
397 } 434 }
398 } 435 }
399 } 436 }
400 437
401 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 438 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
402 SharedMemoryHandle *new_handle, 439 SharedMemoryHandle* new_handle,
403 bool close_self) { 440 bool close_self,
404 const int new_fd = dup(mapped_file_); 441 ShareMode share_mode) {
442 int handle_to_dup = -1;
443 switch(share_mode) {
444 case SHARE_CURRENT_MODE:
445 handle_to_dup = mapped_file_;
446 break;
447 case SHARE_READONLY:
448 // We could imagine re-opening the file from /dev/fd, but that can't make
449 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
450 CHECK(readonly_mapped_file_ >= 0);
451 handle_to_dup = readonly_mapped_file_;
452 break;
453 }
454
455 const int new_fd = dup(handle_to_dup);
405 if (new_fd < 0) { 456 if (new_fd < 0) {
406 DPLOG(ERROR) << "dup() failed."; 457 DPLOG(ERROR) << "dup() failed.";
407 return false; 458 return false;
408 } 459 }
409 460
410 new_handle->fd = new_fd; 461 new_handle->fd = new_fd;
411 new_handle->auto_close = true; 462 new_handle->auto_close = true;
412 463
413 if (close_self) 464 if (close_self)
414 Close(); 465 Close();
415 466
416 return true; 467 return true;
417 } 468 }
418 469
419 } // namespace base 470 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/shared_memory_nacl.cc ('k') | base/memory/shared_memory_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698