michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "base/shared_memory.h" michael@0: michael@0: #include "base/logging.h" michael@0: #include "base/win_util.h" michael@0: #include "base/string_util.h" michael@0: michael@0: namespace base { michael@0: michael@0: SharedMemory::SharedMemory() michael@0: : mapped_file_(NULL), michael@0: memory_(NULL), michael@0: read_only_(false), michael@0: max_size_(0), michael@0: lock_(NULL) { michael@0: } michael@0: michael@0: SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) michael@0: : mapped_file_(handle), michael@0: memory_(NULL), michael@0: read_only_(read_only), michael@0: max_size_(0), michael@0: lock_(NULL) { michael@0: } michael@0: michael@0: SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, michael@0: ProcessHandle process) michael@0: : mapped_file_(NULL), michael@0: memory_(NULL), michael@0: read_only_(read_only), michael@0: max_size_(0), michael@0: lock_(NULL) { michael@0: ::DuplicateHandle(process, handle, michael@0: GetCurrentProcess(), &mapped_file_, michael@0: STANDARD_RIGHTS_REQUIRED | michael@0: (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), michael@0: FALSE, 0); michael@0: } michael@0: michael@0: SharedMemory::~SharedMemory() { michael@0: Close(); michael@0: if (lock_ != NULL) michael@0: CloseHandle(lock_); michael@0: } michael@0: michael@0: // static michael@0: bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { michael@0: return handle != NULL; michael@0: } michael@0: michael@0: // static michael@0: SharedMemoryHandle SharedMemory::NULLHandle() { michael@0: return NULL; michael@0: } michael@0: michael@0: bool SharedMemory::Create(const std::string &cname, bool read_only, michael@0: bool open_existing, size_t size) { michael@0: DCHECK(mapped_file_ == NULL); michael@0: std::wstring name = UTF8ToWide(cname); michael@0: name_ = name; michael@0: read_only_ = read_only; michael@0: mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, michael@0: read_only_ ? PAGE_READONLY : PAGE_READWRITE, 0, static_cast(size), michael@0: name.empty() ? NULL : name.c_str()); michael@0: if (!mapped_file_) michael@0: return false; michael@0: michael@0: // Check if the shared memory pre-exists. michael@0: if (GetLastError() == ERROR_ALREADY_EXISTS && !open_existing) { michael@0: Close(); michael@0: return false; michael@0: } michael@0: max_size_ = size; michael@0: return true; michael@0: } michael@0: michael@0: bool SharedMemory::Delete(const std::wstring& name) { michael@0: // intentionally empty -- there is nothing for us to do on Windows. michael@0: return true; michael@0: } michael@0: michael@0: bool SharedMemory::Open(const std::wstring &name, bool read_only) { michael@0: DCHECK(mapped_file_ == NULL); michael@0: michael@0: name_ = name; michael@0: read_only_ = read_only; michael@0: mapped_file_ = OpenFileMapping( michael@0: read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false, michael@0: name.empty() ? NULL : name.c_str()); michael@0: if (mapped_file_ != NULL) { michael@0: // Note: size_ is not set in this case. michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool SharedMemory::Map(size_t bytes) { michael@0: if (mapped_file_ == NULL) michael@0: return false; michael@0: michael@0: memory_ = MapViewOfFile(mapped_file_, michael@0: read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 0, 0, bytes); michael@0: if (memory_ != NULL) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool SharedMemory::Unmap() { michael@0: if (memory_ == NULL) michael@0: return false; michael@0: michael@0: UnmapViewOfFile(memory_); michael@0: memory_ = NULL; michael@0: return true; michael@0: } michael@0: michael@0: bool SharedMemory::ShareToProcessCommon(ProcessHandle process, michael@0: SharedMemoryHandle *new_handle, michael@0: bool close_self) { michael@0: *new_handle = 0; michael@0: DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ; michael@0: DWORD options = 0; michael@0: HANDLE mapped_file = mapped_file_; michael@0: HANDLE result; michael@0: if (!read_only_) michael@0: access |= FILE_MAP_WRITE; michael@0: if (close_self) { michael@0: // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file. michael@0: options = DUPLICATE_CLOSE_SOURCE; michael@0: mapped_file_ = NULL; michael@0: Unmap(); michael@0: } michael@0: michael@0: if (process == GetCurrentProcess() && close_self) { michael@0: *new_handle = mapped_file; michael@0: return true; michael@0: } michael@0: michael@0: if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process, michael@0: &result, access, FALSE, options)) michael@0: return false; michael@0: *new_handle = result; michael@0: return true; michael@0: } michael@0: michael@0: michael@0: void SharedMemory::Close() { michael@0: if (memory_ != NULL) { michael@0: UnmapViewOfFile(memory_); michael@0: memory_ = NULL; michael@0: } michael@0: michael@0: if (mapped_file_ != NULL) { michael@0: CloseHandle(mapped_file_); michael@0: mapped_file_ = NULL; michael@0: } michael@0: } michael@0: michael@0: void SharedMemory::Lock() { michael@0: if (lock_ == NULL) { michael@0: std::wstring name = name_; michael@0: name.append(L"lock"); michael@0: lock_ = CreateMutex(NULL, FALSE, name.c_str()); michael@0: DCHECK(lock_ != NULL); michael@0: if (lock_ == NULL) { michael@0: DLOG(ERROR) << "Could not create mutex" << GetLastError(); michael@0: return; // there is nothing good we can do here. michael@0: } michael@0: } michael@0: WaitForSingleObject(lock_, INFINITE); michael@0: } michael@0: michael@0: void SharedMemory::Unlock() { michael@0: DCHECK(lock_ != NULL); michael@0: ReleaseMutex(lock_); michael@0: } michael@0: michael@0: SharedMemoryHandle SharedMemory::handle() const { michael@0: return mapped_file_; michael@0: } michael@0: michael@0: } // namespace base