Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: base/memory/shared_memory_mac.cc

Issue 2555483002: Add POSIX shared memory support for Mac (Closed)
Patch Set: erikchen@ comments. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/shared_memory.h" 5 #include "base/memory/shared_memory.h"
6 6
7 #include <errno.h>
7 #include <mach/mach_vm.h> 8 #include <mach/mach_vm.h>
9 #include <stddef.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
8 13
9 #include "base/files/file_util.h" 14 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h" 15 #include "base/files/scoped_file.h"
11 #include "base/logging.h" 16 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_util.h" 17 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_mach_vm.h" 18 #include "base/mac/scoped_mach_vm.h"
19 #include "base/memory/shared_memory_helper.h"
15 #include "base/metrics/field_trial.h" 20 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram_macros.h" 21 #include "base/metrics/histogram_macros.h"
22 #include "base/posix/eintr_wrapper.h"
23 #include "base/posix/safe_strerror.h"
17 #include "base/process/process_metrics.h" 24 #include "base/process/process_metrics.h"
18 #include "base/profiler/scoped_tracker.h"
19 #include "base/scoped_generic.h" 25 #include "base/scoped_generic.h"
20 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/thread_restrictions.h"
21 #include "build/build_config.h" 28 #include "build/build_config.h"
22 29
30 #if defined(OS_MACOSX)
31 #include "base/mac/foundation_util.h"
32 #endif // OS_MACOSX
33
23 namespace base { 34 namespace base {
24 35
25 namespace { 36 namespace {
26 37
27 // Returns whether the operation succeeded. 38 // Returns whether the operation succeeded.
28 // |new_handle| is an output variable, populated on success. The caller takes 39 // |new_handle| is an output variable, populated on success. The caller takes
29 // ownership of the underlying memory object. 40 // ownership of the underlying memory object.
30 // |handle| is the handle to copy. 41 // |handle| is the handle to copy.
31 // If |handle| is already mapped, |mapped_addr| is its mapped location. 42 // If |handle| is already mapped, |mapped_addr| is its mapped location.
32 // Otherwise, |mapped_addr| should be |nullptr|. 43 // Otherwise, |mapped_addr| should be |nullptr|.
(...skipping 27 matching lines...) Expand all
60 mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size), 71 mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
61 reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ, 72 reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
62 &named_right, MACH_PORT_NULL); 73 &named_right, MACH_PORT_NULL);
63 if (kr != KERN_SUCCESS) 74 if (kr != KERN_SUCCESS)
64 return false; 75 return false;
65 76
66 *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId()); 77 *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
67 return true; 78 return true;
68 } 79 }
69 80
81 void UnmapAndCloseIfNeeded(bool close_self, SharedMemory* shm) {
82 if (close_self) {
83 shm->Unmap();
84 shm->Close();
85 }
86 }
87
70 } // namespace 88 } // namespace
71 89
72 SharedMemory::SharedMemory() 90 SharedMemory::SharedMemory()
73 : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {} 91 : mapped_memory_mechanism_(SharedMemoryHandle::MACH),
92 readonly_mapped_file_(-1),
93 mapped_size_(0),
94 memory_(NULL),
95 read_only_(false),
96 requested_size_(0) {}
74 97
75 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) 98 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
76 : shm_(handle), 99 : shm_(handle),
100 mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
101 readonly_mapped_file_(-1),
77 mapped_size_(0), 102 mapped_size_(0),
78 memory_(NULL), 103 memory_(NULL),
79 read_only_(read_only), 104 read_only_(read_only),
80 requested_size_(0) {} 105 requested_size_(0) {}
81 106
82 SharedMemory::~SharedMemory() { 107 SharedMemory::~SharedMemory() {
83 Unmap(); 108 Unmap();
84 Close(); 109 Close();
85 } 110 }
86 111
87 // static 112 // static
88 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 113 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
89 return handle.IsValid(); 114 return handle.IsValid();
90 } 115 }
91 116
92 // static 117 // static
93 SharedMemoryHandle SharedMemory::NULLHandle() { 118 SharedMemoryHandle SharedMemory::NULLHandle() {
94 return SharedMemoryHandle(); 119 return SharedMemoryHandle();
95 } 120 }
96 121
97 // static 122 // static
98 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { 123 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
99 handle.Close(); 124 handle.Close();
100 } 125 }
101 126
102 // static 127 // static
103 size_t SharedMemory::GetHandleLimit() { 128 size_t SharedMemory::GetHandleLimit() {
104 // This should be effectively unlimited on OS X. 129 return GetMaxFds();
105 return 10000;
106 } 130 }
107 131
108 // static 132 // static
109 SharedMemoryHandle SharedMemory::DuplicateHandle( 133 SharedMemoryHandle SharedMemory::DuplicateHandle(
110 const SharedMemoryHandle& handle) { 134 const SharedMemoryHandle& handle) {
111 return handle.Duplicate(); 135 return handle.Duplicate();
112 } 136 }
113 137
138 // static
139 int SharedMemory::GetFdFromSharedMemoryHandle(
140 const SharedMemoryHandle& handle) {
141 return handle.file_descriptor_.fd;
142 }
143
114 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 144 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
115 return CreateAnonymous(size) && Map(size); 145 return CreateAnonymous(size) && Map(size);
116 } 146 }
117 147
118 // static 148 // static
119 bool SharedMemory::GetSizeFromSharedMemoryHandle( 149 bool SharedMemory::GetSizeFromSharedMemoryHandle(
120 const SharedMemoryHandle& handle, 150 const SharedMemoryHandle& handle,
121 size_t* size) { 151 size_t* size) {
122 return handle.GetSize(size); 152 return handle.GetSize(size);
123 } 153 }
124 154
125 // Chromium mostly only uses the unique/private shmem as specified by 155 // Chromium mostly only uses the unique/private shmem as specified by
126 // "name == L"". The exception is in the StatsTable. 156 // "name == L"". The exception is in the StatsTable.
127 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 157 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
128 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
129 // is fixed.
130 tracked_objects::ScopedTracker tracking_profile1(
131 FROM_HERE_WITH_EXPLICIT_FUNCTION(
132 "466437 SharedMemory::Create::Start"));
133 DCHECK(!shm_.IsValid()); 158 DCHECK(!shm_.IsValid());
134 if (options.size == 0) return false; 159 if (options.size == 0) return false;
135 160
136 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) 161 if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
137 return false; 162 return false;
138 163
139 shm_ = SharedMemoryHandle(options.size); 164 if (options.type == SharedMemoryHandle::MACH) {
165 shm_ = SharedMemoryHandle(options.size);
166 requested_size_ = options.size;
167 return shm_.IsValid();
168 }
169
170 // This function theoretically can block on the disk. Both profiling of real
171 // users and local instrumentation shows that this is a real problem.
172 // https://code.google.com/p/chromium/issues/detail?id=466437
173 base::ThreadRestrictions::ScopedAllowIO allow_io;
174
175 ScopedFILE fp;
176 ScopedFD readonly_fd;
177
178 FilePath path;
179 bool result = CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
180 if (!result)
181 return false;
182
183 if (!fp) {
184 PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
185 return false;
186 }
187
188 // Get current size.
189 struct stat stat;
190 if (fstat(fileno(fp.get()), &stat) != 0)
191 return false;
192 const size_t current_size = stat.st_size;
193 if (current_size != options.size) {
194 if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
195 return false;
196 }
140 requested_size_ = options.size; 197 requested_size_ = options.size;
141 return shm_.IsValid(); 198
199 int mapped_file = -1;
200 result = PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file,
201 &readonly_mapped_file_);
202
203 shm_ = SharedMemoryHandle(FileDescriptor(mapped_file, false));
204 return result;
142 } 205 }
143 206
144 bool SharedMemory::MapAt(off_t offset, size_t bytes) { 207 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
145 if (!shm_.IsValid()) 208 if (!shm_.IsValid())
146 return false; 209 return false;
147 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) 210 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
148 return false; 211 return false;
149 if (memory_) 212 if (memory_)
150 return false; 213 return false;
151 214
152 bool success = shm_.MapAt(offset, bytes, &memory_, read_only_); 215 bool success = shm_.MapAt(offset, bytes, &memory_, read_only_);
153 if (success) { 216 if (success) {
154 mapped_size_ = bytes; 217 mapped_size_ = bytes;
155 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & 218 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
156 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 219 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
220 mapped_memory_mechanism_ = shm_.type_;
157 } else { 221 } else {
158 memory_ = NULL; 222 memory_ = NULL;
159 } 223 }
160 224
161 return success; 225 return success;
162 } 226 }
163 227
164 bool SharedMemory::Unmap() { 228 bool SharedMemory::Unmap() {
165 if (memory_ == NULL) 229 if (memory_ == NULL)
166 return false; 230 return false;
167 231
168 mach_vm_deallocate(mach_task_self(), 232 switch (mapped_memory_mechanism_) {
169 reinterpret_cast<mach_vm_address_t>(memory_), 233 case SharedMemoryHandle::POSIX:
170 mapped_size_); 234 munmap(memory_, mapped_size_);
235 break;
236 case SharedMemoryHandle::MACH:
237 mach_vm_deallocate(mach_task_self(),
238 reinterpret_cast<mach_vm_address_t>(memory_),
239 mapped_size_);
240 break;
241 }
242
171 memory_ = NULL; 243 memory_ = NULL;
172 mapped_size_ = 0; 244 mapped_size_ = 0;
173 return true; 245 return true;
174 } 246 }
175 247
176 SharedMemoryHandle SharedMemory::handle() const { 248 SharedMemoryHandle SharedMemory::handle() const {
177 return shm_; 249 switch (shm_.type_) {
250 case SharedMemoryHandle::POSIX:
251 return SharedMemoryHandle(
252 FileDescriptor(shm_.file_descriptor_.fd, false));
253 case SharedMemoryHandle::MACH:
254 return shm_;
255 }
178 } 256 }
179 257
180 SharedMemoryHandle SharedMemory::TakeHandle() { 258 SharedMemoryHandle SharedMemory::TakeHandle() {
181 SharedMemoryHandle dup = DuplicateHandle(handle()); 259 SharedMemoryHandle dup = DuplicateHandle(handle());
182 Close(); 260 Close();
183 return dup; 261 return dup;
184 } 262 }
185 263
186 void SharedMemory::Close() { 264 void SharedMemory::Close() {
187 shm_.Close(); 265 shm_.Close();
188 shm_ = SharedMemoryHandle(); 266 shm_ = SharedMemoryHandle();
267 if (shm_.type_ == SharedMemoryHandle::POSIX) {
268 if (readonly_mapped_file_ > 0) {
269 if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
270 PLOG(ERROR) << "close";
271 readonly_mapped_file_ = -1;
272 }
273 }
189 } 274 }
190 275
191 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, 276 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
192 SharedMemoryHandle* new_handle, 277 SharedMemoryHandle* new_handle,
193 bool close_self, 278 bool close_self,
194 ShareMode share_mode) { 279 ShareMode share_mode) {
195 DCHECK(shm_.IsValid()); 280 if (shm_.type_ == SharedMemoryHandle::MACH) {
281 DCHECK(shm_.IsValid());
196 282
197 bool success = false; 283 bool success = false;
284 switch (share_mode) {
285 case SHARE_CURRENT_MODE:
286 *new_handle = shm_.Duplicate();
287 success = true;
288 break;
289 case SHARE_READONLY:
290 success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
291 break;
292 }
293
294 if (success)
295 new_handle->SetOwnershipPassesToIPC(true);
296
297 UnmapAndCloseIfNeeded(close_self, this);
298
299 return success;
300 }
301
302 int handle_to_dup = -1;
198 switch (share_mode) { 303 switch (share_mode) {
199 case SHARE_CURRENT_MODE: 304 case SHARE_CURRENT_MODE:
200 *new_handle = shm_.Duplicate(); 305 handle_to_dup = shm_.file_descriptor_.fd;
201 success = true;
202 break; 306 break;
203 case SHARE_READONLY: 307 case SHARE_READONLY:
204 success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_); 308 // We could imagine re-opening the file from /dev/fd, but that can't make
309 // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
310 CHECK_GE(readonly_mapped_file_, 0);
311 handle_to_dup = readonly_mapped_file_;
205 break; 312 break;
206 } 313 }
207 314
208 if (success) 315 const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
209 new_handle->SetOwnershipPassesToIPC(true); 316 if (new_fd < 0) {
210 317 DPLOG(ERROR) << "dup() failed.";
211 if (close_self) { 318 UnmapAndCloseIfNeeded(close_self, this);
212 Unmap(); 319 return false;
213 Close();
214 } 320 }
215 321
216 return success; 322 new_handle->file_descriptor_.fd = new_fd;
323 new_handle->type_ = SharedMemoryHandle::POSIX;
324
325 UnmapAndCloseIfNeeded(close_self, this);
326
327 return true;
217 } 328 }
218 329
219 } // namespace base 330 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698