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