OLD | NEW |
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, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "util/mach/mach_message_server.h" | 15 #include "util/mach/mach_message_server.h" |
16 | 16 |
17 #include <limits> | 17 #include <limits> |
18 | 18 |
| 19 #include "base/mac/mach_logging.h" |
19 #include "base/mac/scoped_mach_vm.h" | 20 #include "base/mac/scoped_mach_vm.h" |
20 #include "util/misc/clock.h" | 21 #include "util/misc/clock.h" |
21 | 22 |
22 namespace crashpad { | 23 namespace crashpad { |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 const int kNanosecondsPerMillisecond = 1E6; | 27 const int kNanosecondsPerMillisecond = 1E6; |
27 | 28 |
28 // TimerRunning determines whether |deadline| has passed. If |deadline| is in | 29 // TimerRunning determines whether |deadline| has passed. If |deadline| is in |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 // mach_msg_server(), the |nonblocking| parameter to control blocking directly, | 76 // mach_msg_server(), the |nonblocking| parameter to control blocking directly, |
76 // and the |timeout_ms| parameter allowing this function to not block | 77 // and the |timeout_ms| parameter allowing this function to not block |
77 // indefinitely. | 78 // indefinitely. |
78 // | 79 // |
79 // static | 80 // static |
80 mach_msg_return_t MachMessageServer::Run(Interface* interface, | 81 mach_msg_return_t MachMessageServer::Run(Interface* interface, |
81 mach_port_t receive_port, | 82 mach_port_t receive_port, |
82 mach_msg_options_t options, | 83 mach_msg_options_t options, |
83 Persistent persistent, | 84 Persistent persistent, |
84 Nonblocking nonblocking, | 85 Nonblocking nonblocking, |
| 86 ReceiveLarge receive_large, |
85 mach_msg_timeout_t timeout_ms) { | 87 mach_msg_timeout_t timeout_ms) { |
86 options &= ~(MACH_RCV_MSG | MACH_SEND_MSG); | 88 options &= ~(MACH_RCV_MSG | MACH_SEND_MSG); |
87 | 89 |
88 mach_msg_options_t timeout_options = MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT | | 90 mach_msg_options_t timeout_options = MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT | |
89 MACH_RCV_INTERRUPT | MACH_SEND_INTERRUPT; | 91 MACH_RCV_INTERRUPT | MACH_SEND_INTERRUPT; |
90 | 92 |
91 uint64_t deadline; | 93 uint64_t deadline; |
92 if (nonblocking == kNonblocking) { | 94 if (nonblocking == kNonblocking) { |
93 options |= timeout_options; | 95 options |= timeout_options; |
94 deadline = 0; | 96 deadline = 0; |
95 } else if (timeout_ms != MACH_MSG_TIMEOUT_NONE) { | 97 } else if (timeout_ms != MACH_MSG_TIMEOUT_NONE) { |
96 options |= timeout_options; | 98 options |= timeout_options; |
97 deadline = ClockMonotonicNanoseconds() + | 99 deadline = ClockMonotonicNanoseconds() + |
98 implicit_cast<uint64_t>(timeout_ms) * kNanosecondsPerMillisecond; | 100 implicit_cast<uint64_t>(timeout_ms) * kNanosecondsPerMillisecond; |
99 } else { | 101 } else { |
100 options &= ~timeout_options; | 102 options &= ~timeout_options; |
101 deadline = 0; | 103 deadline = 0; |
102 } | 104 } |
103 | 105 |
| 106 if (receive_large == kReceiveLargeResize) { |
| 107 options |= MACH_RCV_LARGE; |
| 108 } else { |
| 109 options &= ~MACH_RCV_LARGE; |
| 110 } |
| 111 |
104 mach_msg_size_t trailer_alloc = REQUESTED_TRAILER_SIZE(options); | 112 mach_msg_size_t trailer_alloc = REQUESTED_TRAILER_SIZE(options); |
105 mach_msg_size_t max_request_size = interface->MachMessageServerRequestSize(); | 113 mach_msg_size_t max_request_size = interface->MachMessageServerRequestSize(); |
106 mach_msg_size_t request_alloc = round_page(max_request_size + trailer_alloc); | 114 mach_msg_size_t request_alloc = round_page(max_request_size + trailer_alloc); |
107 mach_msg_size_t request_size = (options & MACH_RCV_LARGE) | 115 mach_msg_size_t request_size = (receive_large == kReceiveLargeResize) |
108 ? request_alloc | 116 ? request_alloc |
109 : max_request_size + trailer_alloc; | 117 : max_request_size + trailer_alloc; |
110 | 118 |
111 mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize(); | 119 mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize(); |
112 mach_msg_size_t reply_alloc = round_page( | 120 mach_msg_size_t reply_alloc = round_page( |
113 (options & MACH_SEND_TRAILER) ? (max_reply_size + MAX_TRAILER_SIZE) | 121 (options & MACH_SEND_TRAILER) ? (max_reply_size + MAX_TRAILER_SIZE) |
114 : max_reply_size); | 122 : max_reply_size); |
115 | 123 |
116 kern_return_t kr; | 124 kern_return_t kr; |
117 | 125 |
(...skipping 10 matching lines...) Expand all Loading... |
128 &request_addr, | 136 &request_addr, |
129 this_request_alloc, | 137 this_request_alloc, |
130 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG)); | 138 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG)); |
131 if (kr != KERN_SUCCESS) { | 139 if (kr != KERN_SUCCESS) { |
132 return kr; | 140 return kr; |
133 } | 141 } |
134 base::mac::ScopedMachVM trial_request_scoper(request_addr, | 142 base::mac::ScopedMachVM trial_request_scoper(request_addr, |
135 this_request_alloc); | 143 this_request_alloc); |
136 request_header = reinterpret_cast<mach_msg_header_t*>(request_addr); | 144 request_header = reinterpret_cast<mach_msg_header_t*>(request_addr); |
137 | 145 |
| 146 bool run_mach_msg_receive = false; |
138 do { | 147 do { |
139 // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop | 148 // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop |
140 // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms| | 149 // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms| |
141 // rather than allowing mach_msg() to retry using the original timeout | 150 // rather than allowing mach_msg() to retry using the original timeout |
142 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c | 151 // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c |
143 // mach_msg(). | 152 // mach_msg(). |
144 mach_msg_timeout_t remaining_ms; | 153 mach_msg_timeout_t remaining_ms; |
145 if (!TimerRunning(deadline, &remaining_ms)) { | 154 if (!TimerRunning(deadline, &remaining_ms)) { |
146 return MACH_RCV_TIMED_OUT; | 155 return MACH_RCV_TIMED_OUT; |
147 } | 156 } |
148 | 157 |
149 kr = mach_msg(request_header, | 158 kr = mach_msg(request_header, |
150 options | MACH_RCV_MSG, | 159 options | MACH_RCV_MSG, |
151 0, | 160 0, |
152 this_request_size, | 161 this_request_size, |
153 receive_port, | 162 receive_port, |
154 remaining_ms, | 163 remaining_ms, |
155 MACH_PORT_NULL); | 164 MACH_PORT_NULL); |
156 } while (kr == MACH_RCV_INTERRUPTED); | 165 |
| 166 if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) { |
| 167 MACH_LOG(WARNING, kr) << "mach_msg: ignoring large message"; |
| 168 run_mach_msg_receive = true; |
| 169 } else if (kr == MACH_RCV_INTERRUPTED) { |
| 170 run_mach_msg_receive = true; |
| 171 } |
| 172 } while (run_mach_msg_receive); |
157 | 173 |
158 if (kr == MACH_MSG_SUCCESS) { | 174 if (kr == MACH_MSG_SUCCESS) { |
159 request_scoper.swap(trial_request_scoper); | 175 request_scoper.swap(trial_request_scoper); |
160 } else if (kr == MACH_RCV_TOO_LARGE && options & MACH_RCV_LARGE) { | 176 } else if (kr == MACH_RCV_TOO_LARGE && |
| 177 receive_large == kReceiveLargeResize) { |
161 this_request_size = | 178 this_request_size = |
162 round_page(request_header->msgh_size + trailer_alloc); | 179 round_page(request_header->msgh_size + trailer_alloc); |
163 this_request_alloc = this_request_size; | 180 this_request_alloc = this_request_size; |
164 } else { | 181 } else { |
165 return kr; | 182 return kr; |
166 } | 183 } |
167 } | 184 } |
168 | 185 |
169 vm_address_t reply_addr; | 186 vm_address_t reply_addr; |
170 kr = vm_allocate(mach_task_self(), | 187 kr = vm_allocate(mach_task_self(), |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 // persistent mode, and just return success when not in persistent mode. | 274 // persistent mode, and just return success when not in persistent mode. |
258 return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr; | 275 return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr; |
259 } | 276 } |
260 } | 277 } |
261 } while (persistent == kPersistent); | 278 } while (persistent == kPersistent); |
262 | 279 |
263 return kr; | 280 return kr; |
264 } | 281 } |
265 | 282 |
266 } // namespace crashpad | 283 } // namespace crashpad |
OLD | NEW |