Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows improvements #453

Merged
merged 21 commits into from
Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ if(NOT ENABLE_SWIFT)
set(INSTALL_OS_HEADERS_DIR "include/os" CACHE PATH "Path where the headers will be installed")
endif()

option(DISPATCH_ENABLE_ASSERTS "enable debug assertions" FALSE)

option(ENABLE_DTRACE "enable dtrace support" "")

option(ENABLE_TESTING "build libdispatch tests" ON)
Expand Down
10 changes: 4 additions & 6 deletions private/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,13 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit);

#if TARGET_OS_MAC
#define DISPATCH_COCOA_COMPAT 1
#elif defined(__linux__) || defined(__FreeBSD__)
#elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32)
#define DISPATCH_COCOA_COMPAT 1
#else
#define DISPATCH_COCOA_COMPAT 0
#endif

#if DISPATCH_COCOA_COMPAT || defined(_WIN32)
#if DISPATCH_COCOA_COMPAT
ktopley-apple marked this conversation as resolved.
Show resolved Hide resolved

#define DISPATCH_CF_SPI_VERSION 20160712

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

#if TARGET_OS_MAC
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_runloop_handle_t
_dispatch_get_main_queue_port_4CF(void);
#endif

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

#if TARGET_OS_MAC || defined(_WIN32)
API_AVAILABLE(macos(10.9), ios(7.0))
DISPATCH_EXPORT DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_runloop_handle_t
_dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t queue);

#if TARGET_OS_MAC
API_AVAILABLE(macos(10.13.2), ios(11.2), tvos(11.2), watchos(4.2))
DISPATCH_EXPORT DISPATCH_WARN_RESULT DISPATCH_NOTHROW
bool
Expand Down Expand Up @@ -257,7 +255,7 @@ API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT
void (*_Nullable _dispatch_end_NSAutoReleasePool)(void *);

#endif /* DISPATCH_COCOA_COMPAT || defined(_WIN32) */
#endif /* DISPATCH_COCOA_COMPAT */

API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
DISPATCH_EXPORT DISPATCH_NOTHROW
Expand Down
4 changes: 2 additions & 2 deletions src/allocator_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
// Use the largest type your platform is comfortable doing atomic ops with.
// TODO: rdar://11477843
typedef unsigned long bitmap_t;
#if defined(__LP64__)
#if DISPATCH_SIZEOF_PTR == 8
#define BYTES_PER_BITMAP 8
#else
#define BYTES_PER_BITMAP 4
Expand Down Expand Up @@ -147,7 +147,7 @@ typedef unsigned long bitmap_t;

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

#if defined(__LP64__)
#if DISPATCH_SIZEOF_PTR == 8
#define SIZEOF_HEADER 16
#else
#define SIZEOF_HEADER 8
Expand Down
4 changes: 2 additions & 2 deletions src/benchmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ _dispatch_benchmark_init(void *context)
register size_t cnt = bdata->count;
size_t i = 0;
uint64_t start, delta;
#if defined(__LP64__)
#if DISPATCH_SIZEOF_PTR == 8 && !defined(_WIN32)
__uint128_t lcost;
#else
long double lcost;
Expand Down Expand Up @@ -93,7 +93,7 @@ dispatch_benchmark_f(size_t count, register void *ctxt,
};
static dispatch_once_t pred;
uint64_t ns, start, delta;
#if defined(__LP64__)
#if DISPATCH_SIZEOF_PTR == 8 && !defined(_WIN32)
__uint128_t conversion, big_denom;
#else
long double conversion, big_denom;
Expand Down
196 changes: 180 additions & 16 deletions src/event/event_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,59 +21,223 @@
#include "internal.h"
#if DISPATCH_EVENT_BACKEND_WINDOWS

static HANDLE hPort = NULL;
enum _dispatch_windows_port {
DISPATCH_PORT_POKE = 0,
DISPATCH_PORT_TIMER_CLOCK_WALL,
DISPATCH_PORT_TIMER_CLOCK_UPTIME,
DISPATCH_PORT_TIMER_CLOCK_MONOTONIC,
};

#pragma mark dispatch_unote_t

bool
_dispatch_unote_register(dispatch_unote_t du DISPATCH_UNUSED,
dispatch_wlh_t wlh DISPATCH_UNUSED,
dispatch_priority_t pri DISPATCH_UNUSED)
_dispatch_unote_register_muxed(dispatch_unote_t du DISPATCH_UNUSED)
{
WIN_PORT_ERROR();
return false;
}

void
_dispatch_unote_resume(dispatch_unote_t du DISPATCH_UNUSED)
_dispatch_unote_resume_muxed(dispatch_unote_t du DISPATCH_UNUSED)
{
WIN_PORT_ERROR();
}

bool
_dispatch_unote_unregister(dispatch_unote_t du DISPATCH_UNUSED,
uint32_t flags DISPATCH_UNUSED)
_dispatch_unote_unregister_muxed(dispatch_unote_t du DISPATCH_UNUSED)
{
WIN_PORT_ERROR();
return false;
}

#pragma mark timers

typedef struct _dispatch_windows_timeout_s {
PTP_TIMER pTimer;
enum _dispatch_windows_port ullIdent;
bool bArmed;
} *dispatch_windows_timeout_t;

#define DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(clock) \
[DISPATCH_CLOCK_##clock] = { \
.pTimer = NULL, \
.ullIdent = DISPATCH_PORT_TIMER_CLOCK_##clock, \
.bArmed = FALSE, \
}

static struct _dispatch_windows_timeout_s _dispatch_windows_timeout[] = {
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(WALL),
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(UPTIME),
DISPATCH_WINDOWS_TIMEOUT_INITIALIZER(MONOTONIC),
};

static void
_dispatch_event_merge_timer(dispatch_clock_t clock)
{
uint32_t tidx = DISPATCH_TIMER_INDEX(clock, 0);

_dispatch_windows_timeout[clock].bArmed = FALSE;

_dispatch_timers_heap_dirty(_dispatch_timers_heap, tidx);
_dispatch_timers_heap[tidx].dth_needs_program = true;
_dispatch_timers_heap[tidx].dth_armed = false;
}

static void CALLBACK
_dispatch_timer_callback(PTP_CALLBACK_INSTANCE Instance, PVOID Context,
PTP_TIMER Timer)
{
BOOL bSuccess;

bSuccess = PostQueuedCompletionStatus(hPort, 0, (ULONG_PTR)Context,
NULL);
if (bSuccess == FALSE) {
DISPATCH_INTERNAL_CRASH(GetLastError(),
"PostQueuedCompletionStatus");
}
}

void
_dispatch_event_loop_timer_arm(uint32_t tidx DISPATCH_UNUSED,
dispatch_timer_delay_s range DISPATCH_UNUSED,
dispatch_clock_now_cache_t nows DISPATCH_UNUSED)
_dispatch_event_loop_timer_arm(dispatch_timer_heap_t dth DISPATCH_UNUSED,
uint32_t tidx, dispatch_timer_delay_s range,
dispatch_clock_now_cache_t nows)
{
WIN_PORT_ERROR();
dispatch_windows_timeout_t timer;
FILETIME ftDueTime;
LARGE_INTEGER liTime;

switch (DISPATCH_TIMER_CLOCK(tidx)) {
case DISPATCH_CLOCK_WALL:
timer = &_dispatch_windows_timeout[DISPATCH_CLOCK_WALL];
liTime.QuadPart = range.delay +
_dispatch_time_now_cached(DISPATCH_TIMER_CLOCK(tidx), nows);
break;

case DISPATCH_CLOCK_UPTIME:
case DISPATCH_CLOCK_MONOTONIC:
timer = &_dispatch_windows_timeout[DISPATCH_TIMER_CLOCK(tidx)];
liTime.QuadPart = -((range.delay + 99) / 100);
break;
}

if (timer->pTimer == NULL) {
timer->pTimer = CreateThreadpoolTimer(_dispatch_timer_callback,
(LPVOID)timer->ullIdent, NULL);
if (timer->pTimer == NULL) {
DISPATCH_INTERNAL_CRASH(GetLastError(),
"CreateThreadpoolTimer");
}
}

ftDueTime.dwHighDateTime = liTime.HighPart;
ftDueTime.dwLowDateTime = liTime.LowPart;

SetThreadpoolTimer(timer->pTimer, &ftDueTime, /*msPeriod=*/0,
/*msWindowLength=*/0);
timer->bArmed = TRUE;
}

void
_dispatch_event_loop_timer_delete(uint32_t tidx DISPATCH_UNUSED)
_dispatch_event_loop_timer_delete(dispatch_timer_heap_t dth DISPATCH_UNUSED,
uint32_t tidx)
{
WIN_PORT_ERROR();
dispatch_windows_timeout_t timer;

switch (DISPATCH_TIMER_CLOCK(tidx)) {
case DISPATCH_CLOCK_WALL:
timer = &_dispatch_windows_timeout[DISPATCH_CLOCK_WALL];
break;

case DISPATCH_CLOCK_UPTIME:
case DISPATCH_CLOCK_MONOTONIC:
timer = &_dispatch_windows_timeout[DISPATCH_TIMER_CLOCK(tidx)];
break;
}

SetThreadpoolTimer(timer->pTimer, NULL, /*msPeriod=*/0,
/*msWindowLength=*/0);
timer->bArmed = FALSE;
}

#pragma mark dispatch_loop

static void
_dispatch_windows_port_init(void *context DISPATCH_UNUSED)
{
hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (hPort == NULL) {
DISPATCH_INTERNAL_CRASH(GetLastError(),
"CreateIoCompletionPort");
}

#if DISPATCH_USE_MGR_THREAD
_dispatch_trace_item_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q);
dx_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q, 0);
#endif
}

void
_dispatch_event_loop_poke(dispatch_wlh_t wlh DISPATCH_UNUSED,
uint64_t dq_state DISPATCH_UNUSED, uint32_t flags DISPATCH_UNUSED)
{
WIN_PORT_ERROR();
static dispatch_once_t _dispatch_windows_port_init_pred;
BOOL bSuccess;

dispatch_once_f(&_dispatch_windows_port_init_pred, NULL,
_dispatch_windows_port_init);
bSuccess = PostQueuedCompletionStatus(hPort, 0, DISPATCH_PORT_POKE,
NULL);
(void)dispatch_assume(bSuccess);
}

DISPATCH_NOINLINE
void
_dispatch_event_loop_drain(uint32_t flags DISPATCH_UNUSED)
_dispatch_event_loop_drain(uint32_t flags)
{
DWORD dwNumberOfBytesTransferred;
ULONG_PTR ulCompletionKey;
LPOVERLAPPED pOV;
BOOL bSuccess;

pOV = (LPOVERLAPPED)&pOV;
bSuccess = GetQueuedCompletionStatus(hPort, &dwNumberOfBytesTransferred,
&ulCompletionKey, &pOV,
(flags & KEVENT_FLAG_IMMEDIATE) ? 0 : INFINITE);
while (bSuccess) {
switch (ulCompletionKey) {
case DISPATCH_PORT_POKE:
break;

case DISPATCH_PORT_TIMER_CLOCK_WALL:
_dispatch_event_merge_timer(DISPATCH_CLOCK_WALL);
break;

case DISPATCH_PORT_TIMER_CLOCK_UPTIME:
_dispatch_event_merge_timer(DISPATCH_CLOCK_UPTIME);
break;

case DISPATCH_PORT_TIMER_CLOCK_MONOTONIC:
_dispatch_event_merge_timer(DISPATCH_CLOCK_MONOTONIC);
break;

default:
DISPATCH_INTERNAL_CRASH(ulCompletionKey,
"unsupported completion key");
}

bSuccess = GetQueuedCompletionStatus(hPort,
&dwNumberOfBytesTransferred, &ulCompletionKey, &pOV, 0);
}

if (bSuccess == FALSE && pOV != NULL) {
DISPATCH_INTERNAL_CRASH(GetLastError(),
"GetQueuedCompletionStatus");
}
}

void
_dispatch_event_loop_cancel_waiter(dispatch_sync_context_t dsc DISPATCH_UNUSED)
{
WIN_PORT_ERROR();
}
Expand Down Expand Up @@ -109,9 +273,9 @@ _dispatch_event_loop_assert_not_owned(dispatch_wlh_t wlh)
#endif

void
_dispatch_event_loop_leave_immediate(dispatch_wlh_t wlh, uint64_t dq_state)
_dispatch_event_loop_leave_immediate(uint64_t dq_state)
{
(void)wlh; (void)dq_state;
(void)dq_state;
}

#endif // DISPATCH_EVENT_BACKEND_WINDOWS
2 changes: 0 additions & 2 deletions src/event/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ _dispatch_workq_worker_register(dispatch_queue_global_t root_q)
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
#else
(void)root_q;
(void)cls;
#endif // HAVE_DISPATCH_WORKQ_MONITORING
}

Expand All @@ -124,7 +123,6 @@ _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q)
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
#else
(void)root_q;
(void)cls;
#endif // HAVE_DISPATCH_WORKQ_MONITORING
}

Expand Down
2 changes: 1 addition & 1 deletion src/inline_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ _dispatch_queue_drain_try_lock_wlh(dispatch_queue_t dq, uint64_t *dq_state)
if (unlikely(!_dq_state_is_base_wlh(old_state) ||
!_dq_state_is_enqueued_on_target(old_state) ||
_dq_state_is_enqueued_on_manager(old_state))) {
#if !__LP64__
#if DISPATCH_SIZEOF_PTR == 4
old_state >>= 32;
#endif
DISPATCH_INTERNAL_CRASH(old_state, "Invalid wlh state");
Expand Down
3 changes: 0 additions & 3 deletions src/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,6 @@ upcast(dispatch_object_t dou)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#if defined(_WIN32)
#define _CRT_RAND_S
#endif
#include <stdlib.h>
#include <string.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
Expand Down
Loading