shared_memory_win.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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
10namespace base {
11
12SharedMemory::SharedMemory()
13    : mapped_file_(NULL),
14      memory_(NULL),
15      read_only_(false),
16      created_size_(0),
17      lock_(NULL) {
18}
19
20SharedMemory::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
29SharedMemory::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
37SharedMemory::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
51SharedMemory::~SharedMemory() {
52  Close();
53  if (lock_ != NULL)
54    CloseHandle(lock_);
55}
56
57// static
58bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
59  return handle != NULL;
60}
61
62// static
63SharedMemoryHandle SharedMemory::NULLHandle() {
64  return NULL;
65}
66
67// static
68void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
69  DCHECK(handle != NULL);
70  ::CloseHandle(handle);
71}
72
73bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
74  return CreateAnonymous(size) && Map(size);
75}
76
77bool SharedMemory::CreateAnonymous(uint32 size) {
78  return CreateNamed("", false, size);
79}
80
81bool 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
116bool SharedMemory::Delete(const std::string& name) {
117  // intentionally empty -- there is nothing for us to do on Windows.
118  return true;
119}
120
121bool 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
136bool 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
148bool SharedMemory::Unmap() {
149  if (memory_ == NULL)
150    return false;
151
152  UnmapViewOfFile(memory_);
153  memory_ = NULL;
154  return true;
155}
156
157bool 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
187void 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
199void SharedMemory::Lock() {
200  Lock(INFINITE, NULL);
201}
202
203bool 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
219void SharedMemory::Unlock() {
220  DCHECK(lock_ != NULL);
221  ReleaseMutex(lock_);
222}
223
224SharedMemoryHandle SharedMemory::handle() const {
225  return mapped_file_;
226}
227
228}  // namespace base
229