shared_memory_win.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
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/win_util.h"
9
10namespace base {
11
12SharedMemory::SharedMemory()
13    : mapped_file_(NULL),
14      memory_(NULL),
15      read_only_(false),
16      max_size_(0),
17      lock_(NULL) {
18}
19
20SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
21    : mapped_file_(handle),
22      memory_(NULL),
23      read_only_(read_only),
24      max_size_(0),
25      lock_(NULL) {
26}
27
28SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
29                           ProcessHandle process)
30    : mapped_file_(NULL),
31      memory_(NULL),
32      read_only_(read_only),
33      max_size_(0),
34      lock_(NULL) {
35  ::DuplicateHandle(process, handle,
36                    GetCurrentProcess(), &mapped_file_,
37                    STANDARD_RIGHTS_REQUIRED |
38                    (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS),
39                    FALSE, 0);
40}
41
42SharedMemory::~SharedMemory() {
43  Close();
44  if (lock_ != NULL)
45    CloseHandle(lock_);
46}
47
48// static
49bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
50  return handle != NULL;
51}
52
53// static
54SharedMemoryHandle SharedMemory::NULLHandle() {
55  return NULL;
56}
57
58// static
59void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
60  DCHECK(handle != NULL);
61  ::CloseHandle(handle);
62}
63
64bool SharedMemory::Create(const std::wstring &name, bool read_only,
65                          bool open_existing, uint32 size) {
66  DCHECK(mapped_file_ == NULL);
67
68  // NaCl's memory allocator requires 0mod64K alignment and size for
69  // shared memory objects.  To allow passing shared memory to NaCl,
70  // therefore we round the size actually created to the nearest 64K unit.
71  // To avoid client impact, we continue to retain the size as the
72  // actual requested size.
73  uint32 rounded_size = (size + 0xffff) & ~0xffff;
74  name_ = name;
75  read_only_ = read_only;
76  mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
77      read_only_ ? PAGE_READONLY : PAGE_READWRITE, 0,
78      static_cast<DWORD>(rounded_size),
79      name.empty() ? NULL : name.c_str());
80  if (!mapped_file_)
81    return false;
82
83  // Check if the shared memory pre-exists.
84  if (GetLastError() == ERROR_ALREADY_EXISTS && !open_existing) {
85    Close();
86    return false;
87  }
88  max_size_ = size;
89  return true;
90}
91
92bool SharedMemory::Delete(const std::wstring& name) {
93  // intentionally empty -- there is nothing for us to do on Windows.
94  return true;
95}
96
97bool SharedMemory::Open(const std::wstring &name, bool read_only) {
98  DCHECK(mapped_file_ == NULL);
99
100  name_ = name;
101  read_only_ = read_only;
102  mapped_file_ = OpenFileMapping(
103      read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false,
104      name.empty() ? NULL : name.c_str());
105  if (mapped_file_ != NULL) {
106    // Note: size_ is not set in this case.
107    return true;
108  }
109  return false;
110}
111
112bool SharedMemory::Map(uint32 bytes) {
113  if (mapped_file_ == NULL)
114    return false;
115
116  memory_ = MapViewOfFile(mapped_file_,
117      read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 0, 0, bytes);
118  if (memory_ != NULL) {
119    return true;
120  }
121  return false;
122}
123
124bool SharedMemory::Unmap() {
125  if (memory_ == NULL)
126    return false;
127
128  UnmapViewOfFile(memory_);
129  memory_ = NULL;
130  return true;
131}
132
133bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
134                                        SharedMemoryHandle *new_handle,
135                                        bool close_self) {
136  *new_handle = 0;
137  DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
138  DWORD options = 0;
139  HANDLE mapped_file = mapped_file_;
140  HANDLE result;
141  if (!read_only_)
142    access |= FILE_MAP_WRITE;
143  if (close_self) {
144    // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
145    options = DUPLICATE_CLOSE_SOURCE;
146    mapped_file_ = NULL;
147    Unmap();
148  }
149
150  if (process == GetCurrentProcess() && close_self) {
151    *new_handle = mapped_file;
152    return true;
153  }
154
155  if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
156      &result, access, FALSE, options))
157    return false;
158  *new_handle = result;
159  return true;
160}
161
162
163void SharedMemory::Close() {
164  if (memory_ != NULL) {
165    UnmapViewOfFile(memory_);
166    memory_ = NULL;
167  }
168
169  if (mapped_file_ != NULL) {
170    CloseHandle(mapped_file_);
171    mapped_file_ = NULL;
172  }
173}
174
175void SharedMemory::Lock() {
176  if (lock_ == NULL) {
177    std::wstring name = name_;
178    name.append(L"lock");
179    lock_ = CreateMutex(NULL, FALSE, name.c_str());
180    DCHECK(lock_ != NULL);
181    if (lock_ == NULL) {
182      DLOG(ERROR) << "Could not create mutex" << GetLastError();
183      return;  // there is nothing good we can do here.
184    }
185  }
186  WaitForSingleObject(lock_, INFINITE);
187}
188
189void SharedMemory::Unlock() {
190  DCHECK(lock_ != NULL);
191  ReleaseMutex(lock_);
192}
193
194SharedMemoryHandle SharedMemory::handle() const {
195  return mapped_file_;
196}
197
198}  // namespace base
199