Home | History | Annotate | Download | only in memory
      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
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_MEMORY_SHARED_MEMORY_H_
      6 #define BASE_MEMORY_SHARED_MEMORY_H_
      7 
      8 #include "build/build_config.h"
      9 
     10 #include <string>
     11 
     12 #if defined(OS_POSIX)
     13 #include <stdio.h>
     14 #include <sys/types.h>
     15 #include <semaphore.h>
     16 #endif
     17 
     18 #include "base/base_export.h"
     19 #include "base/basictypes.h"
     20 #include "base/process/process_handle.h"
     21 
     22 #if defined(OS_POSIX)
     23 #include "base/file_descriptor_posix.h"
     24 #include "base/file_util.h"
     25 #endif
     26 
     27 namespace base {
     28 
     29 class FilePath;
     30 
     31 // SharedMemoryHandle is a platform specific type which represents
     32 // the underlying OS handle to a shared memory segment.
     33 #if defined(OS_WIN)
     34 typedef HANDLE SharedMemoryHandle;
     35 typedef HANDLE SharedMemoryLock;
     36 #elif defined(OS_POSIX)
     37 // A SharedMemoryId is sufficient to identify a given shared memory segment on a
     38 // system, but insufficient to map it.
     39 typedef FileDescriptor SharedMemoryHandle;
     40 typedef ino_t SharedMemoryId;
     41 // On POSIX, the lock is implemented as a lockf() on the mapped file,
     42 // so no additional member (or definition of SharedMemoryLock) is
     43 // needed.
     44 #endif
     45 
     46 // Options for creating a shared memory object.
     47 struct SharedMemoryCreateOptions {
     48   SharedMemoryCreateOptions() : name(NULL), size(0), open_existing(false),
     49                                 executable(false) {}
     50 
     51   // If NULL, the object is anonymous.  This pointer is owned by the caller
     52   // and must live through the call to Create().
     53   const std::string* name;
     54 
     55   // Size of the shared memory object to be created.
     56   // When opening an existing object, this has no effect.
     57   size_t size;
     58 
     59   // If true, and the shared memory already exists, Create() will open the
     60   // existing shared memory and ignore the size parameter.  If false,
     61   // shared memory must not exist.  This flag is meaningless unless name is
     62   // non-NULL.
     63   bool open_existing;
     64 
     65   // If true, mappings might need to be made executable later.
     66   bool executable;
     67 };
     68 
     69 // Platform abstraction for shared memory.  Provides a C++ wrapper
     70 // around the OS primitive for a memory mapped file.
     71 class BASE_EXPORT SharedMemory {
     72  public:
     73   SharedMemory();
     74 
     75 #if defined(OS_WIN)
     76   // Similar to the default constructor, except that this allows for
     77   // calling Lock() to acquire the named mutex before either Create or Open
     78   // are called on Windows.
     79   explicit SharedMemory(const std::wstring& name);
     80 #endif
     81 
     82   // Create a new SharedMemory object from an existing, open
     83   // shared memory file.
     84   //
     85   // WARNING: This does not reduce the OS-level permissions on the handle; it
     86   // only affects how the SharedMemory will be mmapped.  Use
     87   // ShareReadOnlyToProcess to drop permissions.  TODO(jln,jyasskin): DCHECK
     88   // that |read_only| matches the permissions of the handle.
     89   SharedMemory(SharedMemoryHandle handle, bool read_only);
     90 
     91   // Create a new SharedMemory object from an existing, open
     92   // shared memory file that was created by a remote process and not shared
     93   // to the current process.
     94   SharedMemory(SharedMemoryHandle handle, bool read_only,
     95                ProcessHandle process);
     96 
     97   // Closes any open files.
     98   ~SharedMemory();
     99 
    100   // Return true iff the given handle is valid (i.e. not the distingished
    101   // invalid value; NULL for a HANDLE and -1 for a file descriptor)
    102   static bool IsHandleValid(const SharedMemoryHandle& handle);
    103 
    104   // Returns invalid handle (see comment above for exact definition).
    105   static SharedMemoryHandle NULLHandle();
    106 
    107   // Closes a shared memory handle.
    108   static void CloseHandle(const SharedMemoryHandle& handle);
    109 
    110   // Returns the maximum number of handles that can be open at once per process.
    111   static size_t GetHandleLimit();
    112 
    113   // Creates a shared memory object as described by the options struct.
    114   // Returns true on success and false on failure.
    115   bool Create(const SharedMemoryCreateOptions& options);
    116 
    117   // Creates and maps an anonymous shared memory segment of size size.
    118   // Returns true on success and false on failure.
    119   bool CreateAndMapAnonymous(size_t size);
    120 
    121   // Creates an anonymous shared memory segment of size size.
    122   // Returns true on success and false on failure.
    123   bool CreateAnonymous(size_t size) {
    124     SharedMemoryCreateOptions options;
    125     options.size = size;
    126     return Create(options);
    127   }
    128 
    129   // Creates or opens a shared memory segment based on a name.
    130   // If open_existing is true, and the shared memory already exists,
    131   // opens the existing shared memory and ignores the size parameter.
    132   // If open_existing is false, shared memory must not exist.
    133   // size is the size of the block to be created.
    134   // Returns true on success, false on failure.
    135   bool CreateNamed(const std::string& name, bool open_existing, size_t size) {
    136     SharedMemoryCreateOptions options;
    137     options.name = &name;
    138     options.open_existing = open_existing;
    139     options.size = size;
    140     return Create(options);
    141   }
    142 
    143   // Deletes resources associated with a shared memory segment based on name.
    144   // Not all platforms require this call.
    145   bool Delete(const std::string& name);
    146 
    147   // Opens a shared memory segment based on a name.
    148   // If read_only is true, opens for read-only access.
    149   // Returns true on success, false on failure.
    150   bool Open(const std::string& name, bool read_only);
    151 
    152   // Maps the shared memory into the caller's address space.
    153   // Returns true on success, false otherwise.  The memory address
    154   // is accessed via the memory() accessor.  The mapped address is guaranteed to
    155   // have an alignment of at least MAP_MINIMUM_ALIGNMENT.
    156   bool Map(size_t bytes) {
    157     return MapAt(0, bytes);
    158   }
    159 
    160   // Same as above, but with |offset| to specify from begining of the shared
    161   // memory block to map.
    162   // |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|.
    163   bool MapAt(off_t offset, size_t bytes);
    164   enum { MAP_MINIMUM_ALIGNMENT = 32 };
    165 
    166   // Unmaps the shared memory from the caller's address space.
    167   // Returns true if successful; returns false on error or if the
    168   // memory is not mapped.
    169   bool Unmap();
    170 
    171   // The size requested when the map is first created.
    172   size_t requested_size() const { return requested_size_; }
    173 
    174   // The actual size of the mapped memory (may be larger than requested).
    175   size_t mapped_size() const { return mapped_size_; }
    176 
    177   // Gets a pointer to the opened memory space if it has been
    178   // Mapped via Map().  Returns NULL if it is not mapped.
    179   void *memory() const { return memory_; }
    180 
    181   // Returns the underlying OS handle for this segment.
    182   // Use of this handle for anything other than an opaque
    183   // identifier is not portable.
    184   SharedMemoryHandle handle() const;
    185 
    186 #if defined(OS_POSIX) && !defined(OS_NACL)
    187   // Returns a unique identifier for this shared memory segment. Inode numbers
    188   // are technically only unique to a single filesystem. However, we always
    189   // allocate shared memory backing files from the same directory, so will end
    190   // up on the same filesystem.
    191   SharedMemoryId id() const { return inode_; }
    192 #endif
    193 
    194   // Closes the open shared memory segment.
    195   // It is safe to call Close repeatedly.
    196   void Close();
    197 
    198   // Shares the shared memory to another process.  Attempts to create a
    199   // platform-specific new_handle which can be used in a remote process to read
    200   // the shared memory file.  new_handle is an output parameter to receive the
    201   // handle for use in the remote process.
    202   //
    203   // |*this| must have been initialized using one of the Create*() or Open()
    204   // methods.  If it was constructed from a SharedMemoryHandle, this call will
    205   // CHECK-fail.
    206   //
    207   // Returns true on success, false otherwise.
    208   bool ShareReadOnlyToProcess(ProcessHandle process,
    209                               SharedMemoryHandle* new_handle) {
    210     return ShareToProcessCommon(process, new_handle, false, SHARE_READONLY);
    211   }
    212 
    213   // Logically equivalent to:
    214   //   bool ok = ShareReadOnlyToProcess(process, new_handle);
    215   //   Close();
    216   //   return ok;
    217   // Note that the memory is unmapped by calling this method, regardless of the
    218   // return value.
    219   bool GiveReadOnlyToProcess(ProcessHandle process,
    220                              SharedMemoryHandle* new_handle) {
    221     return ShareToProcessCommon(process, new_handle, true, SHARE_READONLY);
    222   }
    223 
    224   // Shares the shared memory to another process.  Attempts
    225   // to create a platform-specific new_handle which can be
    226   // used in a remote process to access the shared memory
    227   // file.  new_handle is an output parameter to receive
    228   // the handle for use in the remote process.
    229   // Returns true on success, false otherwise.
    230   bool ShareToProcess(ProcessHandle process,
    231                       SharedMemoryHandle* new_handle) {
    232     return ShareToProcessCommon(process, new_handle, false, SHARE_CURRENT_MODE);
    233   }
    234 
    235   // Logically equivalent to:
    236   //   bool ok = ShareToProcess(process, new_handle);
    237   //   Close();
    238   //   return ok;
    239   // Note that the memory is unmapped by calling this method, regardless of the
    240   // return value.
    241   bool GiveToProcess(ProcessHandle process,
    242                      SharedMemoryHandle* new_handle) {
    243     return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
    244   }
    245 
    246   // Locks the shared memory.
    247   //
    248   // WARNING: on POSIX the memory locking primitive only works across
    249   // processes, not across threads.  The Lock method is not currently
    250   // used in inner loops, so we protect against multiple threads in a
    251   // critical section using a class global lock.
    252   void Lock();
    253 
    254 #if defined(OS_WIN)
    255   // A Lock() implementation with a timeout that also allows setting
    256   // security attributes on the mutex. sec_attr may be NULL.
    257   // Returns true if the Lock() has been acquired, false if the timeout was
    258   // reached.
    259   bool Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr);
    260 #endif
    261 
    262   // Releases the shared memory lock.
    263   void Unlock();
    264 
    265  private:
    266 #if defined(OS_POSIX) && !defined(OS_NACL)
    267   bool PrepareMapFile(file_util::ScopedFILE fp, file_util::ScopedFD readonly);
    268   bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
    269   void LockOrUnlockCommon(int function);
    270 #endif
    271   enum ShareMode {
    272     SHARE_READONLY,
    273     SHARE_CURRENT_MODE,
    274   };
    275   bool ShareToProcessCommon(ProcessHandle process,
    276                             SharedMemoryHandle* new_handle,
    277                             bool close_self,
    278                             ShareMode);
    279 
    280 #if defined(OS_WIN)
    281   std::wstring       name_;
    282   HANDLE             mapped_file_;
    283 #elif defined(OS_POSIX)
    284   int                mapped_file_;
    285   int                readonly_mapped_file_;
    286   ino_t              inode_;
    287 #endif
    288   size_t             mapped_size_;
    289   void*              memory_;
    290   bool               read_only_;
    291   size_t             requested_size_;
    292 #if !defined(OS_POSIX)
    293   SharedMemoryLock   lock_;
    294 #endif
    295 
    296   DISALLOW_COPY_AND_ASSIGN(SharedMemory);
    297 };
    298 
    299 // A helper class that acquires the shared memory lock while
    300 // the SharedMemoryAutoLock is in scope.
    301 class SharedMemoryAutoLock {
    302  public:
    303   explicit SharedMemoryAutoLock(SharedMemory* shared_memory)
    304       : shared_memory_(shared_memory) {
    305     shared_memory_->Lock();
    306   }
    307 
    308   ~SharedMemoryAutoLock() {
    309     shared_memory_->Unlock();
    310   }
    311 
    312  private:
    313   SharedMemory* shared_memory_;
    314   DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLock);
    315 };
    316 
    317 }  // namespace base
    318 
    319 #endif  // BASE_MEMORY_SHARED_MEMORY_H_
    320