OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/shared_memory.h" | 5 #include "base/shared_memory.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <sys/mman.h> | 9 #include <sys/mman.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 if (!FilePathForMemoryName(name, &path)) | 189 if (!FilePathForMemoryName(name, &path)) |
190 return false; | 190 return false; |
191 | 191 |
192 read_only_ = read_only; | 192 read_only_ = read_only; |
193 | 193 |
194 const char *mode = read_only ? "r" : "r+"; | 194 const char *mode = read_only ? "r" : "r+"; |
195 FILE *fp = file_util::OpenFile(path, mode); | 195 FILE *fp = file_util::OpenFile(path, mode); |
196 return PrepareMapFile(fp); | 196 return PrepareMapFile(fp); |
197 } | 197 } |
198 | 198 |
199 // For the given shmem named |mem_name|, return a filename to mmap() | 199 bool SharedMemory::Map(uint32 bytes) { |
200 // (and possibly create). Modifies |filename|. Return false on | 200 if (mapped_file_ == -1) |
201 // error, or true of we are happy. | |
202 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, | |
203 FilePath* path) { | |
204 // mem_name will be used for a filename; make sure it doesn't | |
205 // contain anything which will confuse us. | |
206 DCHECK(mem_name.find('/') == std::string::npos); | |
207 DCHECK(mem_name.find('\0') == std::string::npos); | |
208 | |
209 FilePath temp_dir; | |
210 if (!file_util::GetShmemTempDir(&temp_dir)) | |
211 return false; | 201 return false; |
212 | 202 |
213 *path = temp_dir.AppendASCII("com.google.chrome.shmem." + mem_name); | 203 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), |
| 204 MAP_SHARED, mapped_file_, 0); |
| 205 |
| 206 if (memory_) |
| 207 mapped_size_ = bytes; |
| 208 |
| 209 bool mmap_succeeded = (memory_ != (void*)-1); |
| 210 DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno; |
| 211 return mmap_succeeded; |
| 212 } |
| 213 |
| 214 bool SharedMemory::Unmap() { |
| 215 if (memory_ == NULL) |
| 216 return false; |
| 217 |
| 218 munmap(memory_, mapped_size_); |
| 219 memory_ = NULL; |
| 220 mapped_size_ = 0; |
214 return true; | 221 return true; |
215 } | 222 } |
216 | 223 |
| 224 SharedMemoryHandle SharedMemory::handle() const { |
| 225 return FileDescriptor(mapped_file_, false); |
| 226 } |
| 227 |
| 228 void SharedMemory::Close() { |
| 229 Unmap(); |
| 230 |
| 231 if (mapped_file_ > 0) { |
| 232 close(mapped_file_); |
| 233 mapped_file_ = -1; |
| 234 } |
| 235 } |
| 236 |
| 237 void SharedMemory::Lock() { |
| 238 LockOrUnlockCommon(F_LOCK); |
| 239 } |
| 240 |
| 241 void SharedMemory::Unlock() { |
| 242 LockOrUnlockCommon(F_ULOCK); |
| 243 } |
| 244 |
217 bool SharedMemory::PrepareMapFile(FILE *fp) { | 245 bool SharedMemory::PrepareMapFile(FILE *fp) { |
218 DCHECK(mapped_file_ == -1); | 246 DCHECK(mapped_file_ == -1); |
219 if (fp == NULL) return false; | 247 if (fp == NULL) return false; |
220 | 248 |
221 // This function theoretically can block on the disk, but realistically | 249 // This function theoretically can block on the disk, but realistically |
222 // the temporary files we create will just go into the buffer cache | 250 // the temporary files we create will just go into the buffer cache |
223 // and be deleted before they ever make it out to disk. | 251 // and be deleted before they ever make it out to disk. |
224 base::ThreadRestrictions::ScopedAllowIO allow_io; | 252 base::ThreadRestrictions::ScopedAllowIO allow_io; |
225 | 253 |
226 file_util::ScopedFILE file_closer(fp); | 254 file_util::ScopedFILE file_closer(fp); |
227 | 255 |
228 mapped_file_ = dup(fileno(fp)); | 256 mapped_file_ = dup(fileno(fp)); |
229 if (mapped_file_ == -1) { | 257 if (mapped_file_ == -1) { |
230 if (errno == EMFILE) { | 258 if (errno == EMFILE) { |
231 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; | 259 LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; |
232 return false; | 260 return false; |
233 } else { | 261 } else { |
234 NOTREACHED() << "Call to dup failed, errno=" << errno; | 262 NOTREACHED() << "Call to dup failed, errno=" << errno; |
235 } | 263 } |
236 } | 264 } |
237 | 265 |
238 struct stat st; | 266 struct stat st; |
239 if (fstat(mapped_file_, &st)) | 267 if (fstat(mapped_file_, &st)) |
240 NOTREACHED(); | 268 NOTREACHED(); |
241 inode_ = st.st_ino; | 269 inode_ = st.st_ino; |
242 | 270 |
243 return true; | 271 return true; |
244 } | 272 } |
245 | 273 |
246 bool SharedMemory::Map(uint32 bytes) { | 274 // For the given shmem named |mem_name|, return a filename to mmap() |
247 if (mapped_file_ == -1) | 275 // (and possibly create). Modifies |filename|. Return false on |
| 276 // error, or true of we are happy. |
| 277 bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, |
| 278 FilePath* path) { |
| 279 // mem_name will be used for a filename; make sure it doesn't |
| 280 // contain anything which will confuse us. |
| 281 DCHECK(mem_name.find('/') == std::string::npos); |
| 282 DCHECK(mem_name.find('\0') == std::string::npos); |
| 283 |
| 284 FilePath temp_dir; |
| 285 if (!file_util::GetShmemTempDir(&temp_dir)) |
248 return false; | 286 return false; |
249 | 287 |
250 memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), | 288 *path = temp_dir.AppendASCII("com.google.chrome.shmem." + mem_name); |
251 MAP_SHARED, mapped_file_, 0); | |
252 | |
253 if (memory_) | |
254 mapped_size_ = bytes; | |
255 | |
256 bool mmap_succeeded = (memory_ != (void*)-1); | |
257 DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno; | |
258 return mmap_succeeded; | |
259 } | |
260 | |
261 bool SharedMemory::Unmap() { | |
262 if (memory_ == NULL) | |
263 return false; | |
264 | |
265 munmap(memory_, mapped_size_); | |
266 memory_ = NULL; | |
267 mapped_size_ = 0; | |
268 return true; | 289 return true; |
269 } | 290 } |
270 | 291 |
271 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, | |
272 SharedMemoryHandle *new_handle, | |
273 bool close_self) { | |
274 const int new_fd = dup(mapped_file_); | |
275 DCHECK(new_fd >= 0); | |
276 new_handle->fd = new_fd; | |
277 new_handle->auto_close = true; | |
278 | |
279 if (close_self) | |
280 Close(); | |
281 | |
282 return true; | |
283 } | |
284 | |
285 | |
286 void SharedMemory::Close() { | |
287 Unmap(); | |
288 | |
289 if (mapped_file_ > 0) { | |
290 close(mapped_file_); | |
291 mapped_file_ = -1; | |
292 } | |
293 } | |
294 | |
295 void SharedMemory::LockOrUnlockCommon(int function) { | 292 void SharedMemory::LockOrUnlockCommon(int function) { |
296 DCHECK(mapped_file_ >= 0); | 293 DCHECK(mapped_file_ >= 0); |
297 while (lockf(mapped_file_, function, 0) < 0) { | 294 while (lockf(mapped_file_, function, 0) < 0) { |
298 if (errno == EINTR) { | 295 if (errno == EINTR) { |
299 continue; | 296 continue; |
300 } else if (errno == ENOLCK) { | 297 } else if (errno == ENOLCK) { |
301 // temporary kernel resource exaustion | 298 // temporary kernel resource exaustion |
302 base::PlatformThread::Sleep(500); | 299 base::PlatformThread::Sleep(500); |
303 continue; | 300 continue; |
304 } else { | 301 } else { |
305 NOTREACHED() << "lockf() failed." | 302 NOTREACHED() << "lockf() failed." |
306 << " function:" << function | 303 << " function:" << function |
307 << " fd:" << mapped_file_ | 304 << " fd:" << mapped_file_ |
308 << " errno:" << errno | 305 << " errno:" << errno |
309 << " msg:" << safe_strerror(errno); | 306 << " msg:" << safe_strerror(errno); |
310 } | 307 } |
311 } | 308 } |
312 } | 309 } |
313 | 310 |
314 void SharedMemory::Lock() { | 311 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, |
315 LockOrUnlockCommon(F_LOCK); | 312 SharedMemoryHandle *new_handle, |
316 } | 313 bool close_self) { |
| 314 const int new_fd = dup(mapped_file_); |
| 315 DCHECK(new_fd >= 0); |
| 316 new_handle->fd = new_fd; |
| 317 new_handle->auto_close = true; |
317 | 318 |
318 void SharedMemory::Unlock() { | 319 if (close_self) |
319 LockOrUnlockCommon(F_ULOCK); | 320 Close(); |
320 } | |
321 | 321 |
322 SharedMemoryHandle SharedMemory::handle() const { | 322 return true; |
323 return FileDescriptor(mapped_file_, false); | |
324 } | 323 } |
325 | 324 |
326 } // namespace base | 325 } // namespace base |
OLD | NEW |