Merge pull request #377 from adierking/fls

Ignore Windows FLS destructors during process exit
diff --git a/dispatch/base.h b/dispatch/base.h
index bd01f48..62579ec 100644
--- a/dispatch/base.h
+++ b/dispatch/base.h
@@ -65,6 +65,29 @@
 #define DISPATCH_ALWAYS_INLINE __attribute__((__always_inline__))
 #define DISPATCH_UNAVAILABLE __attribute__((__unavailable__))
 #define DISPATCH_UNAVAILABLE_MSG(msg) __attribute__((__unavailable__(msg)))
+#elif defined(_MSC_VER)
+#define DISPATCH_NORETURN __declspec(noreturn)
+#define DISPATCH_NOTHROW __declspec(nothrow)
+#define DISPATCH_NONNULL1
+#define DISPATCH_NONNULL2
+#define DISPATCH_NONNULL3
+#define DISPATCH_NONNULL4
+#define DISPATCH_NONNULL5
+#define DISPATCH_NONNULL6
+#define DISPATCH_NONNULL7
+#define DISPATCH_NONNULL_ALL
+#define DISPATCH_SENTINEL
+#define DISPATCH_PURE
+#define DISPATCH_CONST
+#if (_MSC_VER >= 1700)
+#define DISPATCH_WARN_RESULT _Check_return_
+#else
+#define DISPATCH_WARN_RESULT
+#endif
+#define DISPATCH_MALLOC
+#define DISPATCH_ALWAYS_INLINE __forceinline
+#define DISPATCH_UNAVAILABLE
+#define DISPATCH_UNAVAILABLE_MSG(msg)
 #else
 /*! @parseOnly */
 #define DISPATCH_NORETURN
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b817674..6b95a9b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -41,6 +41,7 @@
               event/event_epoll.c
               event/event_internal.h
               event/event_kevent.c
+              event/event_windows.c
               firehose/firehose_internal.h
               shims/android_stubs.h
               shims/atomic.h
diff --git a/src/event/event_config.h b/src/event/event_config.h
index fda5d22..c0c38b0 100644
--- a/src/event/event_config.h
+++ b/src/event/event_config.h
@@ -25,13 +25,16 @@
 #	include <sys/eventfd.h>
 #	define DISPATCH_EVENT_BACKEND_EPOLL 1
 #	define DISPATCH_EVENT_BACKEND_KEVENT 0
+#	define DISPATCH_EVENT_BACKEND_WINDOWS 0
 #elif __has_include(<sys/event.h>)
 #	include <sys/event.h>
 #	define DISPATCH_EVENT_BACKEND_EPOLL 0
 #	define DISPATCH_EVENT_BACKEND_KEVENT 1
+#	define DISPATCH_EVENT_BACKEND_WINDOWS 0
 #elif defined(_WIN32)
 #	define DISPATCH_EVENT_BACKEND_EPOLL 0
 #	define DISPATCH_EVENT_BACKEND_KEVENT 0
+#	define DISPATCH_EVENT_BACKEND_WINDOWS 1
 #else
 #	error unsupported event loop
 #endif
diff --git a/src/event/event_internal.h b/src/event/event_internal.h
index 842c4ee..cf80a41 100644
--- a/src/event/event_internal.h
+++ b/src/event/event_internal.h
@@ -418,7 +418,9 @@
 bool _dispatch_unote_unregister(dispatch_unote_t du, uint32_t flags);
 void _dispatch_unote_dispose(dispatch_unote_t du);
 
+#if !DISPATCH_EVENT_BACKEND_WINDOWS
 void _dispatch_event_loop_atfork_child(void);
+#endif
 #define DISPATCH_EVENT_LOOP_CONSUME_2 DISPATCH_WAKEUP_CONSUME_2
 #define DISPATCH_EVENT_LOOP_OVERRIDE  0x80000000
 void _dispatch_event_loop_poke(dispatch_wlh_t wlh, uint64_t dq_state,
diff --git a/src/event/event_windows.c b/src/event/event_windows.c
new file mode 100644
index 0000000..2fe9680
--- /dev/null
+++ b/src/event/event_windows.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+#include "internal.h"
+#if DISPATCH_EVENT_BACKEND_WINDOWS
+
+#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)
+{
+	WIN_PORT_ERROR();
+	return false;
+}
+
+void
+_dispatch_unote_resume(dispatch_unote_t du DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+}
+
+bool
+_dispatch_unote_unregister(dispatch_unote_t du DISPATCH_UNUSED,
+		uint32_t flags DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+	return false;
+}
+
+#pragma mark timers
+
+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)
+{
+	WIN_PORT_ERROR();
+}
+
+void
+_dispatch_event_loop_timer_delete(uint32_t tidx DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+}
+
+#pragma mark dispatch_loop
+
+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();
+}
+
+DISPATCH_NOINLINE
+void
+_dispatch_event_loop_drain(uint32_t flags DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+}
+
+void
+_dispatch_event_loop_wake_owner(dispatch_sync_context_t dsc,
+		dispatch_wlh_t wlh, uint64_t old_state, uint64_t new_state)
+{
+	(void)dsc; (void)wlh; (void)old_state; (void)new_state;
+}
+
+void
+_dispatch_event_loop_wait_for_ownership(dispatch_sync_context_t dsc)
+{
+	if (dsc->dsc_release_storage) {
+		_dispatch_queue_release_storage(dsc->dc_data);
+	}
+}
+
+void
+_dispatch_event_loop_end_ownership(dispatch_wlh_t wlh, uint64_t old_state,
+		uint64_t new_state, uint32_t flags)
+{
+	(void)wlh; (void)old_state; (void)new_state; (void)flags;
+}
+
+#if DISPATCH_WLH_DEBUG
+void
+_dispatch_event_loop_assert_not_owned(dispatch_wlh_t wlh)
+{
+	(void)wlh;
+}
+#endif
+
+void
+_dispatch_event_loop_leave_immediate(dispatch_wlh_t wlh, uint64_t dq_state)
+{
+	(void)wlh; (void)dq_state;
+}
+
+#endif // DISPATCH_EVENT_BACKEND_WINDOWS
diff --git a/src/internal.h b/src/internal.h
index 1eb069c..bde3d4f 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -939,7 +939,7 @@
 		dispatch_assert(_length != -1); \
 		_msg = (char *)malloc((unsigned)_length + 1); \
 		dispatch_assert(_msg); \
-		_snprintf(_msg, (unsigned)_length, "%s" fmt, DISPATCH_ASSERTION_FAILED_MESSAGE, ##__VA_ARGS__); \
+		snprintf(_msg, (unsigned)_length + 1, "%s" fmt, DISPATCH_ASSERTION_FAILED_MESSAGE, ##__VA_ARGS__); \
 		_dispatch_assert_crash(_msg); \
 		free(_msg); \
 	} while (0)
diff --git a/src/shims/generic_win_stubs.c b/src/shims/generic_win_stubs.c
index f6984a2..67b6f51 100644
--- a/src/shims/generic_win_stubs.c
+++ b/src/shims/generic_win_stubs.c
@@ -1,3 +1,23 @@
+#include "internal.h"
+
+/*
+ * This file contains stubbed out functions we are using during
+ * the initial Windows port.  When the port is complete, this file
+ * should be empty (and thus removed).
+ */
+
+void
+_dispatch_runloop_queue_dispose(dispatch_queue_t dq DISPATCH_UNUSED,
+		bool *allow_free DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+}
+
+void
+_dispatch_runloop_queue_xref_dispose(dispatch_queue_t dq DISPATCH_UNUSED)
+{
+	WIN_PORT_ERROR();
+}
 
 /*
  * Stubbed out static data
diff --git a/src/shims/generic_win_stubs.h b/src/shims/generic_win_stubs.h
index d7a6f21..0680112 100644
--- a/src/shims/generic_win_stubs.h
+++ b/src/shims/generic_win_stubs.h
@@ -5,6 +5,7 @@
 #include <stdint.h>
 
 #include <Windows.h>
+#include <crtdbg.h>
 
 #include <io.h>
 #include <process.h>
@@ -44,7 +45,9 @@
 #define O_NONBLOCK 04000
 
 #define bzero(ptr,len) memset((ptr), 0, (len))
-#define snprintf _snprintf
+
+// Report when an unported code path executes.
+#define WIN_PORT_ERROR() \
+		_RPTF1(_CRT_ASSERT, "WIN_PORT_ERROR in %s", __FUNCTION__)
 
 #endif
-
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 508d977..13d8944 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,6 +1,19 @@
 
-execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${CMAKE_SOURCE_DIR}/private" "${CMAKE_CURRENT_BINARY_DIR}/dispatch")
-execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh" "${CMAKE_CURRENT_BINARY_DIR}/leaks-wrapper")
+if(CMAKE_SYSTEM_NAME STREQUAL Windows)
+    execute_process(COMMAND
+                      "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/private"
+                      "${CMAKE_CURRENT_BINARY_DIR}/dispatch")
+    execute_process(COMMAND
+                      "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh"
+                      "${CMAKE_CURRENT_BINARY_DIR}/leaks-wrapper")
+else()
+    execute_process(COMMAND
+                      "${CMAKE_COMMAND}" -E create_symlink "${CMAKE_SOURCE_DIR}/private"
+                      "${CMAKE_CURRENT_BINARY_DIR}/dispatch")
+    execute_process(COMMAND
+                      "${CMAKE_COMMAND}" -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh"
+                      "${CMAKE_CURRENT_BINARY_DIR}/leaks-wrapper")
+endif()
 
 if(CMAKE_SYSTEM_NAME STREQUAL Linux)
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt")