| 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 |