diff options
author | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-04 00:58:39 +0000 |
---|---|---|
committer | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-04 00:58:39 +0000 |
commit | 9e51af9018550b6b23802f66469310f5d1790ab9 (patch) | |
tree | 9ab6f3e0532f6d23c2af1d0acc5605ad00876418 /base/shared_memory_posix.cc | |
parent | 4c7ca4b8c2ceb6f823474744f035672c8501d23b (diff) | |
download | chromium_src-9e51af9018550b6b23802f66469310f5d1790ab9.zip chromium_src-9e51af9018550b6b23802f66469310f5d1790ab9.tar.gz chromium_src-9e51af9018550b6b23802f66469310f5d1790ab9.tar.bz2 |
Properly honor base::SharedMemory semantics for name="" to mean
new/private shared memory on POSIX. Transition base::SharedMemory
implementation to file/mmap() to prevent leaking of wired kernel
resources and allow easier cleanup. Enable one more shared_memory
unit test for POSIX. Enable stats_table_unittest.cc for Mac, and
modify it so it cleans up.
Review URL: http://codereview.chromium.org/19724
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9114 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/shared_memory_posix.cc')
-rw-r--r-- | base/shared_memory_posix.cc | 146 |
1 files changed, 129 insertions, 17 deletions
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc index aa0c837..907ef2d 100644 --- a/base/shared_memory_posix.cc +++ b/base/shared_memory_posix.cc @@ -8,6 +8,7 @@ #include <fcntl.h> #include <sys/mman.h> +#include "base/file_util.h" #include "base/logging.h" #include "base/string_util.h" @@ -62,15 +63,27 @@ bool SharedMemory::Create(const std::wstring &name, bool read_only, if (!open_existing || mapped_file_ <= 0) posix_flags |= O_CREAT; - if (!CreateOrOpen(name, posix_flags)) + if (!CreateOrOpen(name, posix_flags, size)) return false; - if (ftruncate(mapped_file_, size) != 0) { - Close(); + max_size_ = size; + return true; +} + +// Our current implementation of shmem is with mmap()ing of files. +// These files need to be deleted explicitly. +// In practice this call is only needed for unit tests. +bool SharedMemory::Delete(const std::wstring& name) { + std::wstring mem_filename; + if (FilenameForMemoryName(name, &mem_filename) == false) return false; + + FilePath path(WideToUTF8(mem_filename)); + if (file_util::PathExists(path)) { + return file_util::Delete(path, false); } - max_size_ = size; + // Doesn't exist, so success. return true; } @@ -80,26 +93,127 @@ bool SharedMemory::Open(const std::wstring &name, bool read_only) { int posix_flags = 0; posix_flags |= read_only ? O_RDONLY : O_RDWR; - return CreateOrOpen(name, posix_flags); + return CreateOrOpen(name, posix_flags, 0); } -bool SharedMemory::CreateOrOpen(const std::wstring &name, int posix_flags) { +// For the given shmem named |memname|, return a filename to mmap() +// (and possibly create). Modifies |filename|. Return false on +// error, or true of we are happy. +bool SharedMemory::FilenameForMemoryName(const std::wstring &memname, + std::wstring *filename) { + std::wstring mem_filename; + + // mem_name will be used for a filename; make sure it doesn't + // contain anything which will confuse us. + DCHECK(memname.find_first_of(L"/") == std::string::npos); + DCHECK(memname.find_first_of(L"\0") == std::string::npos); + + FilePath temp_dir; + if (file_util::GetShmemTempDir(&temp_dir) == false) + return false; + + mem_filename = UTF8ToWide(temp_dir.value()); + file_util::AppendToPath(&mem_filename, L"com.google.chrome.shmem." + memname); + *filename = mem_filename; + return true; +} + +// Current expectation is that Cromium only really needs +// unique/private shmem as specified by "name == L"". +// TODO(port): confirm that assumption. +// 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.) +bool SharedMemory::CreateOrOpen(const std::wstring &name, + int posix_flags, size_t size) { DCHECK(mapped_file_ == -1); - name_ = L"/" + name; + file_util::ScopedFILE file_closer; + FILE *fp; + + if (name == L"") { + // It doesn't make sense to have a read-only private piece of shmem + DCHECK(posix_flags & (O_RDWR | O_WRONLY)); + + FilePath path; + fp = file_util::CreateAndOpenTemporaryShmemFile(&path); + name_ = UTF8ToWide(path.value()); + + // 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). + file_util::Delete(path, false); + } else { + std::wstring mem_filename; + if (FilenameForMemoryName(name, &mem_filename) == false) + return false; + + name_ = mem_filename; + 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(mem_filename, mode.c_str()); + } - mode_t posix_mode = S_IRUSR | S_IWUSR; // owner read/write - std::string posix_name(WideToUTF8(name_)); - mapped_file_ = shm_open(posix_name.c_str(), posix_flags, posix_mode); - if (mapped_file_ < 0) + if (fp == NULL) return false; + file_closer.reset(fp); // close when we go out of scope + + // Make sure the (new) file is the right size. + // According to the man page, "Use of truncate() to extend a file is + // not portable." + if (size && (posix_flags & (O_RDWR | O_CREAT))) { + // Get current size. + size_t current_size = 0; + struct stat stat; + if (fstat(fileno(fp), &stat) != 0) + return false; + current_size = stat.st_size; + // Possibly grow. + if (current_size < size) { + if (fseeko(fp, current_size, SEEK_SET) != 0) + return false; + size_t writesize = size - current_size; + scoped_array<char> buf(new char[writesize]); + memset(buf.get(), 0, writesize); + if (fwrite(buf.get(), 1, writesize, fp) != writesize) { + return false; + } + if (fflush(fp) != 0) + return false; + } else if (current_size > size) { + // possibly shrink. + if ((ftruncate(fileno(fp), size) != 0) || + (fflush(fp) != 0)) { + return false; + } + } + } + + mapped_file_ = dup(fileno(fp)); + DCHECK(mapped_file_ >= 0); - posix_name += kSemaphoreSuffix; - lock_ = sem_open(posix_name.c_str(), O_CREAT, posix_mode, 1); + mode_t posix_mode = S_IRUSR | S_IWUSR; // owner read/write + // name_ that includes a tmpdir easily exceeds SEM_NAME_LEN, + // so we cannot use it directly as the basis for a sem_name_. + sem_name_ = WideToUTF8(name) + kSemaphoreSuffix; + lock_ = sem_open(sem_name_.c_str(), O_CREAT, posix_mode, 1); if (lock_ == SEM_FAILED) { close(mapped_file_); mapped_file_ = -1; - shm_unlink(posix_name.c_str()); lock_ = NULL; return false; } @@ -147,13 +261,11 @@ void SharedMemory::Close() { std::string posix_name(WideToUTF8(name_)); if (mapped_file_ > 0) { close(mapped_file_); - shm_unlink(posix_name.c_str()); mapped_file_ = -1; } if (lock_) { - posix_name += kSemaphoreSuffix; - sem_unlink(posix_name.c_str()); + sem_unlink(sem_name_.c_str()); lock_ = NULL; } } |