vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 4 | |
brettw@chromium.org | 4329aa7 | 2013-03-30 02:46:23 +0900 | [diff] [blame] | 5 | #include "base/memory/shared_memory.h" |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 6 | |
avi@google.com | 8e4b653 | 2008-12-12 04:51:24 +0900 | [diff] [blame] | 7 | #include <errno.h> |
tc@google.com | 7e1fb1d | 2008-08-13 07:40:21 +0900 | [diff] [blame] | 8 | #include <fcntl.h> |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 9 | #include <sys/mman.h> |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 10 | #include <sys/stat.h> |
jln@chromium.org | e77bef7 | 2013-07-03 08:31:55 +0900 | [diff] [blame] | 11 | #include <sys/types.h> |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 12 | #include <unistd.h> |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 13 | |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 14 | #include "base/file_util.h" |
vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 15 | #include "base/lazy_instance.h" |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 16 | #include "base/logging.h" |
simonjam@chromium.org | 2afd406 | 2013-05-10 08:15:40 +0900 | [diff] [blame] | 17 | #include "base/process_util.h" |
tschmelcher@chromium.org | 90a3f8a | 2009-10-14 03:27:40 +0900 | [diff] [blame] | 18 | #include "base/safe_strerror_posix.h" |
avi@chromium.org | 17f6062 | 2013-06-08 03:37:07 +0900 | [diff] [blame] | 19 | #include "base/strings/utf_string_conversions.h" |
vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 20 | #include "base/synchronization/lock.h" |
simonjam@chromium.org | 2afd406 | 2013-05-10 08:15:40 +0900 | [diff] [blame] | 21 | #include "base/threading/platform_thread.h" |
brettw@chromium.org | 5b5f5e0 | 2011-01-01 10:01:06 +0900 | [diff] [blame] | 22 | #include "base/threading/thread_restrictions.h" |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 23 | |
mark@chromium.org | 13aa8aa | 2011-04-22 13:15:13 +0900 | [diff] [blame] | 24 | #if defined(OS_MACOSX) |
| 25 | #include "base/mac/foundation_util.h" |
| 26 | #endif // OS_MACOSX |
| 27 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 28 | #if defined(OS_ANDROID) |
| 29 | #include "base/os_compat_android.h" |
| 30 | #include "third_party/ashmem/ashmem.h" |
| 31 | #endif |
| 32 | |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 33 | namespace base { |
| 34 | |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 35 | namespace { |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 36 | |
avi@google.com | 9e0cc15 | 2008-08-14 04:59:07 +0900 | [diff] [blame] | 37 | // Paranoia. Semaphores and shared memory segments should live in different |
| 38 | // namespaces, but who knows what's out there. |
| 39 | const char kSemaphoreSuffix[] = "-sem"; |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 40 | |
vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 41 | LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; |
| 42 | |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | SharedMemory::SharedMemory() |
| 46 | : mapped_file_(-1), |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 47 | inode_(0), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 48 | mapped_size_(0), |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 49 | memory_(NULL), |
| 50 | read_only_(false), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 51 | requested_size_(0) { |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) |
agl@chromium.org | 42bbb99 | 2009-02-12 03:59:20 +0900 | [diff] [blame] | 55 | : mapped_file_(handle.fd), |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 56 | inode_(0), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 57 | mapped_size_(0), |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 58 | memory_(NULL), |
| 59 | read_only_(read_only), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 60 | requested_size_(0) { |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 61 | struct stat st; |
| 62 | if (fstat(handle.fd, &st) == 0) { |
| 63 | // If fstat fails, then the file descriptor is invalid and we'll learn this |
| 64 | // fact when Map() fails. |
| 65 | inode_ = st.st_ino; |
| 66 | } |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, |
| 70 | ProcessHandle process) |
agl@chromium.org | 42bbb99 | 2009-02-12 03:59:20 +0900 | [diff] [blame] | 71 | : mapped_file_(handle.fd), |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 72 | inode_(0), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 73 | mapped_size_(0), |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 74 | memory_(NULL), |
| 75 | read_only_(read_only), |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 76 | requested_size_(0) { |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 77 | // We don't handle this case yet (note the ignored parameter); let's die if |
| 78 | // someone comes calling. |
| 79 | NOTREACHED(); |
| 80 | } |
| 81 | |
| 82 | SharedMemory::~SharedMemory() { |
| 83 | Close(); |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 84 | } |
| 85 | |
agl@chromium.org | 42bbb99 | 2009-02-12 03:59:20 +0900 | [diff] [blame] | 86 | // static |
| 87 | bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { |
| 88 | return handle.fd >= 0; |
| 89 | } |
| 90 | |
phajdan.jr@chromium.org | fa1476b | 2009-03-17 01:45:36 +0900 | [diff] [blame] | 91 | // static |
| 92 | SharedMemoryHandle SharedMemory::NULLHandle() { |
| 93 | return SharedMemoryHandle(); |
| 94 | } |
| 95 | |
hclam@chromium.org | 32300e2 | 2009-05-19 02:46:31 +0900 | [diff] [blame] | 96 | // static |
| 97 | void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { |
kushi.p@gmail.com | e486977 | 2011-04-22 22:13:07 +0900 | [diff] [blame] | 98 | DCHECK_GE(handle.fd, 0); |
piman@google.com | 36c0625 | 2011-02-24 06:37:41 +0900 | [diff] [blame] | 99 | if (HANDLE_EINTR(close(handle.fd)) < 0) |
brettw@chromium.org | 5faed3c | 2011-10-27 06:48:00 +0900 | [diff] [blame] | 100 | DPLOG(ERROR) << "close"; |
hclam@chromium.org | 32300e2 | 2009-05-19 02:46:31 +0900 | [diff] [blame] | 101 | } |
| 102 | |
simonjam@chromium.org | 2afd406 | 2013-05-10 08:15:40 +0900 | [diff] [blame] | 103 | // static |
| 104 | size_t SharedMemory::GetHandleLimit() { |
| 105 | return base::GetMaxFds(); |
| 106 | } |
| 107 | |
cevans@chromium.org | 447ba04 | 2013-01-10 11:16:24 +0900 | [diff] [blame] | 108 | bool SharedMemory::CreateAndMapAnonymous(size_t size) { |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 109 | return CreateAnonymous(size) && Map(size); |
| 110 | } |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 111 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 112 | #if !defined(OS_ANDROID) |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 113 | // Chromium mostly only uses the unique/private shmem as specified by |
| 114 | // "name == L"". The exception is in the StatsTable. |
| 115 | // TODO(jrg): there is no way to "clean up" all unused named shmem if |
| 116 | // we restart from a crash. (That isn't a new problem, but it is a problem.) |
| 117 | // In case we want to delete it later, it may be useful to save the value |
| 118 | // of mem_filename after FilePathForMemoryName(). |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 119 | bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { |
mhm@chromium.org | 73bfc43 | 2011-03-01 11:48:05 +0900 | [diff] [blame] | 120 | DCHECK_EQ(-1, mapped_file_); |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 121 | if (options.size == 0) return false; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 122 | |
cevans@chromium.org | 447ba04 | 2013-01-10 11:16:24 +0900 | [diff] [blame] | 123 | if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) |
| 124 | return false; |
| 125 | |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 126 | // This function theoretically can block on the disk, but realistically |
| 127 | // the temporary files we create will just go into the buffer cache |
| 128 | // and be deleted before they ever make it out to disk. |
| 129 | base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 130 | |
| 131 | FILE *fp; |
| 132 | bool fix_size = true; |
| 133 | |
| 134 | FilePath path; |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 135 | if (options.name == NULL || options.name->empty()) { |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 136 | // It doesn't make sense to have a open-existing private piece of shmem |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 137 | DCHECK(!options.open_existing); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 138 | // Q: Why not use the shm_open() etc. APIs? |
| 139 | // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU |
mcgrathr@chromium.org | 569a423 | 2011-12-07 03:07:05 +0900 | [diff] [blame] | 140 | fp = file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 141 | |
viettrungluu@chromium.org | ea7895a | 2013-02-01 05:17:12 +0900 | [diff] [blame] | 142 | // Deleting the file prevents anyone else from mapping it in (making it |
| 143 | // private), and prevents the need for cleanup (once the last fd is closed, |
| 144 | // it is truly freed). |
| 145 | if (fp) { |
| 146 | if (unlink(path.value().c_str())) |
| 147 | PLOG(WARNING) << "unlink"; |
| 148 | } |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 149 | } else { |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 150 | if (!FilePathForMemoryName(*options.name, &path)) |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 151 | return false; |
| 152 | |
jln@chromium.org | e77bef7 | 2013-07-03 08:31:55 +0900 | [diff] [blame] | 153 | // Make sure that the file is opened without any permission |
| 154 | // to other users on the system. |
| 155 | const mode_t kOwnerOnly = S_IRUSR | S_IWUSR; |
| 156 | |
| 157 | // First, try to create the file. |
| 158 | int fd = HANDLE_EINTR( |
| 159 | open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly)); |
| 160 | if (fd == -1 && options.open_existing) { |
| 161 | // If this doesn't work, try and open an existing file in append mode. |
| 162 | // Opening an existing file in a world writable directory has two main |
| 163 | // security implications: |
| 164 | // - Attackers could plant a file under their control, so ownership of |
| 165 | // the file is checked below. |
| 166 | // - Attackers could plant a symbolic link so that an unexpected file |
| 167 | // is opened, so O_NOFOLLOW is passed to open(). |
| 168 | fd = HANDLE_EINTR( |
| 169 | open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW)); |
| 170 | |
| 171 | // Check that the current user owns the file. |
| 172 | // If uid != euid, then a more complex permission model is used and this |
| 173 | // API is not appropriate. |
| 174 | const uid_t real_uid = getuid(); |
| 175 | const uid_t effective_uid = geteuid(); |
| 176 | struct stat sb; |
| 177 | if (fd >= 0 && |
| 178 | (fstat(fd, &sb) != 0 || sb.st_uid != real_uid || |
| 179 | sb.st_uid != effective_uid)) { |
| 180 | LOG(ERROR) << |
| 181 | "Invalid owner when opening existing shared memory file."; |
| 182 | HANDLE_EINTR(close(fd)); |
| 183 | return false; |
| 184 | } |
| 185 | |
| 186 | // An existing file was opened, so its size should not be fixed. |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 187 | fix_size = false; |
| 188 | } |
jln@chromium.org | e77bef7 | 2013-07-03 08:31:55 +0900 | [diff] [blame] | 189 | fp = NULL; |
| 190 | if (fd >= 0) { |
| 191 | // "a+" is always appropriate: if it's a new file, a+ is similar to w+. |
| 192 | fp = fdopen(fd, "a+"); |
| 193 | } |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 194 | } |
| 195 | if (fp && fix_size) { |
| 196 | // Get current size. |
| 197 | struct stat stat; |
gbillock@chromium.org | 6ee384d | 2011-06-28 02:24:27 +0900 | [diff] [blame] | 198 | if (fstat(fileno(fp), &stat) != 0) { |
| 199 | file_util::CloseFile(fp); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 200 | return false; |
gbillock@chromium.org | 6ee384d | 2011-06-28 02:24:27 +0900 | [diff] [blame] | 201 | } |
cevans@chromium.org | 447ba04 | 2013-01-10 11:16:24 +0900 | [diff] [blame] | 202 | const size_t current_size = stat.st_size; |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 203 | if (current_size != options.size) { |
| 204 | if (HANDLE_EINTR(ftruncate(fileno(fp), options.size)) != 0) { |
gbillock@chromium.org | 6ee384d | 2011-06-28 02:24:27 +0900 | [diff] [blame] | 205 | file_util::CloseFile(fp); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 206 | return false; |
gbillock@chromium.org | 6ee384d | 2011-06-28 02:24:27 +0900 | [diff] [blame] | 207 | } |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 208 | } |
jschuh@chromium.org | c41be7b | 2013-03-28 11:02:18 +0900 | [diff] [blame] | 209 | requested_size_ = options.size; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 210 | } |
| 211 | if (fp == NULL) { |
| 212 | #if !defined(OS_MACOSX) |
| 213 | PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; |
| 214 | FilePath dir = path.DirName(); |
| 215 | if (access(dir.value().c_str(), W_OK | X_OK) < 0) { |
| 216 | PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); |
| 217 | if (dir.value() == "/dev/shm") { |
| 218 | LOG(FATAL) << "This is frequently caused by incorrect permissions on " |
brettw@chromium.org | 5faed3c | 2011-10-27 06:48:00 +0900 | [diff] [blame] | 219 | << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 220 | } |
| 221 | } |
| 222 | #else |
| 223 | PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; |
| 224 | #endif |
agl@chromium.org | 8c15834 | 2008-11-18 09:21:37 +0900 | [diff] [blame] | 225 | return false; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 226 | } |
agl@chromium.org | 8c15834 | 2008-11-18 09:21:37 +0900 | [diff] [blame] | 227 | |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 228 | return PrepareMapFile(fp); |
avi@google.com | 9e0cc15 | 2008-08-14 04:59:07 +0900 | [diff] [blame] | 229 | } |
| 230 | |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 231 | // Our current implementation of shmem is with mmap()ing of files. |
| 232 | // These files need to be deleted explicitly. |
| 233 | // In practice this call is only needed for unit tests. |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 234 | bool SharedMemory::Delete(const std::string& name) { |
evan@chromium.org | bd3a0d6 | 2009-09-17 02:32:11 +0900 | [diff] [blame] | 235 | FilePath path; |
| 236 | if (!FilePathForMemoryName(name, &path)) |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 237 | return false; |
| 238 | |
brettw@chromium.org | 10b6412 | 2013-07-12 02:36:07 +0900 | [diff] [blame^] | 239 | if (PathExists(path)) |
brettw@chromium.org | e9f9948 | 2013-07-02 04:41:02 +0900 | [diff] [blame] | 240 | return base::Delete(path, false); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 241 | |
| 242 | // Doesn't exist, so success. |
| 243 | return true; |
| 244 | } |
| 245 | |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 246 | bool SharedMemory::Open(const std::string& name, bool read_only) { |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 247 | FilePath path; |
| 248 | if (!FilePathForMemoryName(name, &path)) |
| 249 | return false; |
| 250 | |
avi@google.com | 9e0cc15 | 2008-08-14 04:59:07 +0900 | [diff] [blame] | 251 | read_only_ = read_only; |
agl@chromium.org | 69e0a49 | 2008-11-18 09:21:05 +0900 | [diff] [blame] | 252 | |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 253 | const char *mode = read_only ? "r" : "r+"; |
| 254 | FILE *fp = file_util::OpenFile(path, mode); |
| 255 | return PrepareMapFile(fp); |
avi@google.com | 9e0cc15 | 2008-08-14 04:59:07 +0900 | [diff] [blame] | 256 | } |
| 257 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 258 | #endif // !defined(OS_ANDROID) |
| 259 | |
vitalybuka@chromium.org | 222e34c | 2013-01-16 18:02:34 +0900 | [diff] [blame] | 260 | bool SharedMemory::MapAt(off_t offset, size_t bytes) { |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 261 | if (mapped_file_ == -1) |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 262 | return false; |
agl@chromium.org | 69e0a49 | 2008-11-18 09:21:05 +0900 | [diff] [blame] | 263 | |
cevans@chromium.org | 447ba04 | 2013-01-10 11:16:24 +0900 | [diff] [blame] | 264 | if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) |
| 265 | return false; |
| 266 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 267 | #if defined(OS_ANDROID) |
aelias@chromium.org | d128809 | 2013-03-29 09:10:06 +0900 | [diff] [blame] | 268 | // On Android, Map can be called with a size and offset of zero to use the |
| 269 | // ashmem-determined size. |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 270 | if (bytes == 0) { |
aelias@chromium.org | d128809 | 2013-03-29 09:10:06 +0900 | [diff] [blame] | 271 | DCHECK_EQ(0, offset); |
michaelbai@google.com | 01ef2f2 | 2011-07-08 05:46:50 +0900 | [diff] [blame] | 272 | int ashmem_bytes = ashmem_get_size_region(mapped_file_); |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 273 | if (ashmem_bytes < 0) |
| 274 | return false; |
aelias@chromium.org | d128809 | 2013-03-29 09:10:06 +0900 | [diff] [blame] | 275 | bytes = ashmem_bytes; |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 276 | } |
| 277 | #endif |
| 278 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 279 | memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), |
vitalybuka@chromium.org | 222e34c | 2013-01-16 18:02:34 +0900 | [diff] [blame] | 280 | MAP_SHARED, mapped_file_, offset); |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 281 | |
raymes@chromium.org | fd41cac | 2012-04-24 06:00:06 +0900 | [diff] [blame] | 282 | bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL; |
dalecurtis@chromium.org | 9329193 | 2012-08-18 11:17:26 +0900 | [diff] [blame] | 283 | if (mmap_succeeded) { |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 284 | mapped_size_ = bytes; |
dalecurtis@chromium.org | 9329193 | 2012-08-18 11:17:26 +0900 | [diff] [blame] | 285 | DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & |
| 286 | (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); |
| 287 | } else { |
raymes@chromium.org | fd41cac | 2012-04-24 06:00:06 +0900 | [diff] [blame] | 288 | memory_ = NULL; |
dalecurtis@chromium.org | 9329193 | 2012-08-18 11:17:26 +0900 | [diff] [blame] | 289 | } |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 290 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 291 | return mmap_succeeded; |
| 292 | } |
| 293 | |
| 294 | bool SharedMemory::Unmap() { |
| 295 | if (memory_ == NULL) |
| 296 | return false; |
| 297 | |
| 298 | munmap(memory_, mapped_size_); |
| 299 | memory_ = NULL; |
| 300 | mapped_size_ = 0; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 301 | return true; |
| 302 | } |
| 303 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 304 | SharedMemoryHandle SharedMemory::handle() const { |
| 305 | return FileDescriptor(mapped_file_, false); |
| 306 | } |
| 307 | |
| 308 | void SharedMemory::Close() { |
| 309 | Unmap(); |
| 310 | |
| 311 | if (mapped_file_ > 0) { |
piman@google.com | 36c0625 | 2011-02-24 06:37:41 +0900 | [diff] [blame] | 312 | if (HANDLE_EINTR(close(mapped_file_)) < 0) |
| 313 | PLOG(ERROR) << "close"; |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 314 | mapped_file_ = -1; |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | void SharedMemory::Lock() { |
vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 319 | g_thread_lock_.Get().Acquire(); |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 320 | LockOrUnlockCommon(F_LOCK); |
| 321 | } |
| 322 | |
| 323 | void SharedMemory::Unlock() { |
| 324 | LockOrUnlockCommon(F_ULOCK); |
vandebo@chromium.org | 439b3d2 | 2012-02-25 15:28:56 +0900 | [diff] [blame] | 325 | g_thread_lock_.Get().Release(); |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 326 | } |
| 327 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 328 | #if !defined(OS_ANDROID) |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 329 | bool SharedMemory::PrepareMapFile(FILE *fp) { |
mhm@chromium.org | 73bfc43 | 2011-03-01 11:48:05 +0900 | [diff] [blame] | 330 | DCHECK_EQ(-1, mapped_file_); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 331 | if (fp == NULL) return false; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 332 | |
evan@chromium.org | 7c9cd8b | 2010-10-23 14:19:20 +0900 | [diff] [blame] | 333 | // This function theoretically can block on the disk, but realistically |
| 334 | // the temporary files we create will just go into the buffer cache |
| 335 | // and be deleted before they ever make it out to disk. |
| 336 | base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 337 | |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 338 | file_util::ScopedFILE file_closer(fp); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 339 | |
| 340 | mapped_file_ = dup(fileno(fp)); |
stuartmorgan@chromium.org | 8a8e966 | 2009-06-13 06:15:33 +0900 | [diff] [blame] | 341 | if (mapped_file_ == -1) { |
| 342 | if (errno == EMFILE) { |
| 343 | LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; |
| 344 | return false; |
| 345 | } else { |
| 346 | NOTREACHED() << "Call to dup failed, errno=" << errno; |
| 347 | } |
| 348 | } |
agl@chromium.org | 31de02e | 2009-02-20 11:00:04 +0900 | [diff] [blame] | 349 | |
| 350 | struct stat st; |
| 351 | if (fstat(mapped_file_, &st)) |
| 352 | NOTREACHED(); |
| 353 | inode_ = st.st_ino; |
| 354 | |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 355 | return true; |
| 356 | } |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 357 | #endif |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 358 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 359 | // For the given shmem named |mem_name|, return a filename to mmap() |
| 360 | // (and possibly create). Modifies |filename|. Return false on |
| 361 | // error, or true of we are happy. |
| 362 | bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, |
| 363 | FilePath* path) { |
| 364 | // mem_name will be used for a filename; make sure it doesn't |
| 365 | // contain anything which will confuse us. |
mhm@chromium.org | 73bfc43 | 2011-03-01 11:48:05 +0900 | [diff] [blame] | 366 | DCHECK_EQ(std::string::npos, mem_name.find('/')); |
| 367 | DCHECK_EQ(std::string::npos, mem_name.find('\0')); |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 368 | |
| 369 | FilePath temp_dir; |
mcgrathr@chromium.org | 569a423 | 2011-12-07 03:07:05 +0900 | [diff] [blame] | 370 | if (!file_util::GetShmemTempDir(&temp_dir, false)) |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 371 | return false; |
agl@chromium.org | 69e0a49 | 2008-11-18 09:21:05 +0900 | [diff] [blame] | 372 | |
mark@chromium.org | 13aa8aa | 2011-04-22 13:15:13 +0900 | [diff] [blame] | 373 | #if !defined(OS_MACOSX) |
| 374 | #if defined(GOOGLE_CHROME_BUILD) |
| 375 | std::string name_base = std::string("com.google.Chrome"); |
| 376 | #else |
| 377 | std::string name_base = std::string("org.chromium.Chromium"); |
| 378 | #endif |
| 379 | #else // OS_MACOSX |
| 380 | std::string name_base = std::string(base::mac::BaseBundleID()); |
| 381 | #endif // OS_MACOSX |
| 382 | *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 383 | return true; |
| 384 | } |
| 385 | |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 386 | void SharedMemory::LockOrUnlockCommon(int function) { |
pkasting@chromium.org | d23fe1a | 2011-04-01 05:34:25 +0900 | [diff] [blame] | 387 | DCHECK_GE(mapped_file_, 0); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 388 | while (lockf(mapped_file_, function, 0) < 0) { |
| 389 | if (errno == EINTR) { |
| 390 | continue; |
| 391 | } else if (errno == ENOLCK) { |
| 392 | // temporary kernel resource exaustion |
tedvessenes@gmail.com | aaa6303 | 2012-01-01 07:53:51 +0900 | [diff] [blame] | 393 | base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 394 | continue; |
| 395 | } else { |
| 396 | NOTREACHED() << "lockf() failed." |
| 397 | << " function:" << function |
| 398 | << " fd:" << mapped_file_ |
| 399 | << " errno:" << errno |
tschmelcher@chromium.org | 90a3f8a | 2009-10-14 03:27:40 +0900 | [diff] [blame] | 400 | << " msg:" << safe_strerror(errno); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 401 | } |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 402 | } |
| 403 | } |
| 404 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 405 | bool SharedMemory::ShareToProcessCommon(ProcessHandle process, |
| 406 | SharedMemoryHandle *new_handle, |
| 407 | bool close_self) { |
| 408 | const int new_fd = dup(mapped_file_); |
darin@chromium.org | 93d40b0 | 2012-11-20 15:54:42 +0900 | [diff] [blame] | 409 | if (new_fd < 0) { |
| 410 | DPLOG(ERROR) << "dup() failed."; |
| 411 | return false; |
| 412 | } |
| 413 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 414 | new_handle->fd = new_fd; |
| 415 | new_handle->auto_close = true; |
avi@google.com | 3a20898 | 2008-08-13 06:06:40 +0900 | [diff] [blame] | 416 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 417 | if (close_self) |
| 418 | Close(); |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame] | 419 | |
erg@google.com | 37c078e | 2011-01-11 09:50:59 +0900 | [diff] [blame] | 420 | return true; |
agl@chromium.org | 42bbb99 | 2009-02-12 03:59:20 +0900 | [diff] [blame] | 421 | } |
| 422 | |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 423 | } // namespace base |