Merge pull request #233 from amboar/master

lock: Avoid use of undefined DISPATCH_INTERNAL_CRASH 
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..08f6fc1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,202 @@
+
+cmake_minimum_required(VERSION 3.4.3)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
+
+project(dispatch
+        VERSION 1.3
+        LANGUAGES C CXX)
+enable_testing()
+
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+set(CMAKE_CXX_STANDARD 11)
+
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+find_package(Threads REQUIRED)
+
+include(GNUInstallDirs)
+include(ExternalProject)
+
+set(WITH_BLOCKS_RUNTIME "" CACHE PATH "Path to blocks runtime")
+set(WITH_PTHREAD_WORKQUEUES "" CACHE PATH "Path to pthread-workqueues")
+
+include(DispatchAppleOptions)
+
+option(ENABLE_DISPATCH_INIT_CONSTRUCTOR "enable libdispatch_init as a constructor" ON)
+set(USE_LIBDISPATCH_INIT_CONSTRUCTOR ${ENABLE_DISPATCH_INIT_CONSTRUCTOR})
+
+# TODO(compnerd) swift options
+
+# TODO(compnerd) consider adding a flag for USE_GOLD_LINKER.  Currently, we
+# expect the user to specify `-fuse-ld=gold`
+
+option(ENABLE_THREAD_LOCAL_STORAGE "enable usage of thread local storage via __thread" ON)
+set(DISPATCH_USE_THREAD_LOCAL_STORAGE ${ENABLE_THREAD_LOCAL_STORAGE})
+
+if(EXISTS "${CMAKE_SOURCE_DIR}/libpwq/CMakeLists.txt")
+  ExternalProject_Add(pwq
+                      SOURCE_DIR
+                        "${CMAKE_SOURCE_DIR}/libpwq"
+                      CMAKE_ARGS
+                        -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+                        -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}
+                        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+                      BUILD_BYPRODUCTS
+                        <INSTALL_DIR>/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pthread_workqueue${CMAKE_STATIC_LIBRARY_SUFFIX})
+  ExternalProject_Get_Property(pwq install_dir)
+  add_library(PTHREAD::workqueue UNKNOWN IMPORTED)
+  set_target_properties(PTHREAD::workqueue
+                        PROPERTIES
+                          IMPORTED_LOCATION ${install_dir}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pthread_workqueue${CMAKE_STATIC_LIBRARY_SUFFIX})
+  set(WITH_PTHREAD_WORKQUEUES "${install_dir}" CACHE PATH "Path to pthread-workqueues" FORCE)
+  set(HAVE_PTHREAD_WORKQUEUES 1)
+else()
+  # TODO(compnerd) support system installed pthread-workqueues
+  # find_package(pthread_workqueues REQUIRED)
+  # set(HAVE_PTHREAD_WORKQUEUES 1)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL Linux OR
+   CMAKE_SYSTEM_NAME STREQUAL Android OR
+   CMAKE_SYSTEM_NAME STREQUAL Windows)
+  add_library(BlocksRuntime
+              STATIC
+                ${CMAKE_SOURCE_DIR}/src/BlocksRuntime/data.c
+                ${CMAKE_SOURCE_DIR}/src/BlocksRuntime/runtime.c)
+  set_target_properties(BlocksRuntime
+                        PROPERTIES
+                          POSITION_INDEPENDENT_CODE TRUE)
+  if(HAVE_OBJC AND CMAKE_DL_LIBS)
+    set_target_properties(BlocksRuntime
+                          PROPERTIES
+                            INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
+  endif()
+  set(WITH_BLOCKS_RUNTIME "${CMAKE_SOURCE_DIR}/src/BlocksRuntime" CACHE PATH "Path to blocks runtime" FORCE)
+else()
+  # TODO(compnerd) support system installed BlocksRuntime
+  # find_package(BlocksRuntime REQUIRED)
+endif()
+
+include(CheckCSourceCompiles)
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+
+check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
+if(_GNU_SOURCE)
+  set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE)
+endif()
+
+check_c_source_compiles("void __attribute__((__noreturn__)) main() { __builtin_trap(); }"
+                        __BUILTIN_TRAP)
+if(__BUILTIN_TRAP)
+  set(HAVE_NORETURN_BUILTIN_TRAP 1)
+endif()
+
+find_package(LibRT)
+
+check_function_exists(_pthread_workqueue_init HAVE__PTHREAD_WORKQUEUE_INIT)
+check_function_exists(getprogname HAVE_GETPROGNAME)
+check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME)
+check_function_exists(mach_approximate_time HAVE_MACH_APPROXIMATE_TIME)
+check_function_exists(mach_port_construct HAVE_MACH_PORT_CONSTRUCT)
+check_function_exists(malloc_create_zone HAVE_MALLOC_CREATE_ZONE)
+check_function_exists(pthread_key_init_np HAVE_PTHREAD_KEY_INIT_NP)
+check_function_exists(pthread_main_np HAVE_PTHREAD_MAIN_NP)
+check_function_exists(pthread_workqueue_setdispatch_np HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP)
+check_function_exists(strlcpy HAVE_STRLCPY)
+check_function_exists(sysconf HAVE_SYSCONF)
+
+if(NOT HAVE_STRLCPY AND NOT HAVE_GETPROGNAME)
+  include(FindPkgConfig)
+  pkg_check_modules(BSD_OVERLAY libbsd-overlay)
+  if(BSD_OVERLAY_FOUND)
+    set(HAVE_STRLCPY 1 CACHE INTERNAL "Have function strlcpy" FORCE)
+    set(HAVE_GETPROGNAME 1 CACHE INTERNAL "Have function getprogname" FORCE)
+  endif()
+endif()
+
+find_package(Threads REQUIRED)
+
+check_include_files("TargetConditionals.h" HAVE_TARGETCONDITIONALS_H)
+check_include_files("dlfcn.h" HAVE_DLFCN_H)
+check_include_files("fcntl.h" HAVE_FCNTL_H)
+check_include_files("inttypes.h" HAVE_INTTYPES_H)
+check_include_files("libkern/OSAtomic.h" HAVE_LIBKERN_OSATOMIC_H)
+check_include_files("libkern/OSCrossEndian.h" HAVE_LIBKERN_OSCROSSENDIAN_H)
+check_include_files("libproc_internal.h" HAVE_LIBPROC_INTERNAL_H)
+check_include_files("mach/mach.h" HAVE_MACH)
+if(HAVE_MACH)
+  set(__DARWIN_NON_CANCELABLE 1)
+  set(USE_MACH_SEM 1)
+else()
+  set(__DARWIN_NON_CANCELABLE 0)
+  set(USE_MACH_SEM 0)
+endif()
+check_include_files("malloc/malloc.h" HAVE_MALLOC_MALLOC_H)
+check_include_files("memory.h" HAVE_MEMORY_H)
+check_include_files("pthread/qos.h" HAVE_PTHREAD_QOS_H)
+check_include_files("pthread/workqueue_private.h" HAVE_PTHREAD_WORKQUEUE_PRIVATE_H)
+check_include_files("pthread_machdep.h" HAVE_PTHREAD_MACHDEP_H)
+check_include_files("pthread_np.h" HAVE_PTHREAD_NP_H)
+check_include_files("pthread_workqueue.h" HAVE_PTHREAD_WORKQUEUE_H)
+check_include_files("stdint.h" HAVE_STDINT_H)
+check_include_files("stdlib.h" HAVE_STDLIB_H)
+check_include_files("string.h" HAVE_STRING_H)
+check_include_files("strings.h" HAVE_STRINGS_H)
+check_include_files("sys/cdefs.h" HAVE_SYS_CDEFS_H)
+check_include_files("sys/guarded.h" HAVE_SYS_GUARDED_H)
+check_include_files("sys/stat.h" HAVE_SYS_STAT_H)
+check_include_files("sys/types.h" HAVE_SYS_TYPES_H)
+check_include_files("unistd.h" HAVE_UNISTD_H)
+check_include_files("objc/objc-internal.h" HAVE_OBJC)
+
+check_library_exists(pthread sem_init "" USE_POSIX_SEM)
+
+check_symbol_exists(CLOCK_UPTIME "time.h" HAVE_DECL_CLOCK_UPTIME)
+check_symbol_exists(CLOCK_UPTIME_FAST "time.h" HAVE_DECL_CLOCK_UPTIME_FAST)
+check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_DECL_CLOCK_MONOTONIC)
+check_symbol_exists(CLOCK_REALTIME "time.h" HAVE_DECL_CLOCK_REALTIME)
+check_symbol_exists(FD_COPY "sys/select.h" HAVE_DECL_FD_COPY)
+check_symbol_exists(NOTE_LOWAT "sys/event.h" HAVE_DECL_NOTE_LOWAT)
+check_symbol_exists(NOTE_NONE "sys/event.h" HAVE_DECL_NOTE_NONE)
+check_symbol_exists(NOTE_REAP "sys/event.h" HAVE_DECL_NOTE_REAP)
+check_symbol_exists(NOTE_REVOKE "sys/event.h" HAVE_DECL_NOTE_REVOKE)
+check_symbol_exists(NOTE_SIGNAL "sys/event.h" HAVE_DECL_NOTE_SIGNAL)
+check_symbol_exists(POSIX_SPAWN_START_SUSPENDED "sys/spawn.h" HAVE_DECL_POSIX_SPAWN_START_SUSPENDED)
+check_symbol_exists(SIGEMT "signal.h" HAVE_DECL_SIGEMT)
+check_symbol_exists(VQ_DESIRED_DISK "sys/mount.h" HAVE_DECL_VQ_DESIRED_DISK)
+check_symbol_exists(VQ_NEARLOWDISK "sys/mount.h" HAVE_DECL_VQ_NEARLOWDISK)
+check_symbol_exists(VQ_QUOTA "sys/mount.h" HAVE_DECL_VQ_QUOTA)
+check_symbol_exists(VQ_UPDATE "sys/mount.h" HAVE_DECL_VQ_UPDATE)
+check_symbol_exists(VQ_VERYLOWDISK "sys/mount.h" HAVE_DECL_VQ_VERYLOWDISK)
+
+check_symbol_exists(program_invocation_name "errno.h" HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME)
+
+find_program(dtrace_EXECUTABLE dtrace)
+if(dtrace_EXECUTABLE)
+  add_definitions(-DDISPATCH_USE_DTRACE=1)
+else()
+  add_definitions(-DDISPATCH_USE_DTRACE=0)
+endif()
+
+find_program(leaks_EXECUTABLE leaks)
+if(leaks_EXECUTABLE)
+  set(HAVE_LEAKS TRUE)
+endif()
+
+configure_file("${CMAKE_SOURCE_DIR}/cmake/config.h.in"
+               "${CMAKE_BINARY_DIR}/config/config_ac.h")
+add_definitions(-DHAVE_CONFIG_H)
+
+add_subdirectory(dispatch)
+add_subdirectory(man)
+add_subdirectory(os)
+add_subdirectory(private)
+add_subdirectory(src)
+if(ENABLE_TESTING)
+  add_subdirectory(tests)
+endif()
+
diff --git a/cmake/config.h.in b/cmake/config.h.in
new file mode 100644
index 0000000..27156dc
--- /dev/null
+++ b/cmake/config.h.in
@@ -0,0 +1,248 @@
+
+/* Define if building pthread work queues from source */
+#cmakedefine BUILD_OWN_PTHREAD_WORKQUEUES
+
+/* Enable usage of thread local storage via __thread */
+#cmakedefine01 DISPATCH_USE_THREAD_LOCAL_STORAGE
+
+/* Define to 1 if you have the declaration of `CLOCK_MONOTONIC', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_CLOCK_MONOTONIC
+
+/* Define to 1 if you have the declaration of `CLOCK_REALTIME', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_CLOCK_REALTIME
+
+/* Define to 1 if you have the declaration of `CLOCK_UPTIME', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_CLOCK_UPTIME
+
+/* Define to 1 if you have the declaration of `CLOCK_UPTIME_FAST', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_CLOCK_UPTIME_FAST
+
+/* Define to 1 if you have the declaration of `FD_COPY', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_FD_COPY
+
+/* Define to 1 if you have the declaration of `NOTE_LOWAT', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_NOTE_LOWAT
+
+/* Define to 1 if you have the declaration of `NOTE_NONE', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_NOTE_NONE
+
+/* Define to 1 if you have the declaration of `NOTE_REAP', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_NOTE_REAP
+
+/* Define to 1 if you have the declaration of `NOTE_REVOKE', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_NOTE_REVOKE
+
+/* Define to 1 if you have the declaration of `NOTE_SIGNAL', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_NOTE_SIGNAL
+
+/* Define to 1 if you have the declaration of `POSIX_SPAWN_START_SUSPENDED',
+   and to 0 if you don't. */
+#cmakedefine01 HAVE_DECL_POSIX_SPAWN_START_SUSPENDED
+
+/* Define to 1 if you have the declaration of `program_invocation_short_name',
+   and to 0 if you don't. */
+#cmakedefine01 HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
+
+/* Define to 1 if you have the declaration of `SIGEMT', and to 0 if you don't.
+   */
+#cmakedefine01 HAVE_DECL_SIGEMT
+
+/* Define to 1 if you have the declaration of `VQ_DESIRED_DISK', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_VQ_DESIRED_DISK
+
+/* Define to 1 if you have the declaration of `VQ_NEARLOWDISK', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_VQ_NEARLOWDISK
+
+/* Define to 1 if you have the declaration of `VQ_QUOTA', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_VQ_QUOTA
+
+/* Define to 1 if you have the declaration of `VQ_UPDATE', and to 0 if you
+   don't. */
+#cmakedefine01 HAVE_DECL_VQ_UPDATE
+
+/* Define to 1 if you have the declaration of `VQ_VERYLOWDISK', and to 0 if
+   you don't. */
+#cmakedefine01 HAVE_DECL_VQ_VERYLOWDISK
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine01 HAVE_DLFCN_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine01 HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getprogname' function. */
+#cmakedefine01 HAVE_GETPROGNAME
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine01 HAVE_INTTYPES_H
+
+/* Define if Apple leaks program is present */
+#cmakedefine HAVE_LEAKS
+
+/* Define to 1 if you have the <libkern/OSAtomic.h> header file. */
+#cmakedefine HAVE_LIBKERN_OSATOMIC_H
+
+/* Define to 1 if you have the <libkern/OSCrossEndian.h> header file. */
+#cmakedefine HAVE_LIBKERN_OSCROSSENDIAN_H
+
+/* Define to 1 if you have the <libproc_internal.h> header file. */
+#cmakedefine HAVE_LIBPROC_INTERNAL_H
+
+/* Define if mach is present */
+#cmakedefine HAVE_MACH
+
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#cmakedefine HAVE_MACH_ABSOLUTE_TIME
+
+/* Define to 1 if you have the `mach_approximate_time' function. */
+#cmakedefine HAVE_MACH_APPROXIMATE_TIME
+
+/* Define to 1 if you have the `mach_port_construct' function. */
+#cmakedefine HAVE_MACH_PORT_CONSTRUCT
+
+/* Define to 1 if you have the `malloc_create_zone' function. */
+#cmakedefine HAVE_MALLOC_CREATE_ZONE
+
+/* Define to 1 if you have the <malloc/malloc.h> header file. */
+#cmakedefine HAVE_MALLOC_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine01 HAVE_MEMORY_H
+
+/* Define if __builtin_trap marked noreturn */
+#cmakedefine01 HAVE_NORETURN_BUILTIN_TRAP
+
+/* Define if you have the Objective-C runtime */
+#cmakedefine HAVE_OBJC
+
+/* Define to 1 if you have the `pthread_key_init_np' function. */
+#cmakedefine HAVE_PTHREAD_KEY_INIT_NP
+
+/* Define to 1 if you have the <pthread_machdep.h> header file. */
+#cmakedefine HAVE_PTHREAD_MACHDEP_H
+
+/* Define to 1 if you have the `pthread_main_np' function. */
+#cmakedefine HAVE_PTHREAD_MAIN_NP
+
+/* Define to 1 if you have the <pthread_np.h> header file. */
+#cmakedefine HAVE_PTHREAD_NP_H
+
+/* Define to 1 if you have the <pthread/qos.h> header file. */
+#cmakedefine HAVE_PTHREAD_QOS_H
+
+/* Define if pthread work queues are present */
+#cmakedefine01 HAVE_PTHREAD_WORKQUEUES
+
+/* Define to 1 if you have the <pthread_workqueue.h> header file. */
+#cmakedefine HAVE_PTHREAD_WORKQUEUE_H
+
+/* Define to 1 if you have the <pthread/workqueue_private.h> header file. */
+#cmakedefine HAVE_PTHREAD_WORKQUEUE_PRIVATE_H
+
+/* Define to 1 if you have the `pthread_workqueue_setdispatch_np' function. */
+#cmakedefine HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine01 HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine01 HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine01 HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine01 HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine01 HAVE_STRLCPY
+
+/* Define if building for Swift */
+#undef HAVE_SWIFT
+
+/* Define to 1 if you have the `sysconf' function. */
+#cmakedefine01 HAVE_SYSCONF
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#cmakedefine01 HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/guarded.h> header file. */
+#cmakedefine HAVE_SYS_GUARDED_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine01 HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine01 HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <TargetConditionals.h> header file. */
+#cmakedefine HAVE_TARGETCONDITIONALS_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine01 HAVE_UNISTD_H
+
+/* Define to 1 if you have the `_pthread_workqueue_init' function. */
+#cmakedefine HAVE__PTHREAD_WORKQUEUE_INIT
+
+/* Define to use non-portable pthread TSD optimizations for Mac OS X) */
+#cmakedefine USE_APPLE_TSD_OPTIMIZATIONS
+
+/* Define to tag libdispatch_init as a constructor */
+#cmakedefine01 USE_LIBDISPATCH_INIT_CONSTRUCTOR
+
+/* Define to use Mach semaphores */
+#cmakedefine USE_MACH_SEM
+
+/* Define to use POSIX semaphores */
+#cmakedefine01 USE_POSIX_SEM
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+#cmakedefine01 _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+#cmakedefine01 _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#cmakedefine01 _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+#cmakedefine01 _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+#cmakedefine01 __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#define VERSION "${PROJECT_VERSION}"
+
+/* Define to 1 if on MINIX. */
+#cmakedefine _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#cmakedefine _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#cmakedefine _POSIX_SOURCE
+
+/* Define if using Darwin $NOCANCEL */
+#cmakedefine __DARWIN_NON_CANCELABLE
diff --git a/cmake/modules/DispatchAppleOptions.cmake b/cmake/modules/DispatchAppleOptions.cmake
new file mode 100644
index 0000000..1f95f88
--- /dev/null
+++ b/cmake/modules/DispatchAppleOptions.cmake
@@ -0,0 +1,43 @@
+
+set(WITH_APPLE_PTHREAD_SOURCE "" CACHE PATH "Path to Apple's libpthread")
+set(WITH_APPLE_LIBPLATFORM_SOURCE "" CACHE PATH "Path to Apple's libplatform")
+set(WITH_APPLE_LIBCLOSURE_SOURCE "" CACHE PATH "Path to Apple's libclosure")
+set(WITH_APPLE_XNU_SOURCE "" CACHE PATH "Path to Apple's XNU")
+set(WITH_APPLE_OBJC4_SOURCE "" CACHE PATH "Path to Apple's ObjC4")
+
+if(WITH_APPLE_PTHREAD_SOURCE)
+  include_directories(SYSTEM "${WITH_APPLE_PTHREAD_SOURCE}")
+endif()
+if(WITH_APPLE_LIBPLATFORM_SOURCE)
+  include_directories(SYSTEM "${WITH_APPLE_LIBPLATFORM_SOURCE}/include")
+endif()
+if(WITH_APPLE_LIBCLOSURE_SOURCE)
+  include_directories(SYSTEM "${WITH_APPLE_LIBCLOSURE_SOURCE}")
+endif()
+if(WITH_APPLE_XNU_SOURCE)
+  # FIXME(compnerd) this should use -idirafter
+  include_directories("${WITH_APPLE_XNU_SOURCE}/libkern")
+  include_directories(SYSTEM
+                        "${WITH_APPLE_XNU_SOURCE}/bsd"
+                        "${WITH_APPLE_XNU_SOURCE}/libsyscall"
+                        "${WITH_APPLE_XNU_SOURCE}/libsyscall/wrappers/libproc")
+
+  # hack for xnu/bsd/sys/event.h EVFILT_SOCK declaration
+  add_definitions(-DPRIVATE=1)
+endif()
+
+if(IS_DIRECTORY "/System/Library/Frameworks/System.framework/PrivateHeaders")
+  include_directories(SYSTEM
+                        "/System/Library/Frameworks/System.framework/PrivateHeaders")
+endif()
+
+option(ENABLE_APPLE_TSD_OPTIMIZATIONS "use non-portable pthread TSD optimizations" OFF)
+if(ENABLE_APPLE_TSD_OPTIMIZATIONS)
+  set(USE_APPLE_TSD_OPTIMIZATIONS 1)
+else()
+  set(USE_APPLE_TSD_OPTIMIZATIONS 0)
+endif()
+
+# TODO(compnerd) link in libpthread headers
+
+
diff --git a/cmake/modules/FindLibRT.cmake b/cmake/modules/FindLibRT.cmake
new file mode 100644
index 0000000..0a9f0d8
--- /dev/null
+++ b/cmake/modules/FindLibRT.cmake
@@ -0,0 +1,39 @@
+#.rst:
+# FindLibRT
+# ---------
+#
+# Find librt library and headers.
+#
+# The mdoule defines the following variables:
+#
+# ::
+#
+# LibRT_FOUND       - true if librt was found
+# LibRT_INCLUDE_DIR - include search path
+# LibRT_LIBRARIES   - libraries to link
+
+if(UNIX)
+  find_path(LibRT_INCLUDE_DIR
+            NAMES
+              time.h)
+  find_library(LibRT_LIBRARIES rt)
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(LibRT
+                                    REQUIRED_VARS
+                                      LibRT_LIBRARIES
+                                      LibRT_INCLUDE_DIR)
+
+  if(LibRT_FOUND)
+    if(NOT TARGET RT::rt)
+      add_library(RT::rt UNKNOWN IMPORTED)
+      set_target_properties(RT::rt
+                            PROPERTIES
+                              IMPORTED_LOCATION ${LibRT_LIBRARIES}
+                              INTERFACE_INCLUDE_DIRECTORIES ${LibRT_INCLUDE_DIR})
+    endif()
+  endif()
+
+  mark_as_advanced(LibRT_LIBRARIES LibRT_INCLUDE_DIR)
+endif()
+
diff --git a/dispatch/CMakeLists.txt b/dispatch/CMakeLists.txt
new file mode 100644
index 0000000..dbfb866
--- /dev/null
+++ b/dispatch/CMakeLists.txt
@@ -0,0 +1,24 @@
+
+install(FILES
+          base.h
+          block.h
+          data.h
+          dispatch.h
+          group.h
+          introspection.h
+          io.h
+          object.h
+          once.h
+          queue.h
+          semaphore.h
+          source.h
+          time.h
+        DESTINATION
+          ${CMAKE_INSTALL_FULL_INCLUDEDIR}/dispatch/)
+if(ENABLE_SWIFT)
+  install(FILES
+            module.modulemap
+          DESTINATION
+            ${CMAKE_INSTALL_FULL_INCLUEDIR}/dispatch/)
+endif()
+
diff --git a/dispatch/darwin/module.modulemap b/dispatch/darwin/module.modulemap
index addaae4..e30807f 100644
--- a/dispatch/darwin/module.modulemap
+++ b/dispatch/darwin/module.modulemap
@@ -1,6 +1,5 @@
 module Dispatch [system] [extern_c] {
 	umbrella header "dispatch.h"
-	module * { export * }
 	export *
 }
 
diff --git a/dispatch/generic/module.modulemap b/dispatch/generic/module.modulemap
index 5c248e5..8c3e7d0 100644
--- a/dispatch/generic/module.modulemap
+++ b/dispatch/generic/module.modulemap
@@ -11,7 +11,6 @@
 
 module CDispatch [system] [extern_c] {
 	umbrella header "dispatch.h"
-	module * { export * }
 	export *
 	requires blocks
 	link "dispatch"
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
new file mode 100644
index 0000000..e81b14b
--- /dev/null
+++ b/man/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+# TODO(compnerd) add symlinks
+if(NOT ENABLE_SWIFT)
+  install(FILES
+            dispatch.3
+            dispatch_after.3
+            dispatch_api.3
+            dispatch_apply.3
+            dispatch_async.3
+            dispatch_data_create.3
+            dispatch_group_create.3
+            dispatch_io_create.3
+            dispatch_io_read.3
+            dispatch_object.3
+            dispatch_once.3
+            dispatch_queue_create.3
+            dispatch_read.3
+            dispatch_semaphore_create.3
+            dispatch_source_create.3
+            dispatch_time.3
+          DESTINATION
+            "${CMAKE_INSTALL_FULL_MANDIR}/man3")
+endif()
diff --git a/os/CMakeLists.txt b/os/CMakeLists.txt
new file mode 100644
index 0000000..6e2b415
--- /dev/null
+++ b/os/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+# TODO(compnerd) ensure that object_private.h voucher_activity_private.h
+# voucher_private.h are included in the source tarball
+
+install(FILES
+          object.h
+          linux_base.h
+        DESTINATION
+          "${CMAKE_INSTALL_FULL_INCLUDEDIR}/os")
+
diff --git a/private/CMakeLists.txt b/private/CMakeLists.txt
new file mode 100644
index 0000000..18788d7
--- /dev/null
+++ b/private/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+# TODO(compnerd) ensure that benchmark.h data_private.h introduction_private.h
+# io_private.h layout_private.h mach_private.h private.h queue_private.h
+# source_private.h are included in the source tarball
+
diff --git a/private/darwin/module.modulemap b/private/darwin/module.modulemap
index 62975a5..ceb963a 100644
--- a/private/darwin/module.modulemap
+++ b/private/darwin/module.modulemap
@@ -1,7 +1,6 @@
 module DispatchPrivate [system] [extern_c] {
 	umbrella header "private.h"
 	exclude header "mach_private.h"
-	module * { export * }
 	export *
 }
 
diff --git a/private/generic/module.modulemap b/private/generic/module.modulemap
index 62975a5..ceb963a 100644
--- a/private/generic/module.modulemap
+++ b/private/generic/module.modulemap
@@ -1,7 +1,6 @@
 module DispatchPrivate [system] [extern_c] {
 	umbrella header "private.h"
 	exclude header "mach_private.h"
-	module * { export * }
 	export *
 }
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..113ff4e
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,117 @@
+
+set(dispatch_BLOCK_SOURCES block.cpp)
+if(HAVE_OBJC)
+  list(APPEND dispatch_BLOCK_SOURCES data.m object.m)
+endif()
+add_library(dispatch
+              allocator.c
+              apply.c
+              benchmark.c
+              data.c
+              init.c
+              introspection.c
+              io.c
+              mach.c
+              object.c
+              once.c
+              queue.c
+              semaphore.c
+              source.c
+              time.c
+              transform.c
+              voucher.c
+              protocol.defs
+              provider.d
+              allocator_internal.h
+              data_internal.h
+              inline_internal.h
+              internal.h
+              introspection_internal.h
+              io_internal.h
+              mach_internal.h
+              object_internal.h
+              queue_internal.h
+              semaphore_internal.h
+              shims.h
+              source_internal.h
+              trace.h
+              voucher_internal.h
+              event/event.c
+              event/event_config.h
+              event/event_epoll.c
+              event/event_internal.h
+              event/event_kevent.c
+              firehose/firehose_internal.h
+              shims/android_stubs.h
+              shims/atomic.h
+              shims/atomic_sfb.h
+              shims/getprogname.h
+              shims/hw_config.h
+              shims/linux_stubs.c
+              shims/linux_stubs.h
+              shims/lock.c
+              shims/lock.h
+              shims/perfmon.h
+              shims/time.h
+              shims/tsd.h
+              shims/yield.h
+              ${dispatch_BLOCK_SOURCES})
+target_include_directories(dispatch
+                           PRIVATE
+                             ${CMAKE_BINARY_DIR}
+                             ${CMAKE_SOURCE_DIR}
+                             ${CMAKE_CURRENT_SOURCE_DIR}
+                             ${CMAKE_SOURCE_DIR}/private)
+if(WITH_PTHREAD_WORKQUEUES)
+  target_include_directories(dispatch
+                             SYSTEM BEFORE PRIVATE
+                               "${WITH_PTHREAD_WORKQUEUES}/include")
+endif()
+if(WITH_BLOCKS_RUNTIME)
+  target_include_directories(dispatch
+                             SYSTEM BEFORE PRIVATE
+                               "${WITH_BLOCKS_RUNTIME}")
+endif()
+# TODO(compnerd) make this portable
+target_compile_options(dispatch PRIVATE -fno-exceptions)
+if(DISPATCH_ENABLE_ASSERTS)
+  target_compile_definitions(dispatch
+                             PRIVATE
+                               -DDISPATCH_DEBUG=1)
+endif()
+if(BSD_OVERLAY_FOUND)
+  target_compile_options(dispatch
+                         PRIVATE
+                           ${BSD_OVERLAY_CFLAGS})
+endif()
+# FIXME(compnerd) add check for -momit-leaf-frame-pointer?
+target_compile_options(dispatch
+                       PRIVATE
+                         -Wall
+                         -fblocks
+                         -momit-leaf-frame-pointer)
+if(BSD_OVERLAY_FOUND)
+  target_link_libraries(dispatch PRIVATE ${BSD_OVERLAY_LDFLAGS})
+endif()
+target_link_libraries(dispatch PRIVATE Threads::Threads)
+if(WITH_PTHREAD_WORKQUEUES)
+  target_link_libraries(dispatch PRIVATE PTHREAD::workqueue)
+endif()
+if(WITH_BLOCKS_RUNTIME)
+  target_link_libraries(dispatch PRIVATE BlocksRuntime)
+endif()
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+  set_property(TARGET dispatch
+               APPEND_STRING
+               PROPERTY LINK_FLAGS
+                 "-Xlinker -compatibility_version -Xlinker 1"
+                 "-Xlinker -current_version -Xlinker ${VERSION}"
+                 "-Xlinker -dead_strip"
+                 "-Xlinker -alias_list -Xlinker ${CMAKE_SOURCE_DIR}/xcodeconfig/libdispatch.aliases")
+endif()
+
+install(TARGETS
+          dispatch
+        DESTINATION
+          "${CMAKE_INSTALL_FULL_LIBDIR}")
+
diff --git a/src/shims/lock.h b/src/shims/lock.h
index ea77097..4bbbb42 100644
--- a/src/shims/lock.h
+++ b/src/shims/lock.h
@@ -89,7 +89,7 @@
 
 #elif defined(__linux__)
 #include <linux/futex.h>
-#if !defined(__x86_64__) && !defined(__i386__)
+#if !defined(__x86_64__) && !defined(__i386__) && !defined(__s390x__)
 #include <linux/membarrier.h>
 #endif
 #include <unistd.h>
@@ -542,8 +542,9 @@
 static inline dispatch_once_t
 _dispatch_once_xchg_done(dispatch_once_t *pred)
 {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
 	// On Intel, any load is a load-acquire, so we don't need to be fancy
+	// same for s390x
 	return os_atomic_xchg(pred, DLOCK_ONCE_DONE, release);
 #elif defined(__linux__)
 	if (unlikely(syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0) < 0)) {
diff --git a/src/swift/Time.swift b/src/swift/Time.swift
index 0b07742..8178ffd 100644
--- a/src/swift/Time.swift
+++ b/src/swift/Time.swift
@@ -17,6 +17,14 @@
 import CDispatch
 
 public struct DispatchTime : Comparable {
+#if HAVE_MACH
+	private static let timebaseInfo: mach_timebase_info_data_t = {
+		var info = mach_timebase_info_data_t(numer: 1, denom: 1)
+		mach_timebase_info(&info)
+		return info
+	}()
+#endif
+ 
 	public let rawValue: dispatch_time_t
 
 	public static func now() -> DispatchTime {
@@ -39,16 +47,34 @@
 	/// - Returns: A new `DispatchTime`
 	/// - Discussion: This clock is the same as the value returned by
 	///               `mach_absolute_time` when converted into nanoseconds.
+	///               On some platforms, the nanosecond value is rounded up to a
+	///               multiple of the Mach timebase, using the conversion factors
+	///               returned by `mach_timebase_info()`. The nanosecond equivalent
+	///               of the rounded result can be obtained by reading the
+	///               `uptimeNanoseconds` property.
 	///               Note that `DispatchTime(uptimeNanoseconds: 0)` is
 	///               equivalent to `DispatchTime.now()`, that is, its value
 	///               represents the number of nanoseconds since boot (excluding
 	///               system sleep time), not zero nanoseconds since boot.
 	public init(uptimeNanoseconds: UInt64) {
-		self.rawValue = dispatch_time_t(uptimeNanoseconds)
+		var rawValue = uptimeNanoseconds
+#if HAVE_MACH
+		if (DispatchTime.timebaseInfo.numer != DispatchTime.timebaseInfo.denom) {
+			rawValue = (rawValue * UInt64(DispatchTime.timebaseInfo.denom) 
+				+ UInt64(DispatchTime.timebaseInfo.numer - 1)) / UInt64(DispatchTime.timebaseInfo.numer)
+		}
+#endif
+		self.rawValue = dispatch_time_t(rawValue)
 	}
 
 	public var uptimeNanoseconds: UInt64 {
-		return UInt64(self.rawValue)
+		var result = self.rawValue
+#if HAVE_MACH
+		if (DispatchTime.timebaseInfo.numer != DispatchTime.timebaseInfo.denom) {
+			result = result * UInt64(DispatchTime.timebaseInfo.numer) / UInt64(DispatchTime.timebaseInfo.denom)
+		}
+#endif
+		return result
 	}
 }
 
@@ -81,8 +107,12 @@
 }
 
 public func <(a: DispatchWallTime, b: DispatchWallTime) -> Bool {
-	if a.rawValue == ~0 || b.rawValue == ~0 { return false }
-	return -Int64(a.rawValue) < -Int64(b.rawValue)
+	if b.rawValue == ~0 {
+		return a.rawValue != ~0
+	} else if a.rawValue == ~0 {
+		return false
+	}
+	return -Int64(bitPattern: a.rawValue) < -Int64(bitPattern: b.rawValue)
 }
 
 public func ==(a: DispatchWallTime, b: DispatchWallTime) -> Bool {
@@ -147,7 +177,7 @@
 }
 
 public func -(time: DispatchWallTime, seconds: Double) -> DispatchWallTime {
-	let interval = seconds * Double(NSEC_PER_SEC)
+	let interval = -seconds * Double(NSEC_PER_SEC)
 	let t = CDispatch.dispatch_time(time.rawValue,
 		interval.isInfinite || interval.isNaN ? Int64.min : Int64(interval))
 	return DispatchWallTime(rawValue: t)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..3d5b1c1
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,139 @@
+
+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")
+
+add_library(bsdtests
+            STATIC
+              bsdtests.c
+              dispatch_test.c)
+target_include_directories(bsdtests
+                           PRIVATE
+                             ${CMAKE_CURRENT_BINARY_DIR}
+                             ${CMAKE_CURRENT_SOURCE_DIR}
+                             ${CMAKE_SOURCE_DIR})
+if(BSD_OVERLAY_FOUND)
+  target_compile_options(bsdtests
+                         PRIVATE
+                           ${BSD_OVERLAY_CFLAGS})
+endif()
+
+add_executable(bsdtestharness
+               bsdtestharness.c)
+target_include_directories(bsdtestharness
+                           PRIVATE
+                             ${CMAKE_CURRENT_BINARY_DIR}
+                             ${CMAKE_CURRENT_SOURCE_DIR}
+                             ${CMAKE_SOURCE_DIR})
+if(BSD_OVERLAY_FOUND)
+  target_compile_options(bsdtestharness
+                         PRIVATE
+                           ${BSD_OVERLAY_CFLAGS})
+endif()
+target_link_libraries(bsdtestharness
+                      PRIVATE
+                        bsdtests
+                        dispatch)
+if(BSD_OVERLAY_FOUND)
+  target_link_libraries(bsdtestharness
+                        PRIVATE
+                          ${BSD_OVERLAY_LDFLAGS})
+endif()
+
+function(add_unit_test name)
+  set(options DISABLED_TEST)
+  set(single_value_args)
+  set(multiple_value_args SOURCES)
+  cmake_parse_arguments(AUT "${options}" "${single_value_args}" "${multiple_value_args}" ${ARGN})
+
+  if(AUT_DISABLED_TEST)
+    return()
+  endif()
+
+  add_executable(${name} ${AUT_SOURCES})
+  target_include_directories(${name}
+                             PRIVATE
+                               ${CMAKE_CURRENT_BINARY_DIR}
+                               ${CMAKE_CURRENT_SOURCE_DIR}
+                               ${CMAKE_SOURCE_DIR})
+  if(WITH_BLOCKS_RUNTIME)
+    target_include_directories(${name}
+                               SYSTEM BEFORE PRIVATE
+                                 "${WITH_BLOCKS_RUNTIME}")
+  endif()
+  if(WITH_PTHREAD_WORKQUEUES)
+    target_include_directories(${name}
+                               SYSTEM BEFORE PRIVATE
+                                 "${WITH_PTHREAD_WORKQUEUES}/include")
+  endif()
+  if(BSD_OVERLAY_FOUND)
+    target_compile_options(${name}
+                           PRIVATE
+                             ${BSD_OVERLAY_CFLAGS})
+  endif()
+  target_compile_options(${name} PRIVATE -fblocks)
+  # TODO(compnerd) make this portable
+  target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
+  target_link_libraries(${name} PRIVATE dispatch Threads::Threads)
+  if(WITH_PTHREAD_WORKQUEUES)
+    target_link_libraries(${name} PRIVATE PTHREAD::workqueue)
+  endif()
+  if(WITH_BLOCKS_RUNTIME)
+    target_link_libraries(${name} PRIVATE BlocksRuntime)
+  endif()
+  if(BSD_OVERLAY_FOUND)
+    target_link_libraries(${name}
+                          PRIVATE
+                            ${BSD_OVERLAY_LDFLAGS})
+  endif()
+  target_link_libraries(${name} PRIVATE bsdtests)
+  add_test(NAME ${name}
+           COMMAND bsdtestharness $<TARGET_FILE:${name}>)
+  set_tests_properties(${name}
+                       PROPERTIES
+                         TIMEOUT 30
+                         DEPENDS bsdtestharness
+                         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+  if(NOT leaks_EXECUTABLE)
+    set_tests_properties(${name}
+                         PROPERTIES
+                           ENVIRONMENT NOLEAKS=1)
+  endif()
+endfunction()
+
+set(DISPATCH_C_TESTS
+    apply
+    api
+    c99
+    debug
+    queue_finalizer
+    group
+    overcommit
+    context_for_key
+    after
+    timer
+    timer_short
+    timer_timeout
+    sema
+    timer_bit31
+    timer_bit63
+    timer_set_time
+    starfish
+    data
+    io_net
+    select)
+set(DISPATCH_CPP_TESTS
+    plusplus)
+
+foreach(test ${DISPATCH_C_TESTS})
+  add_unit_test(dispatch_${test}
+                SOURCES
+                  dispatch_${test}.c)
+endforeach()
+foreach(test ${DISPATCH_CPP_TESTS})
+  add_unit_test(dispatch_${test}
+                SOURCES
+                  dispatch_${test}.cpp)
+endforeach()
+target_link_libraries(dispatch_group PRIVATE m)
+target_link_libraries(dispatch_timer_short PRIVATE m)
+
diff --git a/tests/dispatch_cascade.c b/tests/dispatch_cascade.c
index 78561dd..ad5a359 100644
--- a/tests/dispatch_cascade.c
+++ b/tests/dispatch_cascade.c
@@ -79,7 +79,7 @@
 		}
 	}
 
-	printf("maxcount = %ld\n", maxcount);
+	printf("maxcount = %zd\n", maxcount);
 
 	size_t x,y;
 	for (y = 20; y > 0; --y) {
diff --git a/tests/dispatch_io_net.c b/tests/dispatch_io_net.c
index bbffabc..e35c744 100644
--- a/tests/dispatch_io_net.c
+++ b/tests/dispatch_io_net.c
@@ -277,7 +277,7 @@
 				// convenience method handlers should only be called once
 				if (remaining) {
 					fprintf(stderr, "Server-dispatch_write() incomplete .. "
-							"%lu bytes\n", dispatch_data_get_size(remaining));
+							"%zu bytes\n", dispatch_data_get_size(remaining));
 					close(read_fd);
 					close(clientfd);
 					close(sockfd);
diff --git a/tests/dispatch_starfish.c b/tests/dispatch_starfish.c
index 0fdbe89..e5d3fab 100644
--- a/tests/dispatch_starfish.c
+++ b/tests/dispatch_starfish.c
@@ -68,7 +68,7 @@
 	math = delta;
 	math /= COUNT * COUNT * 2ul + COUNT * 2ul;
 
-	printf("lap: %ld\n", lap_count_down);
+	printf("lap: %zd\n", lap_count_down);
 	printf("count: %lu\n", COUNT);
 	printf("delta: %lu ns\n", delta);
 	printf("math: %Lf ns / lap\n", math);
@@ -144,7 +144,7 @@
 	start = mach_absolute_time();
 
 	for (i = 0; i < COUNT; i++) {
-		snprintf(buf, sizeof(buf), "com.example.starfish-node#%ld", i);
+		snprintf(buf, sizeof(buf), "com.example.starfish-node#%zd", i);
 		queues[i] = dispatch_queue_create(buf, NULL);
 		dispatch_suspend(queues[i]);
 		dispatch_set_target_queue(queues[i], soup);