diff options
Diffstat (limited to 'base/shared_memory_posix.cc')
| -rw-r--r-- | base/shared_memory_posix.cc | 208 |
1 files changed, 105 insertions, 103 deletions
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc index dfd86aa..88203dd 100644 --- a/base/shared_memory_posix.cc +++ b/base/shared_memory_posix.cc @@ -14,6 +14,7 @@ #include "base/logging.h" #include "base/platform_thread.h" #include "base/safe_strerror_posix.h" +#include "base/thread_restrictions.h" #include "base/utf_string_conversions.h" namespace base { @@ -26,18 +27,20 @@ const char kSemaphoreSuffix[] = "-sem"; SharedMemory::SharedMemory() : mapped_file_(-1), + mapped_size_(0), inode_(0), memory_(NULL), read_only_(false), - max_size_(0) { + created_size_(0) { } SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) : mapped_file_(handle.fd), + mapped_size_(0), inode_(0), memory_(NULL), read_only_(read_only), - max_size_(0) { + created_size_(0) { struct stat st; if (fstat(handle.fd, &st) == 0) { // If fstat fails, then the file descriptor is invalid and we'll learn this @@ -49,9 +52,11 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, ProcessHandle process) : mapped_file_(handle.fd), + mapped_size_(0), + inode_(0), memory_(NULL), read_only_(read_only), - max_size_(0) { + created_size_(0) { // We don't handle this case yet (note the ignored parameter); let's die if // someone comes calling. NOTREACHED(); @@ -77,20 +82,90 @@ void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { close(handle.fd); } -bool SharedMemory::Create(const std::string& name, bool read_only, - bool open_existing, uint32 size) { - read_only_ = read_only; +bool SharedMemory::CreateAndMapAnonymous(uint32 size) { + return CreateAnonymous(size) && Map(size); +} + +bool SharedMemory::CreateAnonymous(uint32 size) { + return CreateNamed("", false, size); +} + +// Chromium mostly only uses the unique/private shmem as specified by +// "name == L"". The exception is in the StatsTable. +// TODO(jrg): there is no way to "clean up" all unused named shmem if +// we restart from a crash. (That isn't a new problem, but it is a problem.) +// In case we want to delete it later, it may be useful to save the value +// of mem_filename after FilePathForMemoryName(). +bool SharedMemory::CreateNamed(const std::string& name, + bool open_existing, uint32 size) { + DCHECK(mapped_file_ == -1); + if (size == 0) return false; + + // This function theoretically can block on the disk, but realistically + // the temporary files we create will just go into the buffer cache + // and be deleted before they ever make it out to disk. + base::ThreadRestrictions::ScopedAllowIO allow_io; - int posix_flags = 0; - posix_flags |= read_only ? O_RDONLY : O_RDWR; - if (!open_existing || mapped_file_ <= 0) - posix_flags |= O_CREAT; + FILE *fp; + bool fix_size = true; - if (!CreateOrOpen(name, posix_flags, size)) + FilePath path; + if (name.empty()) { + // It doesn't make sense to have a open-existing private piece of shmem + DCHECK(!open_existing); + // Q: Why not use the shm_open() etc. APIs? + // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU + fp = file_util::CreateAndOpenTemporaryShmemFile(&path); + + // Deleting the file prevents anyone else from mapping it in + // (making it private), and prevents the need for cleanup (once + // the last fd is closed, it is truly freed). + if (fp) + file_util::Delete(path, false); + + } else { + if (!FilePathForMemoryName(name, &path)) + return false; + + fp = file_util::OpenFile(path, "w+x"); + if (fp == NULL && open_existing) { + // "w+" will truncate if it already exists. + fp = file_util::OpenFile(path, "a+"); + fix_size = false; + } + } + if (fp && fix_size) { + // Get current size. + struct stat stat; + if (fstat(fileno(fp), &stat) != 0) + return false; + const uint32 current_size = stat.st_size; + if (current_size != size) { + if (ftruncate(fileno(fp), size) != 0) + return false; + if (fseeko(fp, size, SEEK_SET) != 0) + return false; + } + created_size_ = size; + } + if (fp == NULL) { +#if !defined(OS_MACOSX) + PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; + FilePath dir = path.DirName(); + if (access(dir.value().c_str(), W_OK | X_OK) < 0) { + PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); + if (dir.value() == "/dev/shm") { + LOG(FATAL) << "This is frequently caused by incorrect permissions on " + << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; + } + } +#else + PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; +#endif return false; + } - max_size_ = size; - return true; + return PrepareMapFile(fp); } // Our current implementation of shmem is with mmap()ing of files. @@ -110,12 +185,15 @@ bool SharedMemory::Delete(const std::string& name) { } bool SharedMemory::Open(const std::string& name, bool read_only) { - read_only_ = read_only; + FilePath path; + if (!FilePathForMemoryName(name, &path)) + return false; - int posix_flags = 0; - posix_flags |= read_only ? O_RDONLY : O_RDWR; + read_only_ = read_only; - return CreateOrOpen(name, posix_flags, 0); + const char *mode = read_only ? "r" : "r+"; + FILE *fp = file_util::OpenFile(path, mode); + return PrepareMapFile(fp); } // For the given shmem named |mem_name|, return a filename to mmap() @@ -136,92 +214,16 @@ bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, return true; } -// Chromium mostly only use the unique/private shmem as specified by -// "name == L"". The exception is in the StatsTable. -// TODO(jrg): there is no way to "clean up" all unused named shmem if -// we restart from a crash. (That isn't a new problem, but it is a problem.) -// In case we want to delete it later, it may be useful to save the value -// of mem_filename after FilePathForMemoryName(). -bool SharedMemory::CreateOrOpen(const std::string& name, - int posix_flags, uint32 size) { +bool SharedMemory::PrepareMapFile(FILE *fp) { DCHECK(mapped_file_ == -1); + if (fp == NULL) return false; - file_util::ScopedFILE file_closer; - FILE *fp; - - FilePath path; - if (name.empty()) { - // It doesn't make sense to have a read-only private piece of shmem - DCHECK(posix_flags & (O_RDWR | O_WRONLY)); - - // Q: Why not use the shm_open() etc. APIs? - // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU - fp = file_util::CreateAndOpenTemporaryShmemFile(&path); - - // Deleting the file prevents anyone else from mapping it in - // (making it private), and prevents the need for cleanup (once - // the last fd is closed, it is truly freed). - if (fp) - file_util::Delete(path, false); - } else { - if (!FilePathForMemoryName(name, &path)) - return false; - - std::string mode; - switch (posix_flags) { - case (O_RDWR | O_CREAT): - // Careful: "w+" will truncate if it already exists. - mode = "a+"; - break; - case O_RDWR: - mode = "r+"; - break; - case O_RDONLY: - mode = "r"; - break; - default: - NOTIMPLEMENTED(); - break; - } - - fp = file_util::OpenFile(path, mode.c_str()); - } - - if (fp == NULL) { - if (posix_flags & O_CREAT) { -#if !defined(OS_MACOSX) - PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; - FilePath dir = path.DirName(); - if (access(dir.value().c_str(), W_OK | X_OK) < 0) { - PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); - if (dir.value() == "/dev/shm") { - LOG(FATAL) << "This is frequently caused by incorrect permissions on " - << "/dev/shm. Try 'sudo chmod 777 /dev/shm' to fix."; - } - } -#else - PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; -#endif - } - return false; - } - - file_closer.reset(fp); // close when we go out of scope + // This function theoretically can block on the disk, but realistically + // the temporary files we create will just go into the buffer cache + // and be deleted before they ever make it out to disk. + base::ThreadRestrictions::ScopedAllowIO allow_io; - // Make sure the (new) file is the right size. - if (size && (posix_flags & (O_RDWR | O_CREAT))) { - // Get current size. - struct stat stat; - if (fstat(fileno(fp), &stat) != 0) - return false; - const uint32 current_size = stat.st_size; - if (current_size != size) { - if (ftruncate(fileno(fp), size) != 0) - return false; - if (fseeko(fp, size, SEEK_SET) != 0) - return false; - } - } + file_util::ScopedFILE file_closer(fp); mapped_file_ = dup(fileno(fp)); if (mapped_file_ == -1) { @@ -249,7 +251,7 @@ bool SharedMemory::Map(uint32 bytes) { MAP_SHARED, mapped_file_, 0); if (memory_) - max_size_ = bytes; + mapped_size_ = bytes; bool mmap_succeeded = (memory_ != (void*)-1); DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno; @@ -260,9 +262,9 @@ bool SharedMemory::Unmap() { if (memory_ == NULL) return false; - munmap(memory_, max_size_); + munmap(memory_, mapped_size_); memory_ = NULL; - max_size_ = 0; + mapped_size_ = 0; return true; } |
