Merge pull request #245 from compnerd/windows-cleanups

Windows cleanups
diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake
new file mode 100644
index 0000000..a29fd26
--- /dev/null
+++ b/cmake/modules/SwiftSupport.cmake
@@ -0,0 +1,69 @@
+
+include(CMakeParseArguments)
+
+function(add_swift_library library)
+  set(options)
+  set(single_value_options MODULE_NAME;MODULE_LINK_NAME;MODULE_PATH;MODULE_CACHE_PATH;OUTPUT)
+  set(multiple_value_options SOURCES;SWIFT_FLAGS;CFLAGS)
+
+  cmake_parse_arguments(ASL "${options}" "${single_value_options}" "${multiple_value_options}" ${ARGN})
+
+  set(flags ${CMAKE_SWIFT_FLAGS})
+
+  list(APPEND flags -emit-library)
+
+  if(ASL_MODULE_NAME)
+    list(APPEND flags -module-name;${ASL_MODULE_NAME})
+  endif()
+  if(ASL_MODULE_LINK_NAME)
+    list(APPEND flags -module-link-name;${ASL_MODULE_LINK_NAME})
+  endif()
+  if(ASL_MODULE_PATH)
+    list(APPEND flags -emit-module-path;${ASL_MODULE_PATH})
+  endif()
+  if(ASL_MODULE_CACHE_PATH)
+    list(APPEND flags -module-cache-path;${ASL_MODULE_CACHE_PATH})
+  endif()
+  if(ASL_SWIFT_FLAGS)
+    foreach(flag ${ASL_SWIFT_FLAGS})
+      list(APPEND flags ${flag})
+    endforeach()
+  endif()
+  if(ASL_CFLAGS)
+    foreach(flag ${ASL_CFLAGS})
+      list(APPEND flags -Xcc;${flag})
+    endforeach()
+  endif()
+
+  # FIXME: We shouldn't /have/ to build things in a single process.
+  # <rdar://problem/15972329>
+  list(APPEND flags -force-single-frontend-invocation)
+
+  set(sources)
+  foreach(source ${ASL_SOURCES})
+    get_filename_component(location ${source} PATH)
+    if(IS_ABSOLUTE ${location})
+      list(APPEND sources ${source})
+    else()
+      list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source})
+    endif()
+  endforeach()
+
+  get_filename_component(module_directory ${ASL_MODULE_PATH} DIRECTORY)
+
+  add_custom_command(OUTPUT
+                       ${ASL_OUTPUT}
+                       ${ASL_MODULE_PATH}
+                       ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc
+                     DEPENDS
+                       ${ASL_SOURCES}
+                     COMMAND
+                       ${CMAKE_COMMAND} -E make_directory ${module_directory}
+                     COMMAND
+                       ${CMAKE_SWIFT_COMPILER} ${flags} -c ${sources} -o ${ASL_OUTPUT})
+  add_custom_target(${library}
+                    DEPENDS
+                       ${ASL_OUTPUT}
+                       ${ASL_MODULE_PATH}
+                       ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc)
+endfunction()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 75c7266..8bc572b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,8 +1,44 @@
 
+include(SwiftSupport)
+
 set(dispatch_BLOCK_SOURCES block.cpp)
 if(HAVE_OBJC)
   list(APPEND dispatch_BLOCK_SOURCES data.m object.m)
 endif()
+set(dispatch_SWIFT_SOURCES)
+if(CMAKE_SWIFT_COMPILER)
+  set(swift_optimization_flags)
+  if(CMAKE_BUILD_TYPE MATCHES Release)
+    set(swift_optimization_flags -O)
+  endif()
+  add_swift_library(swiftDispatch
+                    MODULE_NAME
+                      Dispatch
+                    MODULE_LINK_NAME
+                      dispatch
+                    MODULE_PATH
+                      ${CMAKE_CURRENT_BINARY_DIR}/swift/Dispatch.swiftmodule
+                    OUTPUT
+                      ${CMAKE_CURRENT_BINARY_DIR}/swiftDispatch.o
+                    SOURCES
+                      swift/Block.swift
+                      swift/Data.swift
+                      swift/Dispatch.swift
+                      swift/IO.swift
+                      swift/Private.swift
+                      swift/Queue.swift
+                      swift/Source.swift
+                      swift/Time.swift
+                      swift/Wrapper.swift
+                    CFLAGS
+                      -fblocks
+                      -fmodule-map-file=${CMAKE_SOURCE_DIR}/dispatch/module.modulemap
+                    SWIFT_FLAGS
+                      -I ${CMAKE_SOURCE_DIR}
+                      ${swift_optimization_flags})
+  list(APPEND dispatch_SWIFT_SOURCES
+       swift/DispatchStubs.cc;${CMAKE_CURRENT_BINARY_DIR}/swiftDispatch.o)
+endif()
 add_library(dispatch
               allocator.c
               apply.c
@@ -55,7 +91,8 @@
               shims/time.h
               shims/tsd.h
               shims/yield.h
-              ${dispatch_BLOCK_SOURCES})
+              ${dispatch_BLOCK_SOURCES}
+              ${dispatch_SWIFT_SOURCES})
 target_include_directories(dispatch
                            PRIVATE
                              ${CMAKE_BINARY_DIR}
diff --git a/src/event/event_epoll.c b/src/event/event_epoll.c
index 2788b10..647552f 100644
--- a/src/event/event_epoll.c
+++ b/src/event/event_epoll.c
@@ -117,9 +117,28 @@
 	free(dmn);
 }
 
+static pthread_t manager_thread;
+
+static void
+_dispatch_muxnote_signal_block_and_raise(int signo)
+{
+	// On linux, for signals to be delivered to the signalfd, signals
+	// must be blocked, else any thread that hasn't them blocked may
+	// receive them.  Fix that by lazily noticing, blocking said signal,
+	// and raising the signal again when it happens
+	_dispatch_sigmask();
+	pthread_kill(manager_thread, signo);
+}
+
 static dispatch_muxnote_t
 _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
 {
+	static sigset_t signals_with_unotes;
+	static struct sigaction sa = {
+		.sa_handler = _dispatch_muxnote_signal_block_and_raise,
+		.sa_flags = SA_RESTART,
+	};
+
 	dispatch_muxnote_t dmn;
 	struct stat sb;
 	int fd = du._du->du_ident;
@@ -129,13 +148,17 @@
 
 	switch (filter) {
 	case EVFILT_SIGNAL:
+		if (!sigismember(&signals_with_unotes, du._du->du_ident)) {
+			manager_thread = pthread_self();
+			sigaddset(&signals_with_unotes, du._du->du_ident);
+			sigaction(du._du->du_ident, &sa, NULL);
+		}
 		sigemptyset(&sigmask);
 		sigaddset(&sigmask, du._du->du_ident);
 		fd = signalfd(-1, &sigmask, SFD_NONBLOCK | SFD_CLOEXEC);
 		if (fd < 0) {
 			return NULL;
 		}
-		sigprocmask(SIG_BLOCK, &sigmask, NULL);
 		break;
 
 	case EVFILT_WRITE:
diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c
index b3bd63f..3275888 100644
--- a/src/event/event_kevent.c
+++ b/src/event/event_kevent.c
@@ -1557,7 +1557,7 @@
 	kern_return_t kr;
 #if HAVE_MACH_PORT_CONSTRUCT
 	mach_port_options_t opts = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT };
-#ifdef __LP64__
+#if DISPATCH_SIZEOF_PTR == 8
 	const mach_port_context_t guard = 0xfeed09071f1ca7edull;
 #else
 	const mach_port_context_t guard = 0xff1ca7edull;
diff --git a/src/init.c b/src/init.c
index a04daeb..4ccb1f2 100644
--- a/src/init.c
+++ b/src/init.c
@@ -72,6 +72,29 @@
 	_dispatch_unsafe_fork = 0;
 }
 
+int
+_dispatch_sigmask(void)
+{
+	sigset_t mask;
+	int r = 0;
+
+	/* Workaround: 6269619 Not all signals can be delivered on any thread */
+	r |= sigfillset(&mask);
+	r |= sigdelset(&mask, SIGILL);
+	r |= sigdelset(&mask, SIGTRAP);
+#if HAVE_DECL_SIGEMT
+	r |= sigdelset(&mask, SIGEMT);
+#endif
+	r |= sigdelset(&mask, SIGFPE);
+	r |= sigdelset(&mask, SIGBUS);
+	r |= sigdelset(&mask, SIGSEGV);
+	r |= sigdelset(&mask, SIGSYS);
+	r |= sigdelset(&mask, SIGPIPE);
+	r |= sigdelset(&mask, SIGPROF);
+	r |= pthread_sigmask(SIG_BLOCK, &mask, NULL);
+	(void)dispatch_assume_zero(r);
+}
+
 #pragma mark -
 #pragma mark dispatch_globals
 
diff --git a/src/internal.h b/src/internal.h
index 743d0b2..489da74 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -990,6 +990,8 @@
 #endif // DISPATCH_USE_EVFILT_MACHPORT_DIRECT
 
 
+int _dispatch_sigmask(void);
+
 /* #includes dependent on internal.h */
 #include "object_internal.h"
 #include "semaphore_internal.h"
diff --git a/src/object_internal.h b/src/object_internal.h
index abc3f48..61caebf 100644
--- a/src/object_internal.h
+++ b/src/object_internal.h
@@ -225,7 +225,7 @@
 	.do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT
 #endif
 
-#ifdef __LP64__
+#if DISPATCH_SIZEOF_PTR == 8
 // the bottom nibble must not be zero, the rest of the bits should be random
 // we sign extend the 64-bit version so that a better instruction encoding is
 // generated on Intel
diff --git a/src/queue.c b/src/queue.c
index 088c5cf..be831ab 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -66,7 +66,6 @@
 #endif
 #if DISPATCH_USE_PTHREAD_POOL
 static void *_dispatch_worker_thread(void *context);
-static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
 #endif
 
 #if DISPATCH_COCOA_COMPAT
@@ -5466,13 +5465,8 @@
 		pqc->dpq_thread_configure();
 	}
 
-	sigset_t mask;
-	int r;
 	// workaround tweaks the kernel workqueue does for us
-	r = sigfillset(&mask);
-	(void)dispatch_assume_zero(r);
-	r = _dispatch_pthread_sigmask(SIG_BLOCK, &mask, NULL);
-	(void)dispatch_assume_zero(r);
+	_dispatch_sigmask();
 	_dispatch_introspection_thread_add();
 
 	const int64_t timeout = 5ull * NSEC_PER_SEC;
@@ -5489,37 +5483,6 @@
 
 	return NULL;
 }
-
-int
-_dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset)
-{
-	int r;
-
-	/* Workaround: 6269619 Not all signals can be delivered on any thread */
-
-	r = sigdelset(set, SIGILL);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGTRAP);
-	(void)dispatch_assume_zero(r);
-#if HAVE_DECL_SIGEMT
-	r = sigdelset(set, SIGEMT);
-	(void)dispatch_assume_zero(r);
-#endif
-	r = sigdelset(set, SIGFPE);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGBUS);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGSEGV);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGSYS);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGPIPE);
-	(void)dispatch_assume_zero(r);
-	r = sigdelset(set, SIGPROF);
-	(void)dispatch_assume_zero(r);
-
-	return pthread_sigmask(how, set, oset);
-}
 #endif // DISPATCH_USE_PTHREAD_POOL
 
 #pragma mark -
@@ -5749,6 +5712,7 @@
 		pthread_key_t dispatch_main_key;
 		pthread_key_create(&dispatch_main_key, _dispatch_sig_thread);
 		pthread_setspecific(dispatch_main_key, &dispatch_main_key);
+		_dispatch_sigmask();
 #endif
 		pthread_exit(NULL);
 		DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned");
diff --git a/src/queue_internal.h b/src/queue_internal.h
index 29e83cc..ca9886c 100644
--- a/src/queue_internal.h
+++ b/src/queue_internal.h
@@ -748,7 +748,6 @@
 	void *dc_ctxt; \
 	void *dc_data; \
 	void *dc_other
-#define _DISPATCH_SIZEOF_PTR 8
 #elif OS_OBJECT_HAVE_OBJC1
 #define DISPATCH_CONTINUATION_HEADER(x) \
 	dispatch_function_t dc_func; \
@@ -766,7 +765,6 @@
 	void *dc_ctxt; \
 	void *dc_data; \
 	void *dc_other
-#define _DISPATCH_SIZEOF_PTR 4
 #else
 #define DISPATCH_CONTINUATION_HEADER(x) \
 	union { \
@@ -784,17 +782,16 @@
 	void *dc_ctxt; \
 	void *dc_data; \
 	void *dc_other
-#define _DISPATCH_SIZEOF_PTR 4
 #endif
 #define _DISPATCH_CONTINUATION_PTRS 8
 #if DISPATCH_HW_CONFIG_UP
 // UP devices don't contend on continuations so we don't need to force them to
 // occupy a whole cacheline (which is intended to avoid contention)
 #define DISPATCH_CONTINUATION_SIZE \
-		(_DISPATCH_CONTINUATION_PTRS * _DISPATCH_SIZEOF_PTR)
+		(_DISPATCH_CONTINUATION_PTRS * DISPATCH_SIZEOF_PTR)
 #else
 #define DISPATCH_CONTINUATION_SIZE  ROUND_UP_TO_CACHELINE_SIZE( \
-		(_DISPATCH_CONTINUATION_PTRS * _DISPATCH_SIZEOF_PTR))
+		(_DISPATCH_CONTINUATION_PTRS * DISPATCH_SIZEOF_PTR))
 #endif
 #define ROUND_UP_TO_CONTINUATION_SIZE(x) \
 		(((x) + (DISPATCH_CONTINUATION_SIZE - 1u)) & \
diff --git a/src/shims/hw_config.h b/src/shims/hw_config.h
index 6b5a069..26856bc 100644
--- a/src/shims/hw_config.h
+++ b/src/shims/hw_config.h
@@ -27,6 +27,22 @@
 #ifndef __DISPATCH_SHIMS_HW_CONFIG__
 #define __DISPATCH_SHIMS_HW_CONFIG__
 
+#ifdef __SIZEOF_POINTER__
+#define DISPATCH_SIZEOF_PTR __SIZEOF_POINTER__
+#elif defined(_WIN64)
+#define DISPATCH_SIZEOF_PTR 8
+#elif defined(_WIN32)
+#define DISPATCH_SIZEOF_PTR 4
+#elif defined(_MSC_VER)
+#error "could not determine pointer size as a constant int for MSVC"
+#elif defined(__LP64__) || defined(__LLP64__)
+#define DISPATCH_SIZEOF_PTR 8
+#elif defined(__ILP32__)
+#define DISPATCH_SIZEOF_PTR 4
+#else
+#error "could not determine pointer size as a constant int"
+#endif // __SIZEOF_POINTER__
+
 #if !TARGET_OS_WIN32
 
 typedef enum {
diff --git a/tests/dispatch_queue_finalizer.c b/tests/dispatch_queue_finalizer.c
index ec9daa5..9c16e7e 100644
--- a/tests/dispatch_queue_finalizer.c
+++ b/tests/dispatch_queue_finalizer.c
@@ -50,7 +50,7 @@
 {
 	dispatch_test_start("Dispatch Queue Finalizer");
 
-#ifdef __LP64__
+#if DISPATCH_SIZEOF_PTR == 8
 	ctxt_magic = (void*)((uintptr_t)arc4random() << 32 | arc4random());
 #else
 	ctxt_magic = (void*)arc4random();