Skip to content

Commit 4659503

Browse files
Merge pull request #453 from compnerd/windows-improvements
Windows improvements
2 parents d44acc0 + 3085ae0 commit 4659503

28 files changed

+393
-100
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ if(NOT ENABLE_SWIFT)
7777
set(INSTALL_OS_HEADERS_DIR "include/os" CACHE PATH "Path where the headers will be installed")
7878
endif()
7979

80+
option(DISPATCH_ENABLE_ASSERTS "enable debug assertions" FALSE)
81+
8082
option(ENABLE_DTRACE "enable dtrace support" "")
8183

8284
option(ENABLE_TESTING "build libdispatch tests" ON)

private/private.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,13 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit);
177177

178178
#if TARGET_OS_MAC
179179
#define DISPATCH_COCOA_COMPAT 1
180-
#elif defined(__linux__) || defined(__FreeBSD__)
180+
#elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32)
181181
#define DISPATCH_COCOA_COMPAT 1
182182
#else
183183
#define DISPATCH_COCOA_COMPAT 0
184184
#endif
185185

186-
#if DISPATCH_COCOA_COMPAT || defined(_WIN32)
186+
#if DISPATCH_COCOA_COMPAT
187187

188188
#define DISPATCH_CF_SPI_VERSION 20160712
189189

@@ -197,12 +197,10 @@ typedef void *dispatch_runloop_handle_t;
197197
#error "runloop support not implemented on this platform"
198198
#endif
199199

200-
#if TARGET_OS_MAC
201200
API_AVAILABLE(macos(10.6), ios(4.0))
202201
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
203202
dispatch_runloop_handle_t
204203
_dispatch_get_main_queue_port_4CF(void);
205-
#endif
206204

207205
API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
208206
DISPATCH_EXPORT DISPATCH_NOTHROW
@@ -221,12 +219,12 @@ dispatch_queue_serial_t
221219
_dispatch_runloop_root_queue_create_4CF(const char *_Nullable label,
222220
unsigned long flags);
223221

224-
#if TARGET_OS_MAC || defined(_WIN32)
225222
API_AVAILABLE(macos(10.9), ios(7.0))
226223
DISPATCH_EXPORT DISPATCH_WARN_RESULT DISPATCH_NOTHROW
227224
dispatch_runloop_handle_t
228225
_dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t queue);
229226

227+
#if TARGET_OS_MAC
230228
API_AVAILABLE(macos(10.13.2), ios(11.2), tvos(11.2), watchos(4.2))
231229
DISPATCH_EXPORT DISPATCH_WARN_RESULT DISPATCH_NOTHROW
232230
bool
@@ -257,7 +255,7 @@ API_AVAILABLE(macos(10.6), ios(4.0))
257255
DISPATCH_EXPORT
258256
void (*_Nullable _dispatch_end_NSAutoReleasePool)(void *);
259257

260-
#endif /* DISPATCH_COCOA_COMPAT || defined(_WIN32) */
258+
#endif /* DISPATCH_COCOA_COMPAT */
261259

262260
API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
263261
DISPATCH_EXPORT DISPATCH_NOTHROW

src/allocator_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
// Use the largest type your platform is comfortable doing atomic ops with.
9898
// TODO: rdar://11477843
9999
typedef unsigned long bitmap_t;
100-
#if defined(__LP64__)
100+
#if DISPATCH_SIZEOF_PTR == 8
101101
#define BYTES_PER_BITMAP 8
102102
#else
103103
#define BYTES_PER_BITMAP 4
@@ -147,7 +147,7 @@ typedef unsigned long bitmap_t;
147147

148148
#define PADDING_TO_CONTINUATION_SIZE(x) (ROUND_UP_TO_CONTINUATION_SIZE(x) - (x))
149149

150-
#if defined(__LP64__)
150+
#if DISPATCH_SIZEOF_PTR == 8
151151
#define SIZEOF_HEADER 16
152152
#else
153153
#define SIZEOF_HEADER 8

src/benchmark.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ _dispatch_benchmark_init(void *context)
4141
register size_t cnt = bdata->count;
4242
size_t i = 0;
4343
uint64_t start, delta;
44-
#if defined(__LP64__)
44+
#if DISPATCH_SIZEOF_PTR == 8 && !defined(_WIN32)
4545
__uint128_t lcost;
4646
#else
4747
long double lcost;
@@ -93,7 +93,7 @@ dispatch_benchmark_f(size_t count, register void *ctxt,
9393
};
9494
static dispatch_once_t pred;
9595
uint64_t ns, start, delta;
96-
#if defined(__LP64__)
96+
#if DISPATCH_SIZEOF_PTR == 8 && !defined(_WIN32)
9797
__uint128_t conversion, big_denom;
9898
#else
9999
long double conversion, big_denom;

src/event/event_windows.c

Lines changed: 180 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,59 +21,223 @@
2121
#include "internal.h"
2222
#if DISPATCH_EVENT_BACKEND_WINDOWS
2323

24+
static HANDLE hPort = NULL;
25+
enum _dispatch_windows_port {
26+
DISPATCH_PORT_POKE = 0,
27+
DISPATCH_PORT_TIMER_CLOCK_WALL,
28+
DISPATCH_PORT_TIMER_CLOCK_UPTIME,
29+
DISPATCH_PORT_TIMER_CLOCK_MONOTONIC,
30+
};
31+
2432
#pragma mark dispatch_unote_t
2533

2634
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)
35+
_dispatch_unote_register_muxed(dispatch_unote_t du DISPATCH_UNUSED)
3036
{
3137
WIN_PORT_ERROR();
3238
return false;
3339
}
3440

3541
void
36-
_dispatch_unote_resume(dispatch_unote_t du DISPATCH_UNUSED)
42+
_dispatch_unote_resume_muxed(dispatch_unote_t du DISPATCH_UNUSED)
3743
{
3844
WIN_PORT_ERROR();
3945
}
4046

4147
bool
42-
_dispatch_unote_unregister(dispatch_unote_t du DISPATCH_UNUSED,
43-
uint32_t flags DISPATCH_UNUSED)
48+
_dispatch_unote_unregister_muxed(dispatch_unote_t du DISPATCH_UNUSED)
4449
{
4550
WIN_PORT_ERROR();
4651
return false;
4752
}
4853

4954
#pragma mark timers
5055

56+
typedef struct _dispatch_windows_timeout_s {
57+
PTP_TIMER pTimer;
58+
enum _dispatch_windows_port ullIdent;
59+
bool bArmed;
60+
} *dispatch_windows_timeout_t;
61+
62+
#define DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(clock) \
63+
[DISPATCH_CLOCK_##clock] = { \
64+
.pTimer = NULL, \
65+
.ullIdent = DISPATCH_PORT_TIMER_CLOCK_##clock, \
66+
.bArmed = FALSE, \
67+
}
68+
69+
static struct _dispatch_windows_timeout_s _dispatch_windows_timeout[] = {
70+
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(WALL),
71+
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(UPTIME),
72+
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(MONOTONIC),
73+
};
74+
75+
static void
76+
_dispatch_event_merge_timer(dispatch_clock_t clock)
77+
{
78+
uint32_t tidx = DISPATCH_TIMER_INDEX(clock, 0);
79+
80+
_dispatch_windows_timeout[clock].bArmed = FALSE;
81+
82+
_dispatch_timers_heap_dirty(_dispatch_timers_heap, tidx);
83+
_dispatch_timers_heap[tidx].dth_needs_program = true;
84+
_dispatch_timers_heap[tidx].dth_armed = false;
85+
}
86+
87+
static void CALLBACK
88+
_dispatch_timer_callback(PTP_CALLBACK_INSTANCE Instance, PVOID Context,
89+
PTP_TIMER Timer)
90+
{
91+
BOOL bSuccess;
92+
93+
bSuccess = PostQueuedCompletionStatus(hPort, 0, (ULONG_PTR)Context,
94+
NULL);
95+
if (bSuccess == FALSE) {
96+
DISPATCH_INTERNAL_CRASH(GetLastError(),
97+
"PostQueuedCompletionStatus");
98+
}
99+
}
100+
51101
void
52-
_dispatch_event_loop_timer_arm(uint32_t tidx DISPATCH_UNUSED,
53-
dispatch_timer_delay_s range DISPATCH_UNUSED,
54-
dispatch_clock_now_cache_t nows DISPATCH_UNUSED)
102+
_dispatch_event_loop_timer_arm(dispatch_timer_heap_t dth DISPATCH_UNUSED,
103+
uint32_t tidx, dispatch_timer_delay_s range,
104+
dispatch_clock_now_cache_t nows)
55105
{
56-
WIN_PORT_ERROR();
106+
dispatch_windows_timeout_t timer;
107+
FILETIME ftDueTime;
108+
LARGE_INTEGER liTime;
109+
110+
switch (DISPATCH_TIMER_CLOCK(tidx)) {
111+
case DISPATCH_CLOCK_WALL:
112+
timer = &_dispatch_windows_timeout[DISPATCH_CLOCK_WALL];
113+
liTime.QuadPart = range.delay +
114+
_dispatch_time_now_cached(DISPATCH_TIMER_CLOCK(tidx), nows);
115+
break;
116+
117+
case DISPATCH_CLOCK_UPTIME:
118+
case DISPATCH_CLOCK_MONOTONIC:
119+
timer = &_dispatch_windows_timeout[DISPATCH_TIMER_CLOCK(tidx)];
120+
liTime.QuadPart = -((range.delay + 99) / 100);
121+
break;
122+
}
123+
124+
if (timer->pTimer == NULL) {
125+
timer->pTimer = CreateThreadpoolTimer(_dispatch_timer_callback,
126+
(LPVOID)timer->ullIdent, NULL);
127+
if (timer->pTimer == NULL) {
128+
DISPATCH_INTERNAL_CRASH(GetLastError(),
129+
"CreateThreadpoolTimer");
130+
}
131+
}
132+
133+
ftDueTime.dwHighDateTime = liTime.HighPart;
134+
ftDueTime.dwLowDateTime = liTime.LowPart;
135+
136+
SetThreadpoolTimer(timer->pTimer, &ftDueTime, /*msPeriod=*/0,
137+
/*msWindowLength=*/0);
138+
timer->bArmed = TRUE;
57139
}
58140

59141
void
60-
_dispatch_event_loop_timer_delete(uint32_t tidx DISPATCH_UNUSED)
142+
_dispatch_event_loop_timer_delete(dispatch_timer_heap_t dth DISPATCH_UNUSED,
143+
uint32_t tidx)
61144
{
62-
WIN_PORT_ERROR();
145+
dispatch_windows_timeout_t timer;
146+
147+
switch (DISPATCH_TIMER_CLOCK(tidx)) {
148+
case DISPATCH_CLOCK_WALL:
149+
timer = &_dispatch_windows_timeout[DISPATCH_CLOCK_WALL];
150+
break;
151+
152+
case DISPATCH_CLOCK_UPTIME:
153+
case DISPATCH_CLOCK_MONOTONIC:
154+
timer = &_dispatch_windows_timeout[DISPATCH_TIMER_CLOCK(tidx)];
155+
break;
156+
}
157+
158+
SetThreadpoolTimer(timer->pTimer, NULL, /*msPeriod=*/0,
159+
/*msWindowLength=*/0);
160+
timer->bArmed = FALSE;
63161
}
64162

65163
#pragma mark dispatch_loop
66164

165+
static void
166+
_dispatch_windows_port_init(void *context DISPATCH_UNUSED)
167+
{
168+
hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
169+
if (hPort == NULL) {
170+
DISPATCH_INTERNAL_CRASH(GetLastError(),
171+
"CreateIoCompletionPort");
172+
}
173+
174+
#if DISPATCH_USE_MGR_THREAD
175+
_dispatch_trace_item_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q);
176+
dx_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q, 0);
177+
#endif
178+
}
179+
67180
void
68181
_dispatch_event_loop_poke(dispatch_wlh_t wlh DISPATCH_UNUSED,
69182
uint64_t dq_state DISPATCH_UNUSED, uint32_t flags DISPATCH_UNUSED)
70183
{
71-
WIN_PORT_ERROR();
184+
static dispatch_once_t _dispatch_windows_port_init_pred;
185+
BOOL bSuccess;
186+
187+
dispatch_once_f(&_dispatch_windows_port_init_pred, NULL,
188+
_dispatch_windows_port_init);
189+
bSuccess = PostQueuedCompletionStatus(hPort, 0, DISPATCH_PORT_POKE,
190+
NULL);
191+
(void)dispatch_assume(bSuccess);
72192
}
73193

74194
DISPATCH_NOINLINE
75195
void
76-
_dispatch_event_loop_drain(uint32_t flags DISPATCH_UNUSED)
196+
_dispatch_event_loop_drain(uint32_t flags)
197+
{
198+
DWORD dwNumberOfBytesTransferred;
199+
ULONG_PTR ulCompletionKey;
200+
LPOVERLAPPED pOV;
201+
BOOL bSuccess;
202+
203+
pOV = (LPOVERLAPPED)&pOV;
204+
bSuccess = GetQueuedCompletionStatus(hPort, &dwNumberOfBytesTransferred,
205+
&ulCompletionKey, &pOV,
206+
(flags & KEVENT_FLAG_IMMEDIATE) ? 0 : INFINITE);
207+
while (bSuccess) {
208+
switch (ulCompletionKey) {
209+
case DISPATCH_PORT_POKE:
210+
break;
211+
212+
case DISPATCH_PORT_TIMER_CLOCK_WALL:
213+
_dispatch_event_merge_timer(DISPATCH_CLOCK_WALL);
214+
break;
215+
216+
case DISPATCH_PORT_TIMER_CLOCK_UPTIME:
217+
_dispatch_event_merge_timer(DISPATCH_CLOCK_UPTIME);
218+
break;
219+
220+
case DISPATCH_PORT_TIMER_CLOCK_MONOTONIC:
221+
_dispatch_event_merge_timer(DISPATCH_CLOCK_MONOTONIC);
222+
break;
223+
224+
default:
225+
DISPATCH_INTERNAL_CRASH(ulCompletionKey,
226+
"unsupported completion key");
227+
}
228+
229+
bSuccess = GetQueuedCompletionStatus(hPort,
230+
&dwNumberOfBytesTransferred, &ulCompletionKey, &pOV, 0);
231+
}
232+
233+
if (bSuccess == FALSE && pOV != NULL) {
234+
DISPATCH_INTERNAL_CRASH(GetLastError(),
235+
"GetQueuedCompletionStatus");
236+
}
237+
}
238+
239+
void
240+
_dispatch_event_loop_cancel_waiter(dispatch_sync_context_t dsc DISPATCH_UNUSED)
77241
{
78242
WIN_PORT_ERROR();
79243
}
@@ -109,9 +273,9 @@ _dispatch_event_loop_assert_not_owned(dispatch_wlh_t wlh)
109273
#endif
110274

111275
void
112-
_dispatch_event_loop_leave_immediate(dispatch_wlh_t wlh, uint64_t dq_state)
276+
_dispatch_event_loop_leave_immediate(uint64_t dq_state)
113277
{
114-
(void)wlh; (void)dq_state;
278+
(void)dq_state;
115279
}
116280

117281
#endif // DISPATCH_EVENT_BACKEND_WINDOWS

src/event/workqueue.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ _dispatch_workq_worker_register(dispatch_queue_global_t root_q)
9797
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
9898
#else
9999
(void)root_q;
100-
(void)cls;
101100
#endif // HAVE_DISPATCH_WORKQ_MONITORING
102101
}
103102

@@ -124,7 +123,6 @@ _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q)
124123
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
125124
#else
126125
(void)root_q;
127-
(void)cls;
128126
#endif // HAVE_DISPATCH_WORKQ_MONITORING
129127
}
130128

src/inline_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ _dispatch_queue_drain_try_lock_wlh(dispatch_queue_t dq, uint64_t *dq_state)
12941294
if (unlikely(!_dq_state_is_base_wlh(old_state) ||
12951295
!_dq_state_is_enqueued_on_target(old_state) ||
12961296
_dq_state_is_enqueued_on_manager(old_state))) {
1297-
#if !__LP64__
1297+
#if DISPATCH_SIZEOF_PTR == 4
12981298
old_state >>= 32;
12991299
#endif
13001300
DISPATCH_INTERNAL_CRASH(old_state, "Invalid wlh state");

src/internal.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,6 @@ upcast(dispatch_object_t dou)
306306
#include <stdbool.h>
307307
#include <stdint.h>
308308
#include <stdio.h>
309-
#if defined(_WIN32)
310-
#define _CRT_RAND_S
311-
#endif
312309
#include <stdlib.h>
313310
#include <string.h>
314311
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))

0 commit comments

Comments
 (0)