Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/shared_memory.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/utf_string_conversions.h"
      9 
     10 namespace base {
     11 
     12 SharedMemory::SharedMemory()
     13     : mapped_file_(NULL),
     14       memory_(NULL),
     15       read_only_(false),
     16       created_size_(0),
     17       lock_(NULL) {
     18 }
     19 
     20 SharedMemory::SharedMemory(const std::wstring& name)
     21     : mapped_file_(NULL),
     22       memory_(NULL),
     23       read_only_(false),
     24       created_size_(0),
     25       lock_(NULL),
     26       name_(name) {
     27 }
     28 
     29 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
     30     : mapped_file_(handle),
     31       memory_(NULL),
     32       read_only_(read_only),
     33       created_size_(0),
     34       lock_(NULL) {
     35 }
     36 
     37 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
     38                            ProcessHandle process)
     39     : mapped_file_(NULL),
     40       memory_(NULL),
     41       read_only_(read_only),
     42       created_size_(0),
     43       lock_(NULL) {
     44   ::DuplicateHandle(process, handle,
     45                     GetCurrentProcess(), &mapped_file_,
     46                     STANDARD_RIGHTS_REQUIRED |
     47                     (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS),
     48                     FALSE, 0);
     49 }
     50 
     51 SharedMemory::~SharedMemory() {
     52   Close();
     53   if (lock_ != NULL)
     54     CloseHandle(lock_);
     55 }
     56 
     57 // static
     58 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
     59   return handle != NULL;
     60 }
     61 
     62 // static
     63 SharedMemoryHandle SharedMemory::NULLHandle() {
     64   return NULL;
     65 }
     66 
     67 // static
     68 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
     69   DCHECK(handle != NULL);
     70   ::CloseHandle(handle);
     71 }
     72 
     73 bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
     74   return CreateAnonymous(size) && Map(size);
     75 }
     76 
     77 bool SharedMemory::CreateAnonymous(uint32 size) {
     78   return CreateNamed("", false, size);
     79 }
     80 
     81 bool SharedMemory::CreateNamed(const std::string& name,
     82                                bool open_existing, uint32 size) {
     83   DCHECK(!mapped_file_);
     84   if (size == 0)
     85     return false;
     86 
     87   // NaCl's memory allocator requires 0mod64K alignment and size for
     88   // shared memory objects.  To allow passing shared memory to NaCl,
     89   // therefore we round the size actually created to the nearest 64K unit.
     90   // To avoid client impact, we continue to retain the size as the
     91   // actual requested size.
     92   uint32 rounded_size = (size + 0xffff) & ~0xffff;
     93   name_ = ASCIIToWide(name);
     94   mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
     95       PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
     96       name_.empty() ? NULL : name_.c_str());
     97   if (!mapped_file_)
     98     return false;
     99 
    100   created_size_ = size;
    101 
    102   // Check if the shared memory pre-exists.
    103   if (GetLastError() == ERROR_ALREADY_EXISTS) {
    104     // If the file already existed, set created_size_ to 0 to show that
    105     // we don't know the size.
    106     created_size_ = 0;
    107     if (!open_existing) {
    108       Close();
    109       return false;
    110     }
    111   }
    112 
    113   return true;
    114 }
    115 
    116 bool SharedMemory::Delete(const std::string& name) {
    117   // intentionally empty -- there is nothing for us to do on Windows.
    118   return true;
    119 }
    120 
    121 bool SharedMemory::Open(const std::string& name, bool read_only) {
    122   DCHECK(!mapped_file_);
    123 
    124   name_ = ASCIIToWide(name);
    125   read_only_ = read_only;
    126   mapped_file_ = OpenFileMapping(
    127       read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false,
    128       name_.empty() ? NULL : name_.c_str());
    129   if (mapped_file_ != NULL) {
    130     // Note: size_ is not set in this case.
    131     return true;
    132   }
    133   return false;
    134 }
    135 
    136 bool SharedMemory::Map(uint32 bytes) {
    137   if (mapped_file_ == NULL)
    138     return false;
    139 
    140   memory_ = MapViewOfFile(mapped_file_,
    141       read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 0, 0, bytes);
    142   if (memory_ != NULL) {
    143     return true;
    144   }
    145   return false;
    146 }
    147 
    148 bool SharedMemory::Unmap() {
    149   if (memory_ == NULL)
    150     return false;
    151 
    152   UnmapViewOfFile(memory_);
    153   memory_ = NULL;
    154   return true;
    155 }
    156 
    157 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
    158                                         SharedMemoryHandle *new_handle,
    159                                         bool close_self) {
    160   *new_handle = 0;
    161   DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
    162   DWORD options = 0;
    163   HANDLE mapped_file = mapped_file_;
    164   HANDLE result;
    165   if (!read_only_)
    166     access |= FILE_MAP_WRITE;
    167   if (close_self) {
    168     // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
    169     options = DUPLICATE_CLOSE_SOURCE;
    170     mapped_file_ = NULL;
    171     Unmap();
    172   }
    173 
    174   if (process == GetCurrentProcess() && close_self) {
    175     *new_handle = mapped_file;
    176     return true;
    177   }
    178 
    179   if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
    180       &result, access, FALSE, options))
    181     return false;
    182   *new_handle = result;
    183   return true;
    184 }
    185 
    186 
    187 void SharedMemory::Close() {
    188   if (memory_ != NULL) {
    189     UnmapViewOfFile(memory_);
    190     memory_ = NULL;
    191   }
    192 
    193   if (mapped_file_ != NULL) {
    194     CloseHandle(mapped_file_);
    195     mapped_file_ = NULL;
    196   }
    197 }
    198 
    199 void SharedMemory::Lock() {
    200   Lock(INFINITE, NULL);
    201 }
    202 
    203 bool SharedMemory::Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr) {
    204   if (lock_ == NULL) {
    205     std::wstring name = name_;
    206     name.append(L"lock");
    207     lock_ = CreateMutex(sec_attr, FALSE, name.c_str());
    208     if (lock_ == NULL) {
    209       PLOG(ERROR) << "Could not create mutex.";
    210       return false;  // there is nothing good we can do here.
    211     }
    212   }
    213   DWORD result = WaitForSingleObject(lock_, timeout_ms);
    214 
    215   // Return false for WAIT_ABANDONED, WAIT_TIMEOUT or WAIT_FAILED.
    216   return (result == WAIT_OBJECT_0);
    217 }
    218 
    219 void SharedMemory::Unlock() {
    220   DCHECK(lock_ != NULL);
    221   ReleaseMutex(lock_);
    222 }
    223 
    224 SharedMemoryHandle SharedMemory::handle() const {
    225   return mapped_file_;
    226 }
    227 
    228 }  // namespace base
    229