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

Side by Side Diff: util/mach/mach_message_server.cc

Issue 759023004: MachMessageServer: handle allocations more reasonably (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 12 matching lines...) Expand all
23 namespace crashpad { 23 namespace crashpad {
24 24
25 namespace { 25 namespace {
26 26
27 const int kNanosecondsPerMillisecond = 1E6; 27 const int kNanosecondsPerMillisecond = 1E6;
28 28
29 // TimerRunning determines whether |deadline| has passed. If |deadline| is in 29 // TimerRunning determines whether |deadline| has passed. If |deadline| is in
30 // the future, |*remaining_ms| is set to the number of milliseconds remaining, 30 // the future, |*remaining_ms| is set to the number of milliseconds remaining,
31 // which will always be a positive value, and this function returns true. If 31 // which will always be a positive value, and this function returns true. If
32 // |deadline| is zero (indicating that no timer is in effect), |*remaining_ms| 32 // |deadline| is zero (indicating that no timer is in effect), |*remaining_ms|
33 // is set to zero and this function returns true. Otherwise, this function 33 // is set to zero and this function returns true. Otherwise, this function sets
34 // returns false. |deadline| is specified on the same time base as is returned 34 // |*remaining_ms| to zero and returns false. |deadline| is specified on the
35 // by ClockMonotonicNanoseconds(). 35 // same time base as is returned by ClockMonotonicNanoseconds().
36 bool TimerRunning(uint64_t deadline, mach_msg_timeout_t* remaining_ms) { 36 bool TimerRunning(uint64_t deadline, mach_msg_timeout_t* remaining_ms) {
37 if (!deadline) { 37 if (!deadline) {
38 *remaining_ms = MACH_MSG_TIMEOUT_NONE; 38 *remaining_ms = MACH_MSG_TIMEOUT_NONE;
39 return true; 39 return true;
40 } 40 }
41 41
42 uint64_t now = ClockMonotonicNanoseconds(); 42 uint64_t now = ClockMonotonicNanoseconds();
43 43
44 if (now >= deadline) { 44 if (now >= deadline) {
45 *remaining_ms = 0;
45 return false; 46 return false;
46 } 47 }
47 48
48 uint64_t remaining = deadline - now; 49 uint64_t remaining = deadline - now;
49 50
50 // Round to the nearest millisecond, taking care not to overflow. 51 // Round to the nearest millisecond, taking care not to overflow.
51 const int kHalfMillisecondInNanoseconds = kNanosecondsPerMillisecond / 2; 52 const int kHalfMillisecondInNanoseconds = kNanosecondsPerMillisecond / 2;
52 mach_msg_timeout_t remaining_mach; 53 mach_msg_timeout_t remaining_mach;
53 if (remaining <= 54 if (remaining <=
54 std::numeric_limits<uint64_t>::max() - kHalfMillisecondInNanoseconds) { 55 std::numeric_limits<uint64_t>::max() - kHalfMillisecondInNanoseconds) {
55 remaining_mach = (remaining + kHalfMillisecondInNanoseconds) / 56 remaining_mach = (remaining + kHalfMillisecondInNanoseconds) /
56 kNanosecondsPerMillisecond; 57 kNanosecondsPerMillisecond;
57 } else { 58 } else {
58 remaining_mach = remaining / kNanosecondsPerMillisecond; 59 remaining_mach = remaining / kNanosecondsPerMillisecond;
59 } 60 }
60 61
61 if (remaining_mach == MACH_MSG_TIMEOUT_NONE) { 62 if (remaining_mach == MACH_MSG_TIMEOUT_NONE) {
63 *remaining_ms = 0;
62 return false; 64 return false;
63 } 65 }
64 66
65 *remaining_ms = remaining_mach; 67 *remaining_ms = remaining_mach;
66 return true; 68 return true;
67 } 69 }
68 70
69 } // namespace 71 } // namespace
70 72
71 // This implementation is based on 10.9.4 73 // This implementation is based on 10.9.4
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 ? max_request_size + trailer_alloc 126 ? max_request_size + trailer_alloc
125 : request_alloc; 127 : request_alloc;
126 128
127 mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize(); 129 mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize();
128 130
129 // mach_msg_server() and mach_msg_server_once() would consider whether 131 // mach_msg_server() and mach_msg_server_once() would consider whether
130 // |options| contains MACH_SEND_TRAILER and include MAX_TRAILER_SIZE in this 132 // |options| contains MACH_SEND_TRAILER and include MAX_TRAILER_SIZE in this
131 // computation if it does, but that option is ineffective on OS X. 133 // computation if it does, but that option is ineffective on OS X.
132 mach_msg_size_t reply_alloc = round_page(max_reply_size); 134 mach_msg_size_t reply_alloc = round_page(max_reply_size);
133 135
136 base::mac::ScopedMachVM request_scoper;
137 base::mac::ScopedMachVM reply_scoper;
138 bool received_any_request = false;
139
134 kern_return_t kr; 140 kern_return_t kr;
135 141
136 do { 142 do {
137 mach_msg_size_t this_request_alloc = request_alloc; 143 mach_msg_size_t this_request_alloc = request_alloc;
138 mach_msg_size_t this_request_size = request_size; 144 mach_msg_size_t this_request_size = request_size;
139 145
140 base::mac::ScopedMachVM request_scoper;
141 mach_msg_header_t* request_header = nullptr; 146 mach_msg_header_t* request_header = nullptr;
142 147
143 while (!request_scoper.address()) { 148 do {
144 vm_address_t request_addr; 149 if (request_scoper.size() != this_request_alloc) {
Robert Sesek 2014/12/01 20:59:17 Rather than equality, why not just if this_request
Mark Mentovai 2014/12/01 21:04:09 Robert Sesek wrote:
145 kr = vm_allocate(mach_task_self(), 150 // reset() first, so that two allocations don’t exist simultaneously.
146 &request_addr, 151 request_scoper.reset();
147 this_request_alloc, 152
148 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG)); 153 vm_address_t request_addr;
149 if (kr != KERN_SUCCESS) { 154 kr = vm_allocate(mach_task_self(),
150 return kr; 155 &request_addr,
156 this_request_alloc,
157 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
158 if (kr != KERN_SUCCESS) {
159 return kr;
160 }
161
162 request_scoper.reset(request_addr, this_request_alloc);
151 } 163 }
152 base::mac::ScopedMachVM trial_request_scoper(request_addr,
153 this_request_alloc);
154 request_header = reinterpret_cast<mach_msg_header_t*>(request_addr);
155 164
156 bool run_mach_msg_receive = false; 165 request_header =
166 reinterpret_cast<mach_msg_header_t*>(request_scoper.address());
167
157 do { 168 do {
158 // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop 169 // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop
159 // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms| 170 // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms|
160 // rather than allowing mach_msg() to retry using the original timeout 171 // rather than allowing mach_msg() to retry using the original timeout
161 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c 172 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
162 // mach_msg(). 173 // mach_msg(). Don’t return early here if nothing has ever been
174 // received: this method should always attempt to dequeue at least one
175 // message.
163 mach_msg_timeout_t remaining_ms; 176 mach_msg_timeout_t remaining_ms;
164 if (!TimerRunning(deadline, &remaining_ms)) { 177 if (!TimerRunning(deadline, &remaining_ms) && received_any_request) {
165 return MACH_RCV_TIMED_OUT; 178 return MACH_RCV_TIMED_OUT;
166 } 179 }
167 180
168 kr = mach_msg(request_header, 181 kr = mach_msg(request_header,
169 options | MACH_RCV_MSG, 182 options | MACH_RCV_MSG,
170 0, 183 0,
171 this_request_size, 184 this_request_size,
172 receive_port, 185 receive_port,
173 remaining_ms, 186 remaining_ms,
174 MACH_PORT_NULL); 187 MACH_PORT_NULL);
175 188
176 if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) { 189 if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) {
177 MACH_LOG(WARNING, kr) << "mach_msg: ignoring large message"; 190 MACH_LOG(WARNING, kr) << "mach_msg: ignoring large message";
178 run_mach_msg_receive = true;
179 } else if (kr == MACH_RCV_INTERRUPTED) {
180 run_mach_msg_receive = true;
181 } 191 }
182 } while (run_mach_msg_receive); 192 } while (
193 (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) ||
194 kr == MACH_RCV_INTERRUPTED);
183 195
184 if (kr == MACH_MSG_SUCCESS) { 196 if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeResize) {
185 request_scoper.swap(trial_request_scoper);
186 } else if (kr == MACH_RCV_TOO_LARGE &&
187 receive_large == kReceiveLargeResize) {
188 this_request_size = 197 this_request_size =
189 round_page(request_header->msgh_size + trailer_alloc); 198 round_page(request_header->msgh_size + trailer_alloc);
190 this_request_alloc = this_request_size; 199 this_request_alloc = this_request_size;
191 } else { 200 } else if (kr != MACH_MSG_SUCCESS) {
192 return kr; 201 return kr;
193 } 202 }
203 } while (kr != MACH_MSG_SUCCESS);
204
205 received_any_request = true;
206
207 if (reply_scoper.size() == 0) {
208 vm_address_t reply_addr;
209 kr = vm_allocate(mach_task_self(),
210 &reply_addr,
211 reply_alloc,
212 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
213 if (kr != KERN_SUCCESS) {
214 return kr;
215 }
216
217 reply_scoper.reset(reply_addr, reply_alloc);
194 } 218 }
195 219
196 vm_address_t reply_addr;
197 kr = vm_allocate(mach_task_self(),
198 &reply_addr,
199 reply_alloc,
200 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
201 if (kr != KERN_SUCCESS) {
202 return kr;
203 }
204
205 base::mac::ScopedMachVM reply_scoper(reply_addr, reply_alloc);
206
207 mach_msg_header_t* reply_header = 220 mach_msg_header_t* reply_header =
208 reinterpret_cast<mach_msg_header_t*>(reply_addr); 221 reinterpret_cast<mach_msg_header_t*>(reply_scoper.address());
209 bool destroy_complex_request = false; 222 bool destroy_complex_request = false;
210 interface->MachMessageServerFunction( 223 interface->MachMessageServerFunction(
211 request_header, reply_header, &destroy_complex_request); 224 request_header, reply_header, &destroy_complex_request);
212 225
213 if (!(reply_header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 226 if (!(reply_header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
214 // This only works if the reply message is not complex, because otherwise, 227 // This only works if the reply message is not complex, because otherwise,
215 // the location of the RetCode field is not known. It should be possible 228 // the location of the RetCode field is not known. It should be possible
216 // to locate the RetCode field by looking beyond the descriptors in a 229 // to locate the RetCode field by looking beyond the descriptors in a
217 // complex reply message, but this is not currently done. This behavior 230 // complex reply message, but this is not currently done. This behavior
218 // has not proven itself necessary in practice, and it’s not done by 231 // has not proven itself necessary in practice, and it’s not done by
(...skipping 30 matching lines...) Expand all
249 262
250 bool running; 263 bool running;
251 do { 264 do {
252 // If |options| contains MACH_SEND_INTERRUPT, retry mach_msg() in a loop 265 // If |options| contains MACH_SEND_INTERRUPT, retry mach_msg() in a loop
253 // when it returns MACH_SEND_INTERRUPTED to recompute |remaining_ms| 266 // when it returns MACH_SEND_INTERRUPTED to recompute |remaining_ms|
254 // rather than allowing mach_msg() to retry using the original timeout 267 // rather than allowing mach_msg() to retry using the original timeout
255 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c 268 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
256 // mach_msg(). 269 // mach_msg().
257 mach_msg_timeout_t remaining_ms; 270 mach_msg_timeout_t remaining_ms;
258 running = TimerRunning(deadline, &remaining_ms); 271 running = TimerRunning(deadline, &remaining_ms);
259 if (!running) { 272
260 // Don’t return just yet. If the timer ran out in between the time the 273 // Don’t return just yet even if |running| is false. If the timer ran
261 // request was received and now, at least try to send the response. 274 // out in between the time the request was received and now, at least
262 remaining_ms = 0; 275 // try to send the response.
263 }
264 276
265 kr = mach_msg(reply_header, 277 kr = mach_msg(reply_header,
266 send_options, 278 send_options,
267 reply_header->msgh_size, 279 reply_header->msgh_size,
268 0, 280 0,
269 MACH_PORT_NULL, 281 MACH_PORT_NULL,
270 remaining_ms, 282 remaining_ms,
271 MACH_PORT_NULL); 283 MACH_PORT_NULL);
272 } while (kr == MACH_SEND_INTERRUPTED); 284 } while (kr == MACH_SEND_INTERRUPTED);
273 285
(...skipping 10 matching lines...) Expand all
284 // persistent mode, and just return success when not in persistent mode. 296 // persistent mode, and just return success when not in persistent mode.
285 return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr; 297 return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr;
286 } 298 }
287 } 299 }
288 } while (persistent == kPersistent); 300 } while (persistent == kPersistent);
289 301
290 return kr; 302 return kr;
291 } 303 }
292 304
293 } // namespace crashpad 305 } // namespace crashpad
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698