|
21 | 21 | #include "internal.h"
|
22 | 22 | #if DISPATCH_EVENT_BACKEND_WINDOWS
|
23 | 23 |
|
| 24 | +static HANDLE hPort = NULL; |
| 25 | +enum _dispatch_iocp_completion_key |
| 26 | +{ |
| 27 | + DISPATCH_PORT_POKE = 0, |
| 28 | + DISPATCH_PORT_TIMER_CLOCK_UPTIME, |
| 29 | +}; |
| 30 | + |
| 31 | +typedef struct _dispatch_windows_timeout_s { |
| 32 | + PTP_TIMER pTimer; |
| 33 | + enum _dispatch_iocp_completion_key ullIdent; |
| 34 | + BOOL bArmed; |
| 35 | +} *dispatch_windows_timeout_t; |
| 36 | + |
| 37 | +#define DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(clock) \ |
| 38 | + [DISPATCH_CLOCK_##clock] = { \ |
| 39 | + .pTimer = NULL, \ |
| 40 | + .ullIdent = DISPATCH_PORT_TIMER_CLOCK_##clock, \ |
| 41 | + .bArmed = FALSE, \ |
| 42 | + } |
| 43 | +static struct _dispatch_windows_timeout_s _dispatch_windows_timeout[] = { |
| 44 | +// DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(WALL), |
| 45 | + DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(UPTIME), |
| 46 | +// DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(MONOTONIC), |
| 47 | +}; |
| 48 | + |
| 49 | +#pragma mark Helpers |
| 50 | + |
24 | 51 | #pragma mark dispatch_unote_t
|
25 | 52 |
|
26 | 53 | bool
|
27 |
| -_dispatch_unote_register(dispatch_unote_t du DISPATCH_UNUSED, |
28 |
| - dispatch_wlh_t wlh DISPATCH_UNUSED, |
29 |
| - dispatch_priority_t pri DISPATCH_UNUSED) |
| 54 | +_dispatch_unote_register_muxed(dispatch_unote_t du DISPATCH_UNUSED) |
30 | 55 | {
|
31 | 56 | WIN_PORT_ERROR();
|
32 | 57 | return false;
|
33 | 58 | }
|
34 | 59 |
|
35 | 60 | void
|
36 |
| -_dispatch_unote_resume(dispatch_unote_t du DISPATCH_UNUSED) |
| 61 | +_dispatch_unote_resume_muxed(dispatch_unote_t du DISPATCH_UNUSED) |
37 | 62 | {
|
38 | 63 | WIN_PORT_ERROR();
|
39 | 64 | }
|
40 | 65 |
|
41 | 66 | bool
|
42 |
| -_dispatch_unote_unregister(dispatch_unote_t du DISPATCH_UNUSED, |
43 |
| - uint32_t flags DISPATCH_UNUSED) |
| 67 | +_dispatch_unote_unregister_muxed(dispatch_unote_t du DISPATCH_UNUSED) |
44 | 68 | {
|
45 | 69 | WIN_PORT_ERROR();
|
46 | 70 | return false;
|
47 | 71 | }
|
48 | 72 |
|
49 | 73 | #pragma mark timers
|
50 | 74 |
|
| 75 | +static void CALLBACK |
| 76 | +_dispatch_timer_callback(PTP_CALLBACK_INSTANCE Instance, PVOID Context, |
| 77 | + PTP_TIMER Timer) |
| 78 | +{ |
| 79 | + BOOL bSuccess; |
| 80 | + |
| 81 | + bSuccess = PostQueuedCompletionStatus(hPort, 0, (ULONG_PTR)Context, NULL); |
| 82 | + if (bSuccess == FALSE) |
| 83 | + DISPATCH_INTERNAL_CRASH(GetLastError(), "PostQueuedCompletionStatus"); |
| 84 | +} |
| 85 | + |
51 | 86 | void
|
52 |
| -_dispatch_event_loop_timer_arm(uint32_t tidx DISPATCH_UNUSED, |
53 |
| - dispatch_timer_delay_s range DISPATCH_UNUSED, |
| 87 | +_dispatch_event_loop_timer_arm(dispatch_timer_heap_t dth DISPATCH_UNUSED, |
| 88 | + uint32_t tidx, dispatch_timer_delay_s range, |
54 | 89 | dispatch_clock_now_cache_t nows DISPATCH_UNUSED)
|
55 | 90 | {
|
56 |
| - WIN_PORT_ERROR(); |
| 91 | + dispatch_windows_timeout_t timer; |
| 92 | + FILETIME ftDueTime; |
| 93 | + LARGE_INTEGER ulTime; |
| 94 | + |
| 95 | + switch (DISPATCH_TIMER_CLOCK(tidx)) { |
| 96 | + case DISPATCH_CLOCK_UPTIME: |
| 97 | + timer = &_dispatch_windows_timeout[DISPATCH_CLOCK_UPTIME]; |
| 98 | + ulTime.QuadPart = -((range.delay + 99) / 100); |
| 99 | + break; |
| 100 | + default: |
| 101 | + WIN_PORT_ERROR(); |
| 102 | + __assume(0); |
| 103 | + } |
| 104 | + |
| 105 | + if (timer->pTimer == NULL) |
| 106 | + { |
| 107 | + timer->pTimer = CreateThreadpoolTimer(_dispatch_timer_callback, |
| 108 | + (LPVOID)timer->ullIdent, NULL); |
| 109 | + if (timer->pTimer == NULL) |
| 110 | + DISPATCH_INTERNAL_CRASH(GetLastError(), "CreateThreadpoolTimer"); |
| 111 | + } |
| 112 | + |
| 113 | + ftDueTime.dwHighDateTime = ulTime.HighPart; |
| 114 | + ftDueTime.dwLowDateTime = ulTime.LowPart; |
| 115 | + |
| 116 | + SetThreadpoolTimer(timer->pTimer, &ftDueTime, /*msPeriod=*/0, |
| 117 | + /*msWindowLength=*/0); |
| 118 | + timer->bArmed = TRUE; |
57 | 119 | }
|
58 | 120 |
|
59 | 121 | void
|
60 |
| -_dispatch_event_loop_timer_delete(uint32_t tidx DISPATCH_UNUSED) |
| 122 | +_dispatch_event_loop_timer_delete(dispatch_timer_heap_t dth DISPATCH_UNUSED, |
| 123 | + uint32_t tidx) |
61 | 124 | {
|
62 |
| - WIN_PORT_ERROR(); |
| 125 | + dispatch_windows_timeout_t timer; |
| 126 | + |
| 127 | + switch (DISPATCH_TIMER_CLOCK(tidx)) { |
| 128 | + case DISPATCH_CLOCK_UPTIME: |
| 129 | + timer = &_dispatch_windows_timeout[DISPATCH_PORT_TIMER_CLOCK_UPTIME]; |
| 130 | + break; |
| 131 | + default: |
| 132 | + WIN_PORT_ERROR(); |
| 133 | + __assume(0); |
| 134 | + } |
| 135 | + |
| 136 | + SetThreadpoolTimer(timer->pTimer, NULL, /*msPeriod=*/0, |
| 137 | + /*msWindowLength=*/0); |
| 138 | + timer->bArmed = FALSE; |
63 | 139 | }
|
64 | 140 |
|
65 | 141 | #pragma mark dispatch_loop
|
66 | 142 |
|
| 143 | +static void |
| 144 | +_dispatch_port_init(void *context DISPATCH_UNUSED) |
| 145 | +{ |
| 146 | + hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); |
| 147 | + if (hPort == NULL) { |
| 148 | + DISPATCH_INTERNAL_CRASH(GetLastError(), "CreateIoCompletionPort"); |
| 149 | + } |
| 150 | + |
| 151 | +#if DISPATCH_USE_MGR_THREAD |
| 152 | + _dispatch_trace_item_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q); |
| 153 | + dx_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q, 0); |
| 154 | +#endif |
| 155 | +} |
| 156 | + |
67 | 157 | void
|
68 | 158 | _dispatch_event_loop_poke(dispatch_wlh_t wlh DISPATCH_UNUSED,
|
69 | 159 | uint64_t dq_state DISPATCH_UNUSED, uint32_t flags DISPATCH_UNUSED)
|
70 | 160 | {
|
71 |
| - WIN_PORT_ERROR(); |
| 161 | + static dispatch_once_t _dispatch_port_pred; |
| 162 | + dispatch_once_f(&_dispatch_port_pred, NULL, _dispatch_port_init); |
| 163 | + BOOL bResult = PostQueuedCompletionStatus(hPort, 0, DISPATCH_PORT_POKE, |
| 164 | + NULL); |
| 165 | + (void)dispatch_assume(bResult); |
| 166 | +} |
| 167 | + |
| 168 | +static void |
| 169 | +_dispatch_event_merge_timer(dispatch_clock_t clock) |
| 170 | +{ |
| 171 | + dispatch_timer_heap_t dth = _dispatch_timers_heap; |
| 172 | + uint32_t tidx = DISPATCH_TIMER_INDEX(clock, 0); |
| 173 | + |
| 174 | + _dispatch_windows_timeout[clock].bArmed = FALSE; |
| 175 | + |
| 176 | + _dispatch_timers_heap_dirty(dth, tidx); |
| 177 | + dth[tidx].dth_needs_program = true; |
| 178 | + dth[tidx].dth_armed = false; |
72 | 179 | }
|
73 | 180 |
|
74 | 181 | DISPATCH_NOINLINE
|
75 | 182 | void
|
76 |
| -_dispatch_event_loop_drain(uint32_t flags DISPATCH_UNUSED) |
| 183 | +_dispatch_event_loop_drain(uint32_t flags) |
| 184 | +{ |
| 185 | + DWORD dwNumberOfBytesTransferred; |
| 186 | + ULONG_PTR ulCompletionKey; |
| 187 | + LPOVERLAPPED pOV; |
| 188 | + |
| 189 | + pOV = (LPOVERLAPPED)&pOV; |
| 190 | + BOOL bResult = GetQueuedCompletionStatus(hPort, |
| 191 | + &dwNumberOfBytesTransferred, &ulCompletionKey, &pOV, |
| 192 | + (flags & KEVENT_FLAG_IMMEDIATE) ? 0 : INFINITE); |
| 193 | + |
| 194 | + while (bResult) |
| 195 | + { |
| 196 | + switch (ulCompletionKey) |
| 197 | + { |
| 198 | + case DISPATCH_PORT_POKE: |
| 199 | + break; |
| 200 | + case DISPATCH_PORT_TIMER_CLOCK_UPTIME: |
| 201 | + _dispatch_event_merge_timer(DISPATCH_CLOCK_UPTIME); |
| 202 | + break; |
| 203 | + } |
| 204 | + |
| 205 | + bResult = GetQueuedCompletionStatus(hPort, |
| 206 | + &dwNumberOfBytesTransferred, &ulCompletionKey, &pOV, 0); |
| 207 | + } |
| 208 | + |
| 209 | + if (bResult == FALSE && pOV != NULL) |
| 210 | + DISPATCH_INTERNAL_CRASH(GetLastError(), "GetQueuedCompletionStatus"); |
| 211 | +} |
| 212 | + |
| 213 | +void |
| 214 | +_dispatch_event_loop_cancel_waiter(dispatch_sync_context_t dsc DISPATCH_UNUSED) |
77 | 215 | {
|
78 | 216 | WIN_PORT_ERROR();
|
79 | 217 | }
|
@@ -109,9 +247,9 @@ _dispatch_event_loop_assert_not_owned(dispatch_wlh_t wlh)
|
109 | 247 | #endif
|
110 | 248 |
|
111 | 249 | void
|
112 |
| -_dispatch_event_loop_leave_immediate(dispatch_wlh_t wlh, uint64_t dq_state) |
| 250 | +_dispatch_event_loop_leave_immediate(uint64_t dq_state) |
113 | 251 | {
|
114 |
| - (void)wlh; (void)dq_state; |
| 252 | + (void)dq_state; |
115 | 253 | }
|
116 | 254 |
|
117 | 255 | #endif // DISPATCH_EVENT_BACKEND_WINDOWS
|
0 commit comments