Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/message_loop/message_pump_fuchsia.h" |
| 6 | |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 7 | #include <lib/async-loop/cpp/loop.h> |
Wez | 6d0d6ec | 2019-08-29 01:59:55 | [diff] [blame] | 8 | #include <lib/async-loop/default.h> |
Wez | 5c3c6f15 | 2018-06-09 18:24:02 | [diff] [blame] | 9 | #include <lib/fdio/io.h> |
Wez | 65ed7a8 | 2018-10-17 21:20:38 | [diff] [blame] | 10 | #include <lib/fdio/unsafe.h> |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 11 | #include <lib/zx/time.h> |
Tamir Duberstein | b8f8c624 | 2021-04-12 18:10:36 | [diff] [blame] | 12 | #include <zircon/errors.h> |
Scott Graham | 6f68b98 | 2017-06-07 23:02:32 | [diff] [blame] | 13 | |
Sergey Ulanov | f134370 | 2017-08-19 01:02:08 | [diff] [blame] | 14 | #include "base/auto_reset.h" |
Adam Rice | d47f498 | 2024-09-03 16:18:23 | [diff] [blame] | 15 | #include "base/check.h" |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 16 | #include "base/fuchsia/fuchsia_logging.h" |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 17 | #include "base/logging.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 18 | #include "base/trace_event/trace_event.h" |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 19 | |
| 20 | namespace base { |
| 21 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 22 | MessagePumpFuchsia::ZxHandleWatchController::ZxHandleWatchController( |
Brett Wilson | 8e88b31 | 2017-09-12 05:22:16 | [diff] [blame] | 23 | const Location& from_here) |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 24 | : async_wait_t({}), created_from_location_(from_here) {} |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 25 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 26 | MessagePumpFuchsia::ZxHandleWatchController::~ZxHandleWatchController() { |
Adam Rice | d47f498 | 2024-09-03 16:18:23 | [diff] [blame] | 27 | const bool success = StopWatchingZxHandle(); |
| 28 | CHECK(success); |
Scott Graham | 6f68b98 | 2017-06-07 23:02:32 | [diff] [blame] | 29 | } |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 30 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 31 | bool MessagePumpFuchsia::ZxHandleWatchController::WaitBegin() { |
| 32 | DCHECK(!handler); |
| 33 | async_wait_t::handler = &HandleSignal; |
| 34 | |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 35 | zx_status_t status = |
| 36 | async_begin_wait(weak_pump_->async_loop_->dispatcher(), this); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 37 | if (status != ZX_OK) { |
Wez | 7415ecf5 | 2019-02-27 23:20:55 | [diff] [blame] | 38 | ZX_DLOG(ERROR, status) << "async_begin_wait():" |
| 39 | << created_from_location_.ToString(); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 40 | async_wait_t::handler = nullptr; |
| 41 | return false; |
| 42 | } |
| 43 | |
| 44 | return true; |
| 45 | } |
| 46 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 47 | bool MessagePumpFuchsia::ZxHandleWatchController::StopWatchingZxHandle() { |
Sergey Ulanov | 2e69d6b2 | 2017-08-12 17:22:57 | [diff] [blame] | 48 | if (was_stopped_) { |
| 49 | DCHECK(!*was_stopped_); |
| 50 | *was_stopped_ = true; |
| 51 | |
| 52 | // |was_stopped_| points at a value stored on the stack, which will go out |
| 53 | // of scope. MessagePumpFuchsia::Run() will reset it only if the value is |
| 54 | // false. So we need to reset this pointer here as well, to make sure it's |
| 55 | // not used again. |
| 56 | was_stopped_ = nullptr; |
| 57 | } |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 58 | |
Sergey Ulanov | 0357c5b | 2017-08-15 22:52:44 | [diff] [blame] | 59 | // If the pump is gone then there is nothing to cancel. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 60 | if (!weak_pump_) { |
Wez | 14e88d1 | 2017-07-12 01:51:00 | [diff] [blame] | 61 | return true; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 62 | } |
Wez | 5289ff3 | 2017-07-18 00:17:12 | [diff] [blame] | 63 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 64 | if (!is_active()) { |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 65 | return true; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 66 | } |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 67 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 68 | async_wait_t::handler = nullptr; |
| 69 | |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 70 | zx_status_t result = |
| 71 | async_cancel_wait(weak_pump_->async_loop_->dispatcher(), this); |
Wez | 7415ecf5 | 2019-02-27 23:20:55 | [diff] [blame] | 72 | ZX_DLOG_IF(ERROR, result != ZX_OK, result) |
| 73 | << "async_cancel_wait(): " << created_from_location_.ToString(); |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 74 | return result == ZX_OK; |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 75 | } |
| 76 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 77 | // static |
| 78 | void MessagePumpFuchsia::ZxHandleWatchController::HandleSignal( |
Wez | 7f5e484 | 2018-07-22 12:09:32 | [diff] [blame] | 79 | async_dispatcher_t* async, |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 80 | async_wait_t* wait, |
| 81 | zx_status_t status, |
| 82 | const zx_packet_signal_t* signal) { |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 83 | ZxHandleWatchController* controller = |
| 84 | static_cast<ZxHandleWatchController*>(wait); |
| 85 | DCHECK_EQ(controller->handler, &HandleSignal); |
Wez | 7415ecf5 | 2019-02-27 23:20:55 | [diff] [blame] | 86 | |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 87 | // Inform ThreadController of this native work item for tracking purposes. |
| 88 | // This call must precede the "ZxHandleSignal" trace event below as |
| 89 | // BeginWorkItem() might generate a top-level trace event for the thread if |
| 90 | // this is the first work item post-wakeup. |
| 91 | Delegate::ScopedDoWorkItem scoped_do_work_item; |
| 92 | if (controller->weak_pump_ && controller->weak_pump_->run_state_) { |
| 93 | scoped_do_work_item = |
| 94 | controller->weak_pump_->run_state_->delegate->BeginWorkItem(); |
| 95 | } |
| 96 | |
| 97 | TRACE_EVENT0("toplevel", "ZxHandleSignal"); |
| 98 | |
Wez | 7415ecf5 | 2019-02-27 23:20:55 | [diff] [blame] | 99 | if (status != ZX_OK) { |
| 100 | ZX_DLOG(WARNING, status) << "async wait failed: " |
| 101 | << controller->created_from_location_.ToString(); |
| 102 | return; |
| 103 | } |
| 104 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 105 | controller->handler = nullptr; |
| 106 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 107 | // In the case of a persistent Watch, the Watch may be stopped and |
| 108 | // potentially deleted by the caller within the callback, in which case |
| 109 | // |controller| should not be accessed again, and we mustn't continue the |
| 110 | // watch. We check for this with a bool on the stack, which the Watch |
| 111 | // receives a pointer to. |
| 112 | bool was_stopped = false; |
| 113 | controller->was_stopped_ = &was_stopped; |
| 114 | |
Tamir Duberstein | 2aa51e5 | 2019-07-11 22:11:00 | [diff] [blame] | 115 | controller->watcher_->OnZxHandleSignalled(wait->object, signal->observed); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 116 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 117 | if (was_stopped) { |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 118 | return; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 119 | } |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 120 | |
| 121 | controller->was_stopped_ = nullptr; |
| 122 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 123 | if (controller->persistent_) { |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 124 | controller->WaitBegin(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 125 | } |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 126 | } |
| 127 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 128 | void MessagePumpFuchsia::FdWatchController::OnZxHandleSignalled( |
| 129 | zx_handle_t handle, |
| 130 | zx_signals_t signals) { |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 131 | uint32_t events; |
Wez | 65ed7a8 | 2018-10-17 21:20:38 | [diff] [blame] | 132 | fdio_unsafe_wait_end(io_, signals, &events); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 133 | |
Tamir Duberstein | 2aa51e5 | 2019-07-11 22:11:00 | [diff] [blame] | 134 | // |events| can include other spurious things, in particular, that an fd |
| 135 | // is writable, when we only asked to know when it was readable. In that |
| 136 | // case, we don't want to call both the CanWrite and CanRead callback, |
| 137 | // when the caller asked for only, for example, readable callbacks. So, |
| 138 | // mask with the events that we actually wanted to know about. |
Tamir Duberstein | 7358b28c | 2021-04-12 23:06:54 | [diff] [blame] | 139 | // |
| 140 | // Note that errors are always included. |
| 141 | const uint32_t desired_events = desired_events_ | FDIO_EVT_ERROR; |
| 142 | const uint32_t filtered_events = events & desired_events; |
| 143 | DCHECK_NE(filtered_events, 0u) << events << " & " << desired_events; |
Tamir Duberstein | 2aa51e5 | 2019-07-11 22:11:00 | [diff] [blame] | 144 | |
Sergey Ulanov | 2e69d6b2 | 2017-08-12 17:22:57 | [diff] [blame] | 145 | // Each |watcher_| callback we invoke may stop or delete |this|. The pump has |
| 146 | // set |was_stopped_| to point to a safe location on the calling stack, so we |
| 147 | // can use that to detect being stopped mid-callback and avoid doing further |
| 148 | // work that would touch |this|. |
| 149 | bool* was_stopped = was_stopped_; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 150 | if (filtered_events & FDIO_EVT_WRITABLE) { |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 151 | watcher_->OnFileCanWriteWithoutBlocking(fd_); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 152 | } |
| 153 | if (!*was_stopped && (filtered_events & FDIO_EVT_READABLE)) { |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 154 | watcher_->OnFileCanReadWithoutBlocking(fd_); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 155 | } |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 156 | |
Sergey Ulanov | 2e69d6b2 | 2017-08-12 17:22:57 | [diff] [blame] | 157 | // Don't add additional work here without checking |*was_stopped_| again. |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | MessagePumpFuchsia::FdWatchController::FdWatchController( |
Brett Wilson | 8e88b31 | 2017-09-12 05:22:16 | [diff] [blame] | 161 | const Location& from_here) |
Gabriel Charette | 60a2b008 | 2018-04-09 23:47:02 | [diff] [blame] | 162 | : FdWatchControllerInterface(from_here), |
| 163 | ZxHandleWatchController(from_here) {} |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 164 | |
| 165 | MessagePumpFuchsia::FdWatchController::~FdWatchController() { |
Adam Rice | d47f498 | 2024-09-03 16:18:23 | [diff] [blame] | 166 | const bool success = StopWatchingFileDescriptor(); |
| 167 | CHECK(success); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 168 | } |
| 169 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 170 | bool MessagePumpFuchsia::FdWatchController::WaitBegin() { |
Sergey Ulanov | 6e54689e | 2020-05-05 04:00:04 | [diff] [blame] | 171 | // Refresh the |handle_| and |desired_signals_| from the fdio for the fd. |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 172 | // Some types of fdio map read/write events to different signals depending on |
| 173 | // their current state, so we must do this every time we begin to wait. |
Wez | 65ed7a8 | 2018-10-17 21:20:38 | [diff] [blame] | 174 | fdio_unsafe_wait_begin(io_, desired_events_, &object, &trigger); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 175 | if (async_wait_t::object == ZX_HANDLE_INVALID) { |
Wez | 7415ecf5 | 2019-02-27 23:20:55 | [diff] [blame] | 176 | DLOG(ERROR) << "fdio_wait_begin failed: " |
| 177 | << ZxHandleWatchController::created_from_location_.ToString(); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 178 | return false; |
| 179 | } |
| 180 | |
| 181 | return MessagePumpFuchsia::ZxHandleWatchController::WaitBegin(); |
| 182 | } |
| 183 | |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 184 | bool MessagePumpFuchsia::FdWatchController::StopWatchingFileDescriptor() { |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 185 | bool success = StopWatchingZxHandle(); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 186 | if (io_) { |
Wez | 65ed7a8 | 2018-10-17 21:20:38 | [diff] [blame] | 187 | fdio_unsafe_release(io_); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 188 | io_ = nullptr; |
| 189 | } |
| 190 | return success; |
| 191 | } |
| 192 | |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 193 | MessagePumpFuchsia::MessagePumpFuchsia() |
Wez | 6d0d6ec | 2019-08-29 01:59:55 | [diff] [blame] | 194 | : async_loop_(new async::Loop(&kAsyncLoopConfigAttachToCurrentThread)), |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 195 | weak_factory_(this) {} |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 196 | MessagePumpFuchsia::~MessagePumpFuchsia() = default; |
Scott Graham | 8038084 | 2017-10-25 04:01:02 | [diff] [blame] | 197 | |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 198 | bool MessagePumpFuchsia::WatchFileDescriptor(int fd, |
| 199 | bool persistent, |
| 200 | int mode, |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 201 | FdWatchController* controller, |
| 202 | FdWatcher* delegate) { |
Scott Graham | 6f68b98 | 2017-06-07 23:02:32 | [diff] [blame] | 203 | DCHECK_GE(fd, 0); |
| 204 | DCHECK(controller); |
| 205 | DCHECK(delegate); |
Wez | 5289ff3 | 2017-07-18 00:17:12 | [diff] [blame] | 206 | |
Adam Rice | d47f498 | 2024-09-03 16:18:23 | [diff] [blame] | 207 | const bool success = controller->StopWatchingFileDescriptor(); |
| 208 | CHECK(success); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 209 | |
Wez | 5289ff3 | 2017-07-18 00:17:12 | [diff] [blame] | 210 | controller->fd_ = fd; |
James Robinson | f53b4e7 | 2017-06-29 20:59:55 | [diff] [blame] | 211 | controller->watcher_ = delegate; |
James Robinson | f53b4e7 | 2017-06-29 20:59:55 | [diff] [blame] | 212 | |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 213 | DCHECK(!controller->io_); |
Wez | 65ed7a8 | 2018-10-17 21:20:38 | [diff] [blame] | 214 | controller->io_ = fdio_unsafe_fd_to_io(fd); |
Wez | 14e88d1 | 2017-07-12 01:51:00 | [diff] [blame] | 215 | if (!controller->io_) { |
| 216 | DLOG(ERROR) << "Failed to get IO for FD"; |
Scott Graham | 0607b79 | 2017-06-14 22:24:46 | [diff] [blame] | 217 | return false; |
Wez | 14e88d1 | 2017-07-12 01:51:00 | [diff] [blame] | 218 | } |
Scott Graham | 0607b79 | 2017-06-14 22:24:46 | [diff] [blame] | 219 | |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 220 | switch (mode) { |
| 221 | case WATCH_READ: |
Wez | 088e9561 | 2018-11-03 06:08:28 | [diff] [blame] | 222 | controller->desired_events_ = FDIO_EVT_READABLE; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 223 | break; |
| 224 | case WATCH_WRITE: |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 225 | controller->desired_events_ = FDIO_EVT_WRITABLE; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 226 | break; |
| 227 | case WATCH_READ_WRITE: |
Wez | 088e9561 | 2018-11-03 06:08:28 | [diff] [blame] | 228 | controller->desired_events_ = FDIO_EVT_READABLE | FDIO_EVT_WRITABLE; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 229 | break; |
| 230 | default: |
Peter Boström | de57333 | 2024-08-26 20:42:45 | [diff] [blame] | 231 | NOTREACHED() << "unexpected mode: " << mode; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 232 | } |
Scott Graham | 6f68b98 | 2017-06-07 23:02:32 | [diff] [blame] | 233 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 234 | // Pass dummy |handle| and |signals| values to WatchZxHandle(). The real |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 235 | // values will be populated by FdWatchController::WaitBegin(), before actually |
| 236 | // starting the wait operation. |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 237 | return WatchZxHandle(ZX_HANDLE_INVALID, persistent, 1, controller, |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 238 | controller); |
James Robinson | f53b4e7 | 2017-06-29 20:59:55 | [diff] [blame] | 239 | } |
| 240 | |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 241 | bool MessagePumpFuchsia::WatchZxHandle(zx_handle_t handle, |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 242 | bool persistent, |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 243 | zx_signals_t signals, |
| 244 | ZxHandleWatchController* controller, |
| 245 | ZxHandleWatcher* delegate) { |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 246 | DCHECK_NE(0u, signals); |
| 247 | DCHECK(controller); |
| 248 | DCHECK(delegate); |
Sergey Ulanov | 6e54689e | 2020-05-05 04:00:04 | [diff] [blame] | 249 | |
| 250 | // If the watch controller is active then WatchZxHandle() can be called only |
| 251 | // for the same handle. |
| 252 | DCHECK(handle == ZX_HANDLE_INVALID || !controller->is_active() || |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 253 | handle == controller->async_wait_t::object); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 254 | |
Adam Rice | d47f498 | 2024-09-03 16:18:23 | [diff] [blame] | 255 | const bool success = controller->StopWatchingZxHandle(); |
| 256 | CHECK(success); |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 257 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 258 | controller->async_wait_t::object = handle; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 259 | controller->persistent_ = persistent; |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 260 | controller->async_wait_t::trigger = signals; |
Wez | 9a7c727 | 2017-08-10 06:29:27 | [diff] [blame] | 261 | controller->watcher_ = delegate; |
| 262 | |
| 263 | controller->weak_pump_ = weak_factory_.GetWeakPtr(); |
| 264 | |
| 265 | return controller->WaitBegin(); |
| 266 | } |
| 267 | |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 268 | bool MessagePumpFuchsia::HandleIoEventsUntil(zx_time_t deadline) { |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 269 | zx_status_t status = async_loop_->Run(zx::time(deadline), /*once=*/true); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 270 | switch (status) { |
| 271 | // Return true if some tasks or events were dispatched or if the dispatcher |
| 272 | // was stopped by ScheduleWork(). |
| 273 | case ZX_OK: |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 274 | return true; |
| 275 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 276 | case ZX_ERR_CANCELED: |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 277 | async_loop_->ResetQuit(); |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 278 | return true; |
Sergey Ulanov | b2fd4ab5 | 2017-09-09 00:32:17 | [diff] [blame] | 279 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 280 | case ZX_ERR_TIMED_OUT: |
| 281 | return false; |
Sergey Ulanov | b2fd4ab5 | 2017-09-09 00:32:17 | [diff] [blame] | 282 | |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 283 | default: |
Peter Boström | 29c76179 | 2024-01-18 23:05:29 | [diff] [blame] | 284 | ZX_DLOG(FATAL, status) << "unexpected wait status"; |
Sergey Ulanov | 66f866c | 2018-04-17 18:18:25 | [diff] [blame] | 285 | return false; |
Sergey Ulanov | b2fd4ab5 | 2017-09-09 00:32:17 | [diff] [blame] | 286 | } |
Sergey Ulanov | b2fd4ab5 | 2017-09-09 00:32:17 | [diff] [blame] | 287 | } |
| 288 | |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 289 | void MessagePumpFuchsia::Run(Delegate* delegate) { |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 290 | RunState run_state(delegate); |
| 291 | AutoReset<RunState*> auto_reset_run_state(&run_state_, &run_state); |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 292 | |
| 293 | for (;;) { |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 294 | const Delegate::NextWorkInfo next_work_info = delegate->DoWork(); |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 295 | if (run_state.should_quit) { |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 296 | break; |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 297 | } |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 298 | |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 299 | const bool did_handle_io_event = HandleIoEventsUntil(/*deadline=*/0); |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 300 | if (run_state.should_quit) { |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 301 | break; |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 302 | } |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 303 | |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 304 | bool attempt_more_work = |
| 305 | next_work_info.is_immediate() || did_handle_io_event; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 306 | if (attempt_more_work) { |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 307 | continue; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 308 | } |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 309 | |
Olivier Li | c01b2134 | 2024-05-27 16:19:35 | [diff] [blame] | 310 | delegate->DoIdleWork(); |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 311 | if (run_state.should_quit) { |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 312 | break; |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 313 | } |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 314 | |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 315 | delegate->BeforeWait(); |
| 316 | |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 317 | zx_time_t deadline = next_work_info.delayed_run_time.is_max() |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 318 | ? ZX_TIME_INFINITE |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 319 | : next_work_info.delayed_run_time.ToZxTime(); |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 320 | |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 321 | HandleIoEventsUntil(deadline); |
Scott Graham | f240237 | 2017-05-29 23:47:07 | [diff] [blame] | 322 | } |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | void MessagePumpFuchsia::Quit() { |
Gabriel Charette | 37b6f6b2 | 2023-07-12 14:54:11 | [diff] [blame] | 326 | CHECK(run_state_); |
| 327 | run_state_->should_quit = true; |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | void MessagePumpFuchsia::ScheduleWork() { |
Sergey Ulanov | b229d18d | 2018-10-26 00:02:34 | [diff] [blame] | 331 | // Stop async_loop to let MessagePumpFuchsia::Run() handle message loop tasks. |
| 332 | async_loop_->Quit(); |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | void MessagePumpFuchsia::ScheduleDelayedWork( |
Etienne Pierre-doray | f2f8e13b | 2022-03-10 12:42:33 | [diff] [blame] | 336 | const Delegate::NextWorkInfo& next_work_info) { |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 337 | // Since this is always called from the same thread as Run(), there is nothing |
| 338 | // to do as the loop is already running. It will wait in Run() with the |
| 339 | // correct timeout when it's out of immediate tasks. |
Alison Gale | d965ba0 | 2024-04-26 21:50:54 | [diff] [blame] | 340 | // TODO(crbug.com/40594269): Consider removing ScheduleDelayedWork() |
Francois Doray | c1c66c6 | 2020-03-18 15:27:49 | [diff] [blame] | 341 | // when all pumps function this way (bit.ly/merge-message-pump-do-work). |
Scott Graham | f5902f84 | 2017-05-26 02:02:10 | [diff] [blame] | 342 | } |
| 343 | |
| 344 | } // namespace base |