merge darwin/libdispatch-913.1.4

Signed-off-by: Daniel A. Steffen <das@apple.com>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa26514
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+# Mac OS X filesystem metadata
+.DS_Store
+
+# Xcode user artifacts
+xcuserdata
+project.xcworkspace
+
+# python generated files
+*.pyc
+
+# build files generated by the configure script
+*.ninja
+.ninja_deps
+.ninja_log
+
+Build
+.build
+
+# build files generated by autotools
+Makefile
+Makefile.in
+config.log
+configure
+aclocal.m4
+autom4te.cache
+config.log
+config.status
+config
+configure
+libtool
+.dirstamp
+/dispatch/module.modulemap
+/private/module.modulemap
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f6b078e..1f34e51 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,6 +26,9 @@
 
 include(DispatchAppleOptions)
 
+include(DispatchCompilerWarnings)
+dispatch_common_warnings()
+
 option(ENABLE_DISPATCH_INIT_CONSTRUCTOR "enable libdispatch_init as a constructor" ON)
 set(USE_LIBDISPATCH_INIT_CONSTRUCTOR ${ENABLE_DISPATCH_INIT_CONSTRUCTOR})
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..e36bf96
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,10 @@
+By submitting a pull request, you represent that you have the right to license
+your contribution to Apple and the community, and agree by submitting the patch
+that your contributions are licensed under the [Swift
+license](https://swift.org/LICENSE.txt).
+
+---
+
+Before submitting the pull request, please make sure you have tested your
+changes and that they follow the Swift project [guidelines for contributing
+code](https://swift.org/contributing/#contributing-code).
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ef9ec78
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# Grand Central Dispatch
+
+Grand Central Dispatch (GCD or libdispatch) provides comprehensive support for concurrent code execution on multicore hardware.
+
+libdispatch is currently available on all Darwin platforms. This project aims to make a modern version of libdispatch available on all other Swift platforms. To do this, we will implement as much of the portable subset of the API as possible, using the existing open source C implementation.
+
+libdispatch on Darwin is a combination of logic in the `xnu` kernel alongside the user-space Library. The kernel has the most information available to balance workload across the entire system. As a first step, however, we believe it is useful to bring up the basic functionality of the library using user-space pthread primitives on Linux.  Eventually, a Linux kernel module could be developed to support more informed thread scheduling.
+
+## Project Status
+
+A port of libdispatch to Linux has been completed. On Linux, since Swift 3, swift-corelibs-libdispatch has been included in all Swift releases and is used by other swift-corelibs projects.
+
+Opportunities to contribute and on-going work include:
+
+1. Develop a test suite for the Swift APIs of libdispatch.
+2. Enhance libdispatch as needed to support Swift language evolution and the needs of the other Core Libraries projects.
+
+## Build and Install
+
+For detailed instructions on building and installing libdispatch, see [INSTALL.md](INSTALL.md)
+
+## Testing
+
+For detailed instructions on testing libdispatch, see [TESTING.md](TESTING.md)
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 0000000..b4d902a
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,27 @@
+## Testing libdispatch
+
+### Running tests
+
+A C-based test suite can be found in the tests subdirectory.
+It uses the automake testing harness to execute the tests.
+
+A default set of tests that are always expected to pass can
+be executed by doing
+
+   ```
+   make check
+   ```
+
+An extended test suite that includes some tests that may fail
+occasionally can be enabled at configure time:
+
+   ```
+   ./configure --enable-extended-test-suite
+   make check
+   ```
+
+### Additional prerequisites
+
+A few test cases require additional packages to be installed.
+In particular, several IO tests assume /usr/bin/vi is available
+as an input file and will fail if it is not present.
diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake
new file mode 100644
index 0000000..2ae27cd
--- /dev/null
+++ b/cmake/modules/DispatchCompilerWarnings.cmake
@@ -0,0 +1,90 @@
+
+if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")
+  # TODO: someone needs to provide the msvc equivalent warning flags
+  macro(dispatch_common_warnings)
+  endmacro()
+else()
+  macro(dispatch_common_warnings)
+	add_compile_options(-Werror)
+	add_compile_options(-Wall)
+	add_compile_options(-Wextra)
+	add_compile_options(-Wno-unknown-warning-option)
+	add_compile_options(-Wno-trigraphs)
+	add_compile_options(-Wmissing-field-initializers)
+	add_compile_options(-Wmissing-prototypes)
+	add_compile_options(-Wdocumentation)
+	add_compile_options(-Wunreachable-code)
+	add_compile_options(-Wmissing-braces)
+	add_compile_options(-Wparentheses)
+	add_compile_options(-Wswitch)
+	add_compile_options(-Wunused-function)
+	add_compile_options(-Wunused-label)
+	add_compile_options(-Wunused-parameter)
+	add_compile_options(-Wunused-variable)
+	add_compile_options(-Wunused-value)
+	add_compile_options(-Wempty-body)
+	add_compile_options(-Wuninitialized)
+	add_compile_options(-Wunknown-pragmas)
+	add_compile_options(-Wshadow)
+	add_compile_options(-Wno-four-char-constants)
+	add_compile_options(-Wconversion)
+	add_compile_options(-Wconstant-conversion)
+	add_compile_options(-Wint-conversion)
+	add_compile_options(-Wbool-conversion)
+	add_compile_options(-Wenum-conversion)
+	add_compile_options(-Wassign-enum)
+	add_compile_options(-Wsign-compare)
+	add_compile_options(-Wshorten-64-to-32)
+	add_compile_options(-Wpointer-sign)
+	add_compile_options(-Wnewline-eof)
+	add_compile_options(-Wdeprecated-declarations)
+	add_compile_options(-Wsign-conversion)
+	add_compile_options(-Winfinite-recursion)
+	add_compile_options(-Warray-bounds-pointer-arithmetic)
+	add_compile_options(-Watomic-properties)
+	add_compile_options(-Wcomma)
+	add_compile_options(-Wconditional-uninitialized)
+	add_compile_options(-Wcovered-switch-default)
+	add_compile_options(-Wdate-time)
+	add_compile_options(-Wdeprecated)
+	add_compile_options(-Wdouble-promotion)
+	add_compile_options(-Wduplicate-enum)
+	add_compile_options(-Wexpansion-to-defined)
+	add_compile_options(-Wfloat-equal)
+	add_compile_options(-Widiomatic-parentheses)
+	add_compile_options(-Wignored-qualifiers)
+	add_compile_options(-Wimplicit-fallthrough)
+	add_compile_options(-Wnullable-to-nonnull-conversion)
+	add_compile_options(-Wobjc-interface-ivars)
+	add_compile_options(-Wover-aligned)
+	add_compile_options(-Wpacked)
+	add_compile_options(-Wpointer-arith)
+	add_compile_options(-Wselector)
+	add_compile_options(-Wstatic-in-inline)
+	add_compile_options(-Wsuper-class-method-mismatch)
+	add_compile_options(-Wswitch-enum)
+	add_compile_options(-Wtautological-compare)
+	add_compile_options(-Wunguarded-availability)
+	add_compile_options(-Wunused)
+	add_compile_options(-Wno-disabled-macro-expansion)
+	add_compile_options(-Wno-pedantic)
+	add_compile_options(-Wno-bad-function-cast)
+	add_compile_options(-Wno-c++-compat)
+	add_compile_options(-Wno-c++98-compat)
+	add_compile_options(-Wno-c++98-compat-pedantic)
+	add_compile_options(-Wno-cast-align)
+	add_compile_options(-Wno-cast-qual)
+	add_compile_options(-Wno-documentation-unknown-command)
+	add_compile_options(-Wno-format-nonliteral)
+	add_compile_options(-Wno-missing-variable-declarations)
+	add_compile_options(-Wno-old-style-cast)
+	add_compile_options(-Wno-padded)
+	add_compile_options(-Wno-reserved-id-macro)
+	add_compile_options(-Wno-shift-sign-overflow)
+	add_compile_options(-Wno-undef)
+	add_compile_options(-Wno-unreachable-code-aggressive)
+	add_compile_options(-Wno-unused-macros)
+	add_compile_options(-Wno-used-but-marked-unused)
+	add_compile_options(-Wno-vla)
+  endmacro()
+endif()
diff --git a/libdispatch.xcodeproj/project.pbxproj b/libdispatch.xcodeproj/project.pbxproj
index e7134e7..e136647 100644
--- a/libdispatch.xcodeproj/project.pbxproj
+++ b/libdispatch.xcodeproj/project.pbxproj
@@ -810,6 +810,52 @@
 		E4EC122D12514715000DDBD1 /* libdispatch_mp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdispatch_mp.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		E4ECBAA415253C25002C313C /* mach_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_private.h; sourceTree = "<group>"; };
 		E4FC3263145F46C9002FBDDB /* object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = object.m; sourceTree = "<group>"; };
+		EA53C60E1BFEA851000A02EA /* bsdtestharness.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bsdtestharness.c; path = tests/bsdtestharness.c; sourceTree = "<group>"; };
+		EA53C60F1BFEA851000A02EA /* bsdtests.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bsdtests.c; path = tests/bsdtests.c; sourceTree = "<group>"; };
+		EA53C6101BFEA851000A02EA /* bsdtests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bsdtests.h; path = tests/bsdtests.h; sourceTree = "<group>"; };
+		EA53C6111BFEA851000A02EA /* bsdtestsummarize.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bsdtestsummarize.c; path = tests/bsdtestsummarize.c; sourceTree = "<group>"; };
+		EA53C6121BFEA851000A02EA /* cffd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cffd.c; path = tests/cffd.c; sourceTree = "<group>"; };
+		EA53C6131BFEA851000A02EA /* dispatch_after.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_after.c; path = tests/dispatch_after.c; sourceTree = "<group>"; };
+		EA53C6141BFEA851000A02EA /* dispatch_api.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_api.c; path = tests/dispatch_api.c; sourceTree = "<group>"; };
+		EA53C6151BFEA851000A02EA /* dispatch_apply.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_apply.c; path = tests/dispatch_apply.c; sourceTree = "<group>"; };
+		EA53C6161BFEA851000A02EA /* dispatch_c99.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_c99.c; path = tests/dispatch_c99.c; sourceTree = "<group>"; };
+		EA53C6171BFEA851000A02EA /* dispatch_cascade.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_cascade.c; path = tests/dispatch_cascade.c; sourceTree = "<group>"; };
+		EA53C6181BFEA851000A02EA /* dispatch_cf_main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_cf_main.c; path = tests/dispatch_cf_main.c; sourceTree = "<group>"; };
+		EA53C6191BFEA851000A02EA /* dispatch_concur.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_concur.c; path = tests/dispatch_concur.c; sourceTree = "<group>"; };
+		EA53C61A1BFEA851000A02EA /* dispatch_context_for_key.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_context_for_key.c; path = tests/dispatch_context_for_key.c; sourceTree = "<group>"; };
+		EA53C61B1BFEA851000A02EA /* dispatch_data.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_data.c; path = tests/dispatch_data.c; sourceTree = "<group>"; };
+		EA53C61C1BFEA851000A02EA /* dispatch_deadname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_deadname.c; path = tests/dispatch_deadname.c; sourceTree = "<group>"; };
+		EA53C61D1BFEA851000A02EA /* dispatch_debug.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_debug.c; path = tests/dispatch_debug.c; sourceTree = "<group>"; };
+		EA53C61E1BFEA851000A02EA /* dispatch_drift.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_drift.c; path = tests/dispatch_drift.c; sourceTree = "<group>"; };
+		EA53C61F1BFEA851000A02EA /* dispatch_group.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_group.c; path = tests/dispatch_group.c; sourceTree = "<group>"; };
+		EA53C6201BFEA851000A02EA /* dispatch_io_net.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_io_net.c; path = tests/dispatch_io_net.c; sourceTree = "<group>"; };
+		EA53C6211BFEA851000A02EA /* dispatch_io.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_io.c; path = tests/dispatch_io.c; sourceTree = "<group>"; };
+		EA53C6221BFEA851000A02EA /* dispatch_overcommit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_overcommit.c; path = tests/dispatch_overcommit.c; sourceTree = "<group>"; };
+		EA53C6231BFEA851000A02EA /* dispatch_pingpong.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_pingpong.c; path = tests/dispatch_pingpong.c; sourceTree = "<group>"; };
+		EA53C6241BFEA851000A02EA /* dispatch_plusplus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dispatch_plusplus.cpp; path = tests/dispatch_plusplus.cpp; sourceTree = "<group>"; };
+		EA53C6251BFEA851000A02EA /* dispatch_priority.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_priority.c; path = tests/dispatch_priority.c; sourceTree = "<group>"; };
+		EA53C6261BFEA851000A02EA /* dispatch_proc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_proc.c; path = tests/dispatch_proc.c; sourceTree = "<group>"; };
+		EA53C6271BFEA851000A02EA /* dispatch_queue_finalizer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_queue_finalizer.c; path = tests/dispatch_queue_finalizer.c; sourceTree = "<group>"; };
+		EA53C6281BFEA851000A02EA /* dispatch_read.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_read.c; path = tests/dispatch_read.c; sourceTree = "<group>"; };
+		EA53C6291BFEA851000A02EA /* dispatch_read2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_read2.c; path = tests/dispatch_read2.c; sourceTree = "<group>"; };
+		EA53C62A1BFEA851000A02EA /* dispatch_readsync.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_readsync.c; path = tests/dispatch_readsync.c; sourceTree = "<group>"; };
+		EA53C62B1BFEA851000A02EA /* dispatch_select.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_select.c; path = tests/dispatch_select.c; sourceTree = "<group>"; };
+		EA53C62C1BFEA851000A02EA /* dispatch_sema.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_sema.c; path = tests/dispatch_sema.c; sourceTree = "<group>"; };
+		EA53C62D1BFEA851000A02EA /* dispatch_starfish.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_starfish.c; path = tests/dispatch_starfish.c; sourceTree = "<group>"; };
+		EA53C62E1BFEA851000A02EA /* dispatch_suspend_timer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_suspend_timer.c; path = tests/dispatch_suspend_timer.c; sourceTree = "<group>"; };
+		EA53C62F1BFEA851000A02EA /* dispatch_sync_on_main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_sync_on_main.c; path = tests/dispatch_sync_on_main.c; sourceTree = "<group>"; };
+		EA53C6301BFEA851000A02EA /* dispatch_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_test.c; path = tests/dispatch_test.c; sourceTree = "<group>"; };
+		EA53C6311BFEA851000A02EA /* dispatch_test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dispatch_test.h; path = tests/dispatch_test.h; sourceTree = "<group>"; };
+		EA53C6321BFEA851000A02EA /* dispatch_timer_bit31.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer_bit31.c; path = tests/dispatch_timer_bit31.c; sourceTree = "<group>"; };
+		EA53C6331BFEA851000A02EA /* dispatch_timer_bit63.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer_bit63.c; path = tests/dispatch_timer_bit63.c; sourceTree = "<group>"; };
+		EA53C6341BFEA851000A02EA /* dispatch_timer_set_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer_set_time.c; path = tests/dispatch_timer_set_time.c; sourceTree = "<group>"; };
+		EA53C6351BFEA851000A02EA /* dispatch_timer_short.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer_short.c; path = tests/dispatch_timer_short.c; sourceTree = "<group>"; };
+		EA53C6361BFEA851000A02EA /* dispatch_timer_timeout.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer_timeout.c; path = tests/dispatch_timer_timeout.c; sourceTree = "<group>"; };
+		EA53C6371BFEA851000A02EA /* dispatch_timer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_timer.c; path = tests/dispatch_timer.c; sourceTree = "<group>"; };
+		EA53C6381BFEA851000A02EA /* dispatch_transform.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_transform.c; path = tests/dispatch_transform.c; sourceTree = "<group>"; };
+		EA53C6391BFEA851000A02EA /* dispatch_vm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_vm.c; path = tests/dispatch_vm.c; sourceTree = "<group>"; };
+		EA53C63A1BFEA851000A02EA /* dispatch_vnode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dispatch_vnode.c; path = tests/dispatch_vnode.c; sourceTree = "<group>"; };
+		EA53C63B1BFEA851000A02EA /* func.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = func.c; path = tests/func.c; sourceTree = "<group>"; };
 		FC0B34780FA2851C0080FFA0 /* source_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = source_internal.h; sourceTree = "<group>"; };
 		FC1832A2109923C7003403D5 /* perfmon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = perfmon.h; sourceTree = "<group>"; };
 		FC1832A3109923C7003403D5 /* time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time.h; sourceTree = "<group>"; };
@@ -863,6 +909,7 @@
 				92F3FEC91BEC687200025962 /* Darwin Tests */,
 				C6A0FF2B0290797F04C91782 /* Documentation */,
 				1AB674ADFE9D54B511CA2CBB /* Products */,
+				EA53C60D1BFE9605000A02EA /* Tests */,
 				C927F35F10FD7F1000C5AB8B /* ddt.xcodeproj */,
 				4552536E19B1384900B88766 /* libdispatchtest.xcodeproj */,
 			);
@@ -1165,6 +1212,59 @@
 			path = os;
 			sourceTree = "<group>";
 		};
+		EA53C60D1BFE9605000A02EA /* Tests */ = {
+			isa = PBXGroup;
+			children = (
+				EA53C60E1BFEA851000A02EA /* bsdtestharness.c */,
+				EA53C60F1BFEA851000A02EA /* bsdtests.c */,
+				EA53C6101BFEA851000A02EA /* bsdtests.h */,
+				EA53C6111BFEA851000A02EA /* bsdtestsummarize.c */,
+				EA53C6121BFEA851000A02EA /* cffd.c */,
+				EA53C6131BFEA851000A02EA /* dispatch_after.c */,
+				EA53C6141BFEA851000A02EA /* dispatch_api.c */,
+				EA53C6151BFEA851000A02EA /* dispatch_apply.c */,
+				EA53C6161BFEA851000A02EA /* dispatch_c99.c */,
+				EA53C6171BFEA851000A02EA /* dispatch_cascade.c */,
+				EA53C6181BFEA851000A02EA /* dispatch_cf_main.c */,
+				EA53C6191BFEA851000A02EA /* dispatch_concur.c */,
+				EA53C61A1BFEA851000A02EA /* dispatch_context_for_key.c */,
+				EA53C61B1BFEA851000A02EA /* dispatch_data.c */,
+				EA53C61C1BFEA851000A02EA /* dispatch_deadname.c */,
+				EA53C61D1BFEA851000A02EA /* dispatch_debug.c */,
+				EA53C61E1BFEA851000A02EA /* dispatch_drift.c */,
+				EA53C61F1BFEA851000A02EA /* dispatch_group.c */,
+				EA53C6201BFEA851000A02EA /* dispatch_io_net.c */,
+				EA53C6211BFEA851000A02EA /* dispatch_io.c */,
+				EA53C6221BFEA851000A02EA /* dispatch_overcommit.c */,
+				EA53C6231BFEA851000A02EA /* dispatch_pingpong.c */,
+				EA53C6241BFEA851000A02EA /* dispatch_plusplus.cpp */,
+				EA53C6251BFEA851000A02EA /* dispatch_priority.c */,
+				EA53C6261BFEA851000A02EA /* dispatch_proc.c */,
+				EA53C6271BFEA851000A02EA /* dispatch_queue_finalizer.c */,
+				EA53C6281BFEA851000A02EA /* dispatch_read.c */,
+				EA53C6291BFEA851000A02EA /* dispatch_read2.c */,
+				EA53C62A1BFEA851000A02EA /* dispatch_readsync.c */,
+				EA53C62B1BFEA851000A02EA /* dispatch_select.c */,
+				EA53C62C1BFEA851000A02EA /* dispatch_sema.c */,
+				EA53C62D1BFEA851000A02EA /* dispatch_starfish.c */,
+				EA53C62E1BFEA851000A02EA /* dispatch_suspend_timer.c */,
+				EA53C62F1BFEA851000A02EA /* dispatch_sync_on_main.c */,
+				EA53C6301BFEA851000A02EA /* dispatch_test.c */,
+				EA53C6311BFEA851000A02EA /* dispatch_test.h */,
+				EA53C6321BFEA851000A02EA /* dispatch_timer_bit31.c */,
+				EA53C6331BFEA851000A02EA /* dispatch_timer_bit63.c */,
+				EA53C6341BFEA851000A02EA /* dispatch_timer_set_time.c */,
+				EA53C6351BFEA851000A02EA /* dispatch_timer_short.c */,
+				EA53C6361BFEA851000A02EA /* dispatch_timer_timeout.c */,
+				EA53C6371BFEA851000A02EA /* dispatch_timer.c */,
+				EA53C6381BFEA851000A02EA /* dispatch_transform.c */,
+				EA53C6391BFEA851000A02EA /* dispatch_vm.c */,
+				EA53C63A1BFEA851000A02EA /* dispatch_vnode.c */,
+				EA53C63B1BFEA851000A02EA /* func.c */,
+			);
+			name = Tests;
+			sourceTree = "<group>";
+		};
 		FC1832A0109923B3003403D5 /* shims */ = {
 			isa = PBXGroup;
 			children = (
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..38066dd
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,5 @@
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
diff --git a/private/queue_private.h b/private/queue_private.h
index 2b50eb8..b9356e2 100644
--- a/private/queue_private.h
+++ b/private/queue_private.h
@@ -323,7 +323,6 @@
 dispatch_async_enforce_qos_class_f(dispatch_queue_t queue,
 	void *_Nullable context, dispatch_function_t work);
 
-
 #ifdef __ANDROID__
 /*!
  * @function _dispatch_install_thread_detach_callback
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..194c2cb
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,9 @@
+provider.h
+module.map
+module.build.map
+.libs
+*.lo
+*.la
+*.o
+*.swiftmodule
+*.swiftdoc
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..6713a96
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,44 @@
+*.o
+*.lo
+*.la
+*.log
+*.trs
+.libs
+bsdtestharness
+bsdtestsummarize
+dispatch
+dispatch_after
+dispatch_api
+dispatch_apply
+dispatch_c99
+dispatch_cascade
+dispatch_concur
+dispatch_context_for_key
+dispatch_data
+dispatch_debug
+dispatch_drift
+dispatch_group
+dispatch_io
+dispatch_io_net
+dispatch_overcommit
+dispatch_pingpong
+dispatch_plusplus
+dispatch_priority
+dispatch_priority2
+dispatch_queue_finalizer
+dispatch_read
+dispatch_read2
+dispatch_readsync
+dispatch_select
+dispatch_sema
+dispatch_starfish
+dispatch_suspend_timer
+dispatch_timer
+dispatch_timer_bit31
+dispatch_timer_bit63
+dispatch_timer_set_time
+dispatch_timer_short
+dispatch_timer_timeout
+dispatch_vnode
+leaks-wrapper
+
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..0f8628f
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,190 @@
+
+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")
+
+# TODO(compnerd) hoist this out of the test directory
+if(SWIFT_RUNTIME_LIBDIR)
+  add_library(swiftCore SHARED IMPORTED)
+  set_target_properties(swiftCore
+                        PROPERTIES
+                          IMPORTED_LOCATION ${SWIFT_RUNTIME_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}swiftCore${CMAKE_SHARED_LIBRARY_SUFFIX})
+
+  add_library(swiftSwiftOnoneSupport SHARED IMPORTED)
+  set_target_properties(swiftSwiftOnoneSupport
+                        PROPERTIES
+                          IMPORTED_LOCATION ${SWIFT_RUNTIME_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}swiftSwiftOnoneSupport${CMAKE_SHARED_LIBRARY_SUFFIX})
+endif()
+
+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()
+if(ENABLE_SWIFT)
+  target_link_libraries(bsdtestharness
+                        PRIVATE
+                          swiftCore
+                          swiftSwiftOnoneSupport)
+endif()
+
+function(add_unit_test name)
+  set(options DISABLED_TEST;NO_BSD_OVERLAY)
+  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(CMAKE_SWIFT_COMPILER)
+	# For testing in swift.org CI system; make deadlines lenient by default
+	# to reduce probability of test failures due to machine load.
+	target_compile_options(${name} PRIVATE -DLENIENT_DEADLINES=1)
+  endif()
+  if(WITH_BLOCKS_RUNTIME)
+    target_include_directories(${name}
+                               SYSTEM BEFORE PRIVATE
+                                 "${WITH_BLOCKS_RUNTIME}")
+  endif()
+  if(BSD_OVERLAY_FOUND AND NOT AUT_NO_BSD_OVERLAY)
+    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_BLOCKS_RUNTIME)
+    target_link_libraries(${name} PRIVATE BlocksRuntime)
+  endif()
+  if(BSD_OVERLAY_FOUND AND NOT AUT_NO_BSD_OVERLAY)
+    target_link_libraries(${name}
+                          PRIVATE
+                            ${BSD_OVERLAY_LDFLAGS})
+  endif()
+  if(ENABLE_SWIFT)
+    target_link_libraries(${name}
+                          PRIVATE
+                            swiftCore
+                            swiftSwiftOnoneSupport)
+  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()
+
+# Tests that reliably pass on all platforms
+set(DISPATCH_C_TESTS
+    apply
+    api
+    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)
+
+# Tests that usually pass, but occasionally fail.
+# Excluded by default for purposes of Swift CI
+if(EXTENDED_TEST_SUITE)
+  list(APPEND DISPATCH_C_TESTS
+	priority
+	concur
+	read
+	read2
+	suspend_timer
+	pingpong
+	drift
+	readsync
+	cascade
+	io)
+  # an oddball; dispatch_priority.c compiled with -DUSE_SET_TARGET_QUEUE=1
+  add_unit_test(dispatch_priority2 SOURCES dispatch_priority.c)
+  target_compile_options(dispatch_priority2 PRIVATE -DUSE_SET_TARGET_QUEUE=1)
+endif()
+
+# add C tests for platform-specific functionality when applicable
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+  list(APPEND DISPATCH_C_TESTS
+	deadname
+	proc
+	vm
+	vnode)
+endif()
+
+foreach(test ${DISPATCH_C_TESTS})
+  add_unit_test(dispatch_${test}
+                SOURCES
+                  dispatch_${test}.c)
+endforeach()
+
+# test dispatch API for various C/CXX language variants
+add_unit_test(dispatch_c99 NO_BSD_OVERLAY SOURCES dispatch_c99.c)
+add_unit_test(dispatch_plusplus SOURCES dispatch_plusplus.cpp)
+
+# test-specific link options
+target_link_libraries(dispatch_group PRIVATE m)
+target_link_libraries(dispatch_timer_short PRIVATE m)
+
+# test-specific compile options
+target_compile_options(dispatch_c99 PRIVATE -std=c99)
diff --git a/tests/Foundation/bench.mm b/tests/Foundation/bench.mm
new file mode 100644
index 0000000..c516366
--- /dev/null
+++ b/tests/Foundation/bench.mm
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2008-2011 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 <Foundation/Foundation.h>
+#include <libkern/OSAtomic.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <math.h>
+#ifdef __BLOCKS__
+#include <Block.h>
+#endif
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+
+//#define BENCH_SLOW 1
+
+extern "C" {
+__private_extern__ void func(void);
+#ifdef __BLOCKS__
+__private_extern__ void (^block)(void);
+#endif
+static void backflip(void *ctxt);
+static void backflip_done(void);
+}
+
+@interface BasicObject : NSObject
+{
+}
+- (void) method;
+@end
+
+@implementation BasicObject
+- (void) method
+{
+}
+@end
+
+class BasicClass {
+public:
+	virtual void virtfunc(void) {
+	};
+};
+
+static void *
+force_a_thread(void *arg)
+{
+	pause();
+	abort();
+	return arg;
+}
+
+static volatile int32_t global;
+static volatile int64_t w_global;
+
+#if TARGET_OS_EMBEDDED
+static const size_t cnt = 5000000;
+#else
+static const size_t cnt = 200000000;
+#endif
+static const size_t cnt2 = cnt/100;
+
+static uint64_t bfs;
+static long double loop_cost;
+static long double cycles_per_nanosecond;
+static mach_timebase_info_data_t tbi;
+
+static void __attribute__((noinline))
+print_result(uint64_t s, const char *str)
+{
+	uint64_t d, e = mach_absolute_time();
+	long double dd;
+
+	d = e - s;
+
+	if (tbi.numer != tbi.denom) {
+		d *= tbi.numer;
+		d /= tbi.denom;
+	}
+
+	dd = (typeof(dd))d / (typeof(dd))cnt;
+
+	dd -= loop_cost;
+
+	if (loop_cost == 0.0) {
+		loop_cost = dd;
+	}
+
+	dd *= cycles_per_nanosecond;
+	dd = roundl(dd * 200.0)/200.0;
+
+	printf("%-45s%15.3Lf cycles\n", str, dd);
+}
+
+#if BENCH_SLOW || !TARGET_OS_EMBEDDED
+static void __attribute__((noinline))
+print_result2(uint64_t s, const char *str)
+{
+	uint64_t d, e = mach_absolute_time();
+	long double dd;
+
+	d = e - s;
+
+	if (tbi.numer != tbi.denom) {
+		d *= tbi.numer;
+		d /= tbi.denom;
+	}
+
+	dd = (typeof(dd))d / (typeof(dd))cnt2;
+
+	dd -= loop_cost;
+	dd *= cycles_per_nanosecond;
+
+	printf("%-45s%15.3Lf cycles\n", str, dd);
+}
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+static inline uint64_t
+rdtsc(void)
+{
+	uint32_t lo, hi;
+
+	asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+
+	return (uint64_t)hi << 32 | lo;
+}
+#endif
+
+static struct fml {
+	struct fml *fml_next;
+} *fixed_malloc_lifo_head;
+
+struct fml *fixed_malloc_lifo(void);// __attribute__((noinline));
+void fixed_free_lifo(struct fml *fml);// __attribute__((noinline));
+
+struct fml *
+fixed_malloc_lifo(void)
+{
+	struct fml *fml_r = fixed_malloc_lifo_head;
+
+	if (fml_r) {
+		fixed_malloc_lifo_head = fml_r->fml_next;
+		return fml_r;
+	} else {
+		return (struct fml *)malloc(32);
+	}
+}
+
+void
+fixed_free_lifo(struct fml *fml)
+{
+	fml->fml_next = fixed_malloc_lifo_head;
+	fixed_malloc_lifo_head = fml;
+}
+
+int
+main(void)
+{
+	pthread_mutex_t plock = PTHREAD_MUTEX_INITIALIZER;
+	OSSpinLock slock = OS_SPINLOCK_INIT;
+	BasicObject *bo;
+	BasicClass *bc;
+	pthread_t pthr_pause;
+	dispatch_queue_t q, mq;
+	kern_return_t kr;
+#if BENCH_SLOW
+	semaphore_t sem;
+#endif
+	uint64_t freq;
+	uint64_t s;
+	size_t freq_len = sizeof(freq);
+	size_t bf_cnt = cnt;
+	unsigned i;
+	int r;
+
+	printf("\n====================================================================\n");
+	printf("[TEST] dispatch benchmark\n");
+	printf("[PID] %d\n", getpid());
+	printf("====================================================================\n\n");
+
+	r = sysctlbyname("hw.cpufrequency", &freq, &freq_len, NULL, 0);
+	assert(r != -1);
+	assert(freq_len == sizeof(freq));
+
+	cycles_per_nanosecond = (long double)freq / (long double)NSEC_PER_SEC;
+
+#if BENCH_SLOW
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+	assert(pool);
+#endif
+
+	/* Malloc has different logic for threaded apps. */
+	r = pthread_create(&pthr_pause, NULL, force_a_thread, NULL);
+	assert(r == 0);
+
+	kr = mach_timebase_info(&tbi);
+	assert(kr == 0);
+#if defined(__i386__) || defined(__x86_64__)
+	assert(tbi.numer == tbi.denom); /* This will fail on PowerPC. */
+#endif
+
+	bo = [[BasicObject alloc] init];
+	assert(bo);
+
+	bc = new BasicClass();
+	assert(bc);
+
+	q = dispatch_queue_create("com.apple.bench-dispatch", NULL);
+	assert(q);
+
+	mq = dispatch_get_main_queue();
+	assert(mq);
+
+	printf("%-45s%15Lf\n\n", "Cycles per nanosecond:", cycles_per_nanosecond);
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm volatile("");
+	}
+	print_result(s, "Empty loop:");
+
+	printf("\nLoop cost subtracted from the following:\n\n");
+
+#if TARGET_OS_EMBEDDED
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		mach_absolute_time();
+	}
+	print_result(s, "mach_absolute_time():");
+#else
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		mach_absolute_time();
+	}
+	print_result2(s, "mach_absolute_time():");
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		rdtsc();
+	}
+	print_result(s, "rdtsc():");
+#endif
+
+#if BENCH_SLOW
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		pthread_t pthr;
+		void *pr;
+
+		r = pthread_create(&pthr, NULL, (void *(*)(void *))func, NULL);
+		assert(r == 0);
+		r = pthread_join(pthr, &pr);
+		assert(r == 0);
+	}
+	print_result2(s, "pthread create+join:");
+
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		kr = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0);
+		assert(kr == 0);
+		kr = semaphore_destroy(mach_task_self(), sem);
+		assert(kr == 0);
+	}
+	print_result2(s, "Mach semaphore create/destroy:");
+
+	kr = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0);
+	assert(kr == 0);
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		kr = semaphore_signal(sem);
+		assert(kr == 0);
+	}
+	print_result2(s, "Mach semaphore signal:");
+	kr = semaphore_destroy(mach_task_self(), sem);
+	assert(kr == 0);
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		free(malloc(32));
+	}
+	print_result(s, "free(malloc(32)):");
+
+	s = mach_absolute_time();
+	for (i = cnt / 2; i; i--) {
+		void *m1 = malloc(32);
+		void *m2 = malloc(32);
+		free(m1);
+		free(m2);
+	}
+	print_result(s, "Avoiding the MRU cache of free(malloc(32)):");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		fixed_free_lifo(fixed_malloc_lifo());
+	}
+	print_result(s, "per-thread/fixed free(malloc(32)):");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		assert(strtoull("18446744073709551615", NULL, 0) == ~0ull);
+	}
+	print_result(s, "strtoull(\"18446744073709551615\") == ~0ull:");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		func();
+	}
+	print_result(s, "Empty function call:");
+
+#ifdef __BLOCKS__
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		block();
+	}
+	print_result(s, "Empty block call:");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		bc->virtfunc();
+	}
+	print_result(s, "Empty C++ virtual call:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		[bo method];
+	}
+	print_result(s, "Empty ObjC call:");
+
+#if BENCH_SLOW
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		[bo description];
+	}
+	print_result2(s, "\"description\" ObjC call:");
+
+	[pool release];
+
+	pool = NULL;
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("nop");
+	}
+	print_result(s, "raw 'nop':");
+
+#if defined(__i386__) || defined(__x86_64__)
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("pause");
+	}
+	print_result(s, "raw 'pause':");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("mfence");
+	}
+	print_result(s, "Atomic mfence:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("lfence");
+	}
+	print_result(s, "Atomic lfence:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("sfence");
+	}
+	print_result(s, "Atomic sfence:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		uint64_t sidt_rval;
+		asm("sidt %0" : "=m" (sidt_rval));
+	}
+	print_result(s, "'sidt' instruction:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		long prev;
+		asm volatile("cmpxchg %1,%2"
+				: "=a" (prev) : "r" (0l), "m" (global), "0" (1l));
+	}
+	print_result(s, "'cmpxchg' without the 'lock' prefix:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		global = 0;
+		asm volatile("mfence" ::: "memory");
+	}
+	print_result(s, "Store + mfence:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		unsigned long _clbr;
+#ifdef __LP64__
+		asm volatile("cpuid" : "=a" (_clbr)
+				: "0" (0) : "rbx", "rcx", "rdx", "cc", "memory");
+#else
+#ifdef __llvm__
+		asm volatile("cpuid" : "=a" (_clbr) : "0" (0)
+				: "ebx", "ecx", "edx", "cc", "memory" );
+#else // gcc does not allow inline i386 asm to clobber ebx
+		asm volatile("pushl %%ebx\n\tcpuid\n\tpopl %%ebx"
+				: "=a" (_clbr) : "0" (0) : "ecx", "edx", "cc", "memory" );
+#endif
+#endif
+	}
+	print_result(s, "'cpuid' instruction:");
+
+#elif defined(__arm__)
+
+#include <arm/arch.h>
+
+#if !defined(_ARM_ARCH_7) && defined(__thumb__)
+#error "GCD requires instructions unvailable in ARMv6 Thumb1"
+#endif
+
+#ifdef _ARM_ARCH_7
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm("yield");
+	}
+	print_result(s, "raw 'yield':");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+#ifdef _ARM_ARCH_7
+		asm volatile("dmb ish" : : : "memory");
+#else
+		asm volatile("mcr	p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory");
+#endif
+	}
+	print_result(s, "'dmb ish' instruction:");
+
+#ifdef _ARM_ARCH_7
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm volatile("dmb ishst" : : : "memory");
+	}
+	print_result(s, "'dmb ishst' instruction:");
+#endif
+
+#ifdef _ARM_ARCH_7
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		asm volatile("str	%[_r], [%[_p], %[_o]]" :
+				: [_p] "p" (&global), [_o] "M" (0), [_r] "r" (0) : "memory");
+		asm volatile("dmb ishst" : : : "memory");
+	}
+	print_result(s, "'str + dmb ishst' instructions:");
+#endif
+
+#ifdef _ARM_ARCH_7
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		uintptr_t prev;
+		uint32_t t;
+		do {
+		asm volatile("ldrex	%[_r], [%[_p], %[_o]]"
+				: [_r] "=&r" (prev) \
+				: [_p] "p" (&global), [_o] "M" (0) : "memory");
+		asm volatile("strex	%[_t], %[_r], [%[_p], %[_o]]"
+				: [_t] "=&r" (t) \
+				: [_p] "p" (&global), [_o] "M" (0), [_r] "r" (0) : "memory");
+		} while (t);
+	}
+	print_result(s, "'ldrex + strex' instructions:");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+#ifdef _ARM_ARCH_7
+		asm volatile("dsb ish" : : : "memory");
+#else
+		asm volatile("mcr	p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory");
+#endif
+	}
+	print_result(s, "'dsb ish' instruction:");
+
+#if BENCH_SLOW
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		register long _swtch_pri asm("ip") = -59;
+		asm volatile("svc	0x80" : : "r" (_swtch_pri) : "r0", "memory");
+	}
+	print_result(s, "swtch_pri syscall:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		register long _r0 asm("r0") = 0, _r1 asm("r1") = 1, _r2 asm("r2") = 1;
+		register long _thread_switch asm("ip") = -61;
+		asm volatile("svc	0x80" : "+r" (_r0)
+				: "r" (_r1), "r" (_r2), "r" (_thread_switch): "memory");
+	}
+	print_result(s, "thread_switch syscall:");
+#endif
+
+#endif // __arm__
+
+#if BENCH_SLOW
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		pthread_yield_np();
+	}
+	print_result(s, "pthread_yield_np():");
+
+	s = mach_absolute_time();
+	for (i = cnt2; i; i--) {
+		usleep(0);
+	}
+	print_result2(s, "usleep(0):");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		__sync_lock_test_and_set(&global, 0);
+	}
+	print_result(s, "Atomic xchg:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		__sync_val_compare_and_swap(&global, 1, 0);
+	}
+	print_result(s, "Atomic cmpxchg:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		__sync_fetch_and_add(&global, 1);
+	}
+	print_result(s, "Atomic increment:");
+
+	{
+		global = 0;
+		volatile int32_t *g = &global;
+
+		s = mach_absolute_time();
+		for (i = cnt; i; i--) {
+			uint32_t result;
+			__sync_and_and_fetch(g, 1);
+			result = *g;
+			if (result) {
+				abort();
+			}
+		}
+		print_result(s, "Atomic and-and-fetch, reloading result:");
+	}
+
+	{
+		global = 0;
+		volatile int32_t *g = &global;
+
+		s = mach_absolute_time();
+		for (i = cnt; i; i--) {
+			uint32_t result;
+			result = __sync_and_and_fetch(g, 1);
+			if (result) {
+				abort();
+			}
+		}
+		print_result(s, "Atomic and-and-fetch, using result:");
+	}
+
+	global = 0;
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		OSAtomicIncrement32Barrier(&global);
+	}
+	print_result(s, "OSAtomicIncrement32Barrier:");
+
+	global = 0;
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		OSAtomicIncrement32(&global);
+	}
+	print_result(s, "OSAtomicIncrement32:");
+
+	w_global = 0;
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		OSAtomicIncrement64Barrier(&w_global);
+	}
+	print_result(s, "OSAtomicIncrement64Barrier:");
+
+	w_global = 0;
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		OSAtomicIncrement64(&w_global);
+	}
+	print_result(s, "OSAtomicIncrement64:");
+
+	global = 0;
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		while (!__sync_bool_compare_and_swap(&global, 0, 1)) {
+			do {
+#if defined(__i386__) || defined(__x86_64__)
+				asm("pause");
+#elif defined(__arm__) && defined _ARM_ARCH_7
+				asm("yield");
+#endif
+			} while (global);
+		}
+		global = 0;
+	}
+	print_result(s, "Inlined spin lock/unlock:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		OSSpinLockLock(&slock);
+		OSSpinLockUnlock(&slock);
+	}
+	print_result(s, "OSSpinLock/Unlock:");
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		r = pthread_mutex_lock(&plock);
+		assert(r == 0);
+		r = pthread_mutex_unlock(&plock);
+		assert(r == 0);
+	}
+	print_result(s, "pthread lock/unlock:");
+
+#ifdef __BLOCKS__
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		dispatch_sync(q, ^{ });
+	}
+	print_result(s, "dispatch_sync:");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		dispatch_sync_f(q, NULL, (void (*)(void *))func);
+	}
+	print_result(s, "dispatch_sync_f:");
+
+#ifdef __BLOCKS__
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		dispatch_barrier_sync(q, ^{ });
+	}
+	print_result(s, "dispatch_barrier_sync:");
+#endif
+
+	s = mach_absolute_time();
+	for (i = cnt; i; i--) {
+		dispatch_barrier_sync_f(q, NULL, (void (*)(void *))func);
+	}
+	print_result(s, "dispatch_barrier_sync_f:");
+
+	s = mach_absolute_time();
+	dispatch_apply_f(cnt,
+			dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+			NULL, (void (*)(void *, size_t))func);
+	s += loop_cost; // cancel out the implicit subtraction done by the next line
+	print_result(s, "dispatch_apply_f():");
+
+	// do a "double backflip" to hit the fast-path of the enqueue/dequeue logic
+	bfs = mach_absolute_time();
+	dispatch_async_f(dispatch_get_main_queue(), &bf_cnt, backflip);
+	dispatch_async_f(dispatch_get_main_queue(), &bf_cnt, backflip);
+
+	dispatch_main();
+}
+
+__attribute__((noinline))
+void
+backflip_done(void)
+{
+	print_result(bfs, "dispatch_async_f():");
+	exit(EXIT_SUCCESS);
+}
+
+void
+backflip(void *ctxt)
+{
+	size_t *bf_cnt = (size_t *)ctxt;
+	if (--(*bf_cnt)) {
+		return dispatch_async_f(dispatch_get_main_queue(), ctxt, backflip);
+	}
+	backflip_done();
+}
diff --git a/tests/Foundation/dispatch_apply_gc.m b/tests/Foundation/dispatch_apply_gc.m
new file mode 100644
index 0000000..6f0ac6a
--- /dev/null
+++ b/tests/Foundation/dispatch_apply_gc.m
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009-2011 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 <dispatch/dispatch.h>
+#import <Foundation/Foundation.h>
+#include <libkern/OSAtomic.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if __OBJC_GC__
+const size_t final = 50000, desclen = 538892;
+#else
+const size_t final = 1000, desclen = 8892;
+#endif
+NSAutoreleasePool *pool = nil;
+
+static void
+work(void* ctxt __attribute__((unused)))
+{
+	pool = [[NSAutoreleasePool alloc] init];
+	NSMutableArray *a = [NSMutableArray array];
+	OSSpinLock sl = OS_SPINLOCK_INIT, *l = &sl;
+
+	dispatch_apply(final, dispatch_get_global_queue(0, 0), ^(size_t i){
+		NSDecimalNumber *n = [NSDecimalNumber decimalNumberWithDecimal:
+				[[NSNumber numberWithInteger:i] decimalValue]];
+		OSSpinLockLock(l);
+		[a addObject:n];
+		OSSpinLockUnlock(l);
+	});
+	test_long("count", [a count], final);
+	test_long("description length", [[a description] length], desclen);
+	a = nil;
+	[pool drain];
+	test_stop_after_delay((void*)(intptr_t)1);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Apply GC"); // <rdar://problem/7455071>
+	dispatch_async_f(dispatch_get_main_queue(), (void*)(intptr_t)1, work);
+	CFRunLoopRun();
+	return 0;
+}
diff --git a/tests/Foundation/dispatch_sync_gc.m b/tests/Foundation/dispatch_sync_gc.m
new file mode 100644
index 0000000..97a9070
--- /dev/null
+++ b/tests/Foundation/dispatch_sync_gc.m
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009-2011 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 <dispatch/dispatch.h>
+#import <Foundation/Foundation.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if __OBJC_GC__
+const size_t final = 50000, desclen = 538892;
+#else
+const size_t final = 1000, desclen = 8892;
+#endif
+NSAutoreleasePool *pool = nil;
+
+static void
+work(void* ctxt __attribute__((unused)))
+{
+	pool = [[NSAutoreleasePool alloc] init];
+	NSMutableArray *a = [NSMutableArray array];
+	dispatch_group_t g = dispatch_group_create();
+
+	dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
+		NSUInteger i;
+		for (i = 0; i < final; i++) {
+			NSDecimalNumber *n = [NSDecimalNumber decimalNumberWithDecimal:
+				   [[NSNumber numberWithInteger:i] decimalValue]];
+			dispatch_sync(dispatch_get_main_queue(), ^{
+				[a addObject:n];
+			});
+		}
+	});
+	dispatch_group_notify(g, dispatch_get_main_queue(), ^{
+		test_long("count", [a count], final);
+		test_long("description length", [[a description] length], desclen);
+		[pool drain];
+		test_stop_after_delay((void*)(intptr_t)1);
+	});
+	dispatch_release(g);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Sync GC"); // <rdar://problem/7458685>
+	dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+	CFRunLoopRun();
+	return 0;
+}
diff --git a/tests/Foundation/nsoperation.m b/tests/Foundation/nsoperation.m
new file mode 100644
index 0000000..a042135
--- /dev/null
+++ b/tests/Foundation/nsoperation.m
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2008-2011 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 <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <Foundation/Foundation.h>
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+@interface MYOperation : NSOperation
+{
+}
+@end
+
+@implementation MYOperation
+
+- (id) init
+{
+	self = [super init];
+	return self;
+}
+
+- (void)main
+{
+	test_stop();
+}
+
+@end
+
+int
+main(void)
+{
+	dispatch_test_start("NSOperation");
+
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+	NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
+	test_ptr_notnull("NSOperationQueue", queue);
+
+	MYOperation *operation = [[MYOperation alloc] init];
+	test_ptr_notnull("NSOperation", operation);
+
+	[queue addOperation:operation];
+	[operation release];
+
+	[[NSRunLoop mainRunLoop] run];
+
+	[pool release];
+
+	return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..56e5b58
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,160 @@
+#
+#
+#
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+noinst_LTLIBRARIES=libbsdtests.la
+
+libbsdtests_la_SOURCES=				\
+	bsdtests.c				\
+	bsdtests.h				\
+	dispatch_test.c				\
+	dispatch_test.h				\
+	linux_port.h
+
+check_PROGRAMS=					\
+	bsdtestharness				\
+	bsdtestsummarize			\
+	$(TESTS)
+
+noinst_SCRIPTS=leaks-wrapper.sh
+
+# Tests that have not been ported to Linux
+# because they test unsupported functionality.
+UNPORTED_TESTS=					\
+	dispatch_deadname			\
+	dispatch_proc				\
+	dispatch_vm					\
+	dispatch_vnode
+
+# Tests that usually pass, but occasionally fail
+# and are therefore not suitable for general CI usage.
+UNRELIABLE_TESTS=				\
+	dispatch_priority			\
+	dispatch_priority2			\
+	dispatch_concur				\
+	dispatch_read				\
+	dispatch_read2				\
+	dispatch_suspend_timer		\
+	dispatch_pingpong			\
+	dispatch_drift				\
+	dispatch_readsync			\
+	dispatch_cascade			\
+	dispatch_io
+
+if EXTENDED_TEST_SUITE
+ADDITIONAL_TESTS= $(UNRELIABLE_TESTS)
+else
+ADDITIONAL_TESTS=
+endif
+
+# The set of tests that will be run by 'make check'
+TESTS=							\
+	dispatch_apply				\
+	dispatch_api				\
+	dispatch_c99				\
+	dispatch_debug				\
+	dispatch_queue_finalizer	\
+	dispatch_group				\
+	dispatch_overcommit			\
+	dispatch_plusplus			\
+	dispatch_context_for_key	\
+	dispatch_after				\
+	dispatch_timer				\
+	dispatch_timer_short		\
+	dispatch_timer_timeout		\
+	dispatch_sema				\
+	dispatch_timer_bit31		\
+	dispatch_timer_bit63		\
+	dispatch_timer_set_time		\
+	dispatch_starfish			\
+	dispatch_data				\
+	dispatch_io_net				\
+	dispatch_select				\
+	$(ADDITIONAL_TESTS)
+
+# For testing in swift.org CI system; make deadlines lenient by default
+# to reduce probability of test failures due to machine load.
+if HAVE_SWIFT
+CI_CFLAGS=-DLENIENT_DEADLINES=1
+endif
+
+dispatch_c99_CFLAGS=$(DISPATCH_TESTS_CFLAGS) $(CBLOCKS_FLAGS) -std=c99
+dispatch_plusplus_SOURCES=dispatch_plusplus.cpp
+dispatch_priority2_SOURCES=dispatch_priority.c
+dispatch_priority2_CPPFLAGS=$(AM_CPPFLAGS) -DUSE_SET_TARGET_QUEUE=1
+
+AM_CPPFLAGS=-I$(top_builddir) -I$(top_srcdir)
+
+DISPATCH_TESTS_CFLAGS=-Wall -Wno-deprecated-declarations $(MARCH_FLAGS) $(CI_CFLAGS)
+AM_CFLAGS=$(DISPATCH_TESTS_CFLAGS) $(CBLOCKS_FLAGS) $(BSD_OVERLAY_CFLAGS)
+AM_OBJCFLAGS=$(DISPATCH_TESTS_CFLAGS) $(CBLOCKS_FLAGS)
+AM_CXXFLAGS=$(DISPATCH_TESTS_CFLAGS) $(CXXBLOCKS_FLAGS) $(BSD_OVERLAY_CFLAGS)
+AM_OBJCXXFLAGS=$(DISPATCH_TESTS_CFLAGS) $(CXXBLOCKS_FLAGS)
+
+if HAVE_PTHREAD_WORKQUEUES
+  PTHREAD_WORKQUEUE_LIBS=-lpthread_workqueue
+endif
+
+if BUILD_OWN_BLOCKS_RUNTIME
+CBLOCKS_FLAGS+= -I$(top_srcdir)/src/BlocksRuntime
+CXXBLOCKS_FLAGS+= -I$(top_srcdir)/src/BlocksRuntime
+endif
+
+if HAVE_SWIFT
+  SWIFT_LIBS=-L$(SWIFT_LIBDIR) -lswiftCore -lswiftSwiftOnoneSupport
+  AM_LDFLAGS=-rpath $(SWIFT_LIBDIR)
+endif
+
+LDADD=libbsdtests.la $(top_builddir)/src/libdispatch.la $(PTHREAD_WORKQUEUE_LIBS) $(BSD_OVERLAY_LIBS) $(SWIFT_LIBS)
+libbsdtests_la_LDFLAGS=-avoid-version
+
+bsdtestsummarize_LDADD=-lm $(BSD_OVERLAY_LIBS)
+dispatch_timer_short_LDADD=-lm $(LDADD)
+dispatch_group_LDADD=-lm $(LDADD)
+
+if HAVE_LEAKS
+AM_TESTS_ENVIRONMENT=
+else
+AM_TESTS_ENVIRONMENT=NOLEAKS=1
+endif
+LOG_COMPILER=./bsdtestharness
+
+DISTCLEAN=Foundation/bench.cc
+
+if HAVE_COREFOUNDATION
+TESTS+=							\
+	dispatch_cf_main			\
+	dispatch_transform			\
+	dispatch_sync_on_main		\
+	cffd
+AM_CFLAGS+=-DHAVE_COREFOUNDATION
+
+dispatch_cf_main_LDFLAGS=-framework CoreFoundation
+dispatch_transform_LDFLAGS=-framework CoreFoundation -framework Security
+dispatch_sync_on_main_LDFLAGS=-framework CoreFoundation
+cffd_LDFLAGS=-framework CoreFoundation
+endif
+
+if HAVE_FOUNDATION
+TESTS+=							\
+	dispatch_sync_gc			\
+	dispatch_apply_gc			\
+	nsoperation					\
+	bench
+AM_CFLAGS+=-DHAVE_FOUNDATION
+
+dispatch_sync_gc_SOURCES=Foundation/dispatch_sync_gc.m
+dispatch_sync_gc_LDFLAGS=-framework Foundation
+dispatch_apply_gc_SOURCES=Foundation/dispatch_apply_gc.m
+dispatch_apply_gc_LDFLAGS=-framework Foundation
+nsoperation_SOURCES=Foundation/nsoperation.m
+nsoperation_LDFLAGS=-framework Foundation
+bench_SOURCES=Foundation/bench.mm func.c
+bench_LDFLAGS=-framework Foundation
+endif
+
+# For use by swift/utils/build-script to force test cases to be
+# built during the build phase of CI
+build-tests: $(TESTS) $(check_PROGRAMS)
diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c
new file mode 100644
index 0000000..eab84b3
--- /dev/null
+++ b/tests/bsdtestharness.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <assert.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <mach/clock_types.h>
+#include <mach-o/arch.h>
+#endif
+#include <sys/resource.h>
+#include <sys/time.h>
+#ifdef __linux__
+#include <sys/wait.h>
+#endif
+
+#include <bsdtests.h>
+
+extern char **environ;
+
+#ifdef __linux__
+// Linux lacks the DISPATCH_SOURCE_TYPE_PROC functionality
+// the real test harness needs.
+#define SIMPLE_TEST_HARNESS 1
+#else
+#define SIMPLE_TEST_HARNESS 0
+#endif
+
+int
+main(int argc, char *argv[])
+{
+	int res;
+	pid_t pid = 0;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s [...]\n", argv[0]);
+		exit(1);
+	}
+
+#ifdef __APPLE__
+	short spawnflags = POSIX_SPAWN_START_SUSPENDED;
+#if TARGET_OS_EMBEDDED
+	spawnflags |= POSIX_SPAWN_SETEXEC;
+#endif
+#else
+#define POSIX_SPAWN_SETEXEC 0      /* ignore... */
+	short spawnflags = 0;
+#endif
+
+	posix_spawnattr_t attr;
+	res = posix_spawnattr_init(&attr);
+	assert(res == 0);
+	res = posix_spawnattr_setflags(&attr, spawnflags);
+	assert(res == 0);
+
+	uint64_t to = 0;
+	char *tos = getenv("BSDTEST_TIMEOUT");
+	if (tos) {
+		to = strtoul(tos, NULL, 0);
+		to *= NSEC_PER_SEC;
+	}
+
+#ifdef __APPLE__
+	char *arch = getenv("BSDTEST_ARCH");
+	if (arch) {
+		const NXArchInfo *ai = NXGetArchInfoFromName(arch);
+		if (ai) {
+			res = posix_spawnattr_setbinpref_np(&attr, 1, (cpu_type_t*)&ai->cputype, NULL);
+			assert(res == 0);
+		}
+	}
+
+#endif
+	int i;
+	char** newargv = calloc((size_t)argc, sizeof(void*));
+	for (i = 1; i < argc; ++i) {
+		newargv[i-1] = argv[i];
+	}
+	newargv[i-1] = NULL;
+
+	struct timeval tv_start;
+	gettimeofday(&tv_start, NULL);
+
+	if (spawnflags & POSIX_SPAWN_SETEXEC) {
+		pid = fork();
+	}
+	if (!pid) {
+		res = posix_spawnp(&pid, newargv[0], NULL, &attr, newargv, environ);
+		if (res) {
+			errno = res;
+			perror(newargv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	//fprintf(stderr, "pid = %d\n", pid);
+	assert(pid > 0);
+
+#if SIMPLE_TEST_HARNESS
+	int status;
+	struct rusage usage;
+	struct timeval tv_stop, tv_wall;
+
+	gettimeofday(&tv_stop, NULL);
+	tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
+	tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
+	tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);
+
+	int res2 = wait4(pid, &status, 0, &usage);
+	(void)res2;
+	assert(res2 != -1);
+	test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0);
+	printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
+	printf("[PERF]\tuser time: %ld.%06ld\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
+	printf("[PERF]\tsystem time: %ld.%06ld\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
+	printf("[PERF]\tmax resident set size: %ld\n", usage.ru_maxrss);
+	printf("[PERF]\tpage faults: %ld\n", usage.ru_majflt);
+	printf("[PERF]\tswaps: %ld\n", usage.ru_nswap);
+	printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw);
+	printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw);
+	exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status));
+#else
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+
+	dispatch_source_t tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, main_q);
+	assert(tmp_ds);
+	dispatch_source_set_event_handler(tmp_ds, ^{
+		int status;
+		struct rusage usage;
+		struct timeval tv_stop, tv_wall;
+
+		gettimeofday(&tv_stop, NULL);
+		tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
+		tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
+		tv_wall.tv_usec = abs(tv_stop.tv_usec - tv_start.tv_usec);
+
+		int res2 = wait4(pid, &status, 0, &usage);
+		assert(res2 != -1);
+		test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0);
+		printf("[PERF]\twall time: %ld.%06d\n", tv_wall.tv_sec, tv_wall.tv_usec);
+		printf("[PERF]\tuser time: %ld.%06d\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
+		printf("[PERF]\tsystem time: %ld.%06d\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
+		printf("[PERF]\tmax resident set size: %ld\n", usage.ru_maxrss);
+		printf("[PERF]\tpage faults: %ld\n", usage.ru_majflt);
+		printf("[PERF]\tswaps: %ld\n", usage.ru_nswap);
+		printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw);
+		printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw);
+		exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status));
+	});
+	dispatch_resume(tmp_ds);
+
+	if (!to) {
+#if TARGET_OS_EMBEDDED
+		to = 180LL * NSEC_PER_SEC;
+#else
+		to = 90LL * NSEC_PER_SEC;
+#endif
+	}
+
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, to), main_q, ^{
+		kill(pid, SIGKILL);
+		fprintf(stderr, "Terminating unresponsive process (%0.1lfs)\n", (double)to / NSEC_PER_SEC);
+	});
+
+	signal(SIGINT, SIG_IGN);
+	tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGINT, 0, main_q);
+	assert(tmp_ds);
+	dispatch_source_set_event_handler(tmp_ds, ^{
+		fprintf(stderr, "Terminating process due to signal\n");
+		kill(pid, SIGKILL);
+	});
+	dispatch_resume(tmp_ds);
+
+	if (spawnflags & POSIX_SPAWN_SETEXEC) {
+		usleep(USEC_PER_SEC/10);
+	}
+	kill(pid, SIGCONT);
+
+	dispatch_main();
+#endif // SIMPLE_TEST_HARNESS
+
+	return 0;
+}
diff --git a/tests/bsdtests.c b/tests/bsdtests.c
new file mode 100644
index 0000000..18b4462
--- /dev/null
+++ b/tests/bsdtests.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+#ifdef __linux__
+// for asprintf
+#define _GNU_SOURCE 1
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/errno.h>
+#include <sys/wait.h>
+#include <string.h>
+#ifdef __APPLE__
+#include <crt_externs.h>
+#include <mach/mach_error.h>
+#endif
+#include <spawn.h>
+#include <inttypes.h>
+#include "bsdtests.h"
+
+static int _test_exit_code;
+
+#define _test_print(_file, _line, _desc, \
+	_expr, _fmt1, _val1, _fmt2, _val2) do { \
+	const char* _exprstr; \
+	char _linestr[BUFSIZ]; \
+	_linestr[0] = 0; \
+	if (!(_expr)) { \
+		_exprstr = "FAIL"; \
+		_test_exit_code = 0xff; \
+		if (_file && _file[0] != '\0') { \
+			snprintf(_linestr, sizeof(_linestr), \
+					 " (%s:%ld)", _file, _line); \
+		} \
+	} else { \
+		_exprstr = "PASS"; \
+	} \
+	if (_fmt2 == 0) { \
+		fprintf(stdout, "\n"			\
+			"[BEGIN] %s\n"			\
+			"\tValue: " _fmt1 "\n"		\
+			"[%s] %s%s\n",			\
+			_desc,				\
+			_val1,				\
+			_exprstr,			\
+			_desc,				\
+			_linestr);			\
+	} else { \
+		fprintf(stdout, "\n"		   \
+			"[BEGIN] %s\n"		   \
+			"\tActual: " _fmt1 "\n"	   \
+			"\tExpected: " _fmt2 "\n"  \
+			"[%s] %s%s\n",		   \
+			_desc,			   \
+			_val1,			   \
+			_val2,			   \
+			_exprstr,		   \
+			_desc,			   \
+			_linestr);		   \
+	} \
+	if (!_expr && _file && _file[0] != '\0') { \
+		fprintf(stdout, "\t%s:%ld\n", _file, _line); \
+	} \
+	fflush(stdout); \
+} while (0);
+
+#define GENERATE_DESC	\
+	char desc[BUFSIZ];	\
+	va_list args;	\
+	\
+	va_start(args, format);	\
+	vsnprintf(desc, sizeof(desc), format, args);	\
+	va_end(args);
+
+void
+_test_ptr_null(const char* file, long line, const char* desc, const void* ptr)
+{
+	_test_print(file, line, desc,
+		(ptr == NULL), "%p", ptr, "%p", (void*)0);
+}
+
+void
+test_ptr_null_format(void *ptr, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_ptr_null(NULL, 0, desc, ptr);
+}
+
+void
+_test_ptr_notnull(const char* file, long line, const char* desc, const void* ptr)
+{
+	_test_print(file, line, desc,
+		(ptr != NULL), "%p", ptr, "%p", ptr ?: (void*)~0);
+}
+
+void
+test_ptr_notnull_format(const void *ptr, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_ptr_notnull(NULL, 0, desc, ptr);
+}
+
+void
+_test_ptr(const char* file, long line, const char* desc, const void* actual, const void* expected)
+{
+	_test_print(file, line, desc,
+		(actual == expected), "%p", actual, "%p", expected);
+}
+
+void
+test_ptr_format(const void* actual, const void* expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_ptr(NULL, 0, desc, actual, expected);
+}
+
+void _test_ptr_not(const char* file, long line, const char* desc, const void* actual, const void* expected)
+{
+	_test_print(file, line, desc,
+				(actual != expected), "%p", actual, "!%p", expected);
+}
+
+void test_ptr_not_format(const void *actual, const void* expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_ptr_not(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_uint32(const char* file, long line, const char* desc, uint32_t actual, uint32_t expected)
+{
+	_test_print(file, line, desc,
+		(actual == expected), "%u", actual, "%u", expected);
+}
+
+void
+test_uint32_format(uint32_t actual, uint32_t expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_uint32(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_int32(const char* file, long line, const char* desc, int32_t actual, int32_t expected)
+{
+	_test_print(file, line, desc,
+		(actual == expected), "%d", actual, "%d", expected);
+}
+
+void
+test_int32_format(int32_t actual, int32_t expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_int32(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_long(const char* file, long line, const char* desc, long actual, long expected)
+{
+	_test_print(file, line, desc,
+		(actual == expected), "%ld", actual, "%ld", expected);
+}
+
+void
+test_long_format(long actual, long expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_long(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_uint64(const char* file, long line, const char* desc, uint64_t actual, uint64_t expected)
+{
+	_test_print(file, line, desc,
+							(actual == expected), "%" PRIu64, actual, "%" PRIu64, expected);
+}
+
+void
+test_uint64_format(uint64_t actual, uint64_t expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_uint64(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_int64(const char* file, long line, const char* desc, int64_t actual, int64_t expected)
+{
+	_test_print(file, line, desc,
+							(actual == expected), "%" PRId64, actual, "%" PRId64, expected);
+}
+
+void
+test_int64_format(int64_t actual, int64_t expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_int64(NULL, 0, desc, actual, expected);
+}
+
+void
+_test_long_less_than(const char* file, long line, const char* desc, long actual, long expected_max)
+{
+	_test_print(file, line, desc, (actual < expected_max), "%ld", actual, "<%ld", expected_max);
+}
+
+void
+test_long_less_than_format(long actual, long expected_max, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_long_less_than(NULL, 0, desc, actual, expected_max);
+}
+
+void
+_test_long_less_than_or_equal(const char* file, long line, const char* desc, long actual, long expected_max)
+{
+	_test_print(file, line, desc, (actual <= expected_max), "%ld", actual, "<=%ld", expected_max);
+}
+
+void
+test_long_less_than_or_equal_format(long actual, long expected_max, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_long_less_than_or_equal(NULL, 0, desc, actual, expected_max);
+}
+
+void
+_test_long_greater_than_or_equal(const char* file, long line, const char* desc, long actual, long expected_min)
+{
+	_test_print(file, line, desc, (actual >= expected_min), "%ld", actual, ">=%ld", expected_min);
+}
+
+void
+test_long_greater_than_or_equal_format(long actual, long expected_max, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_long_greater_than_or_equal(NULL, 0, desc, actual, expected_max);
+}
+
+void
+_test_double_less_than(const char* file, long line, const char* desc, double val, double max_expected)
+{
+	_test_print(file, line, desc, (val < max_expected), "%f", val, "<%f", max_expected);
+}
+
+void
+test_double_less_than_format(double val, double max_expected, const char* format, ...)
+{
+	GENERATE_DESC
+	_test_double_less_than(NULL, 0, desc, val, max_expected);
+}
+
+void
+_test_double_less_than_or_equal(const char* file, long line, const char* desc, double val, double max_expected)
+{
+	_test_print(file, line, desc, (val <= max_expected), "%f", val, "<=%f", max_expected);
+}
+
+void
+test_double_less_than_or_equal_format(double val, double max_expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_double_less_than_or_equal(NULL, 0, desc, val, max_expected);
+}
+
+void
+_test_double_equal(const char* file, long line, const char* desc, double val, double expected)
+{
+	#pragma clang diagnostic push
+	#pragma clang diagnostic ignored "-Wfloat-equal"
+	_test_print(file, line, desc, (val == expected), "%f", val, "%f", expected);
+	#pragma clang diagnostic pop
+}
+
+
+void
+test_double_equal_format(double val, double expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_double_equal(NULL, 0, desc, val, expected);
+}
+
+void
+_test_errno(const char* file, long line, const char* desc, int actual, int expected)
+{
+	char* actual_str;
+	char* expected_str;
+	asprintf(&actual_str, "%d\t%s", actual, actual ? strerror(actual) : "");
+	asprintf(&expected_str, "%d\t%s", expected, expected ? strerror(expected) : "");
+	_test_print(file, line, desc,
+		(actual == expected), "%s", actual_str, "%s", expected_str);
+	free(actual_str);
+	free(expected_str);
+}
+
+void
+test_errno_format(int actual, int expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_errno(NULL, 0, desc, actual, expected);
+}
+
+#ifdef __APPLE__
+void
+_test_mach_error(const char* file, long line, const char* desc,
+		mach_error_t actual, mach_error_t expected)
+{
+	char* actual_str;
+	char* expected_str;
+	asprintf(&actual_str, "%d %s", actual, actual ? mach_error_string(actual) : "");
+	asprintf(&expected_str, "%d %s", expected, expected ? mach_error_string(expected) : "");
+	_test_print(file, line, desc,
+		(actual == expected), "%s", actual_str, "%s", expected_str);
+	free(actual_str);
+	free(expected_str);
+}
+
+void
+test_mach_error_format(mach_error_t actual, mach_error_t expected, const char *format, ...)
+{
+	GENERATE_DESC
+	_test_mach_error(NULL, 0, desc, actual, expected);
+}
+#endif
+
+void
+_test_skip(const char* file, long line, const char* desc)
+{
+	if (file != NULL && file[0] != '\0') {
+		fprintf(stdout, "[SKIP] %s (%s:%ld)\n", desc, file, line);
+	} else {
+		fprintf(stdout, "[SKIP] %s\n", desc);
+	}
+	fflush(stdout);
+}
+
+void
+test_skip_format(const char *format, ...)
+{
+	GENERATE_DESC
+	fprintf(stdout, "[SKIP] %s\n", desc);
+}
+
+#if USE_COREFOUNDATION
+void
+test_cferror(const char *desc, CFErrorRef actual, CFIndex expectedCode)
+{
+	if (actual != NULL) {
+		CFStringRef errDesc = CFErrorCopyDescription(actual);
+		CFIndex code = CFErrorGetCode(actual);
+		char* actual_str;
+		char* expected_str;
+
+		if (code != expectedCode) {
+			char buffer[BUFSIZ];
+			CFStringGetCString(errDesc, buffer, sizeof(buffer), kCFStringEncodingUTF8);
+			asprintf(&actual_str, "%ld\t%s", code, buffer);
+		} else {
+			asprintf(&actual_str, "%ld", code);
+		}
+
+		asprintf(&expected_str, "%ld", expectedCode);
+		_test_print("", (long) 0, desc,
+					(code == expectedCode), "%s", actual_str, "%s", expected_str);
+
+		free(actual_str);
+		free(expected_str);
+
+		CFRelease(errDesc);
+	} else {
+		_test_print("", (long) 0, desc, (0 == expectedCode), "%ld", (long) 0, "%ld", (long) expectedCode);
+	}
+}
+
+void
+test_cferror_format(CFErrorRef actual, CFIndex expectedCode, const char *format, ...)
+{
+	GENERATE_DESC
+	test_cferror(desc, actual, expectedCode);
+}
+#endif
+
+void
+test_start(const char* desc)
+{
+	if (desc) {
+		fprintf(stdout, "\n==================================================\n");
+		fprintf(stdout, "[TEST] %s\n", desc);
+		fprintf(stdout, "[PID] %d\n", getpid());
+		fprintf(stdout, "==================================================\n\n");
+		fflush(stdout);
+	}
+	_test_exit_code = EXIT_SUCCESS;
+	usleep(100000);	// give 'gdb --waitfor=' a chance to find this proc
+}
+
+#if __linux__
+static char** get_environment(void)
+{
+	extern char **environ; 
+	return environ;
+}
+#else
+static char** get_environment(void)
+{
+	return (* _NSGetEnviron());
+}
+#endif
+
+void
+test_leaks_pid(const char *name, pid_t pid)
+{
+	int res;
+	char pidstr[10];
+
+	if (getenv("NOLEAKS")) {
+		return;
+	}
+
+	if (!name) {
+		name = "Leaks";
+	}
+
+	/* leaks doesn't work against debug variant malloc */
+	const char *dyld_image_suffix = getenv("DYLD_IMAGE_SUFFIX");
+	if (dyld_image_suffix && strstr(dyld_image_suffix, "_debug")) {
+		return;
+	}
+
+	char *inserted_libs = getenv("DYLD_INSERT_LIBRARIES");
+	if (inserted_libs && strstr(inserted_libs, "/usr/lib/libgmalloc.dylib")) {
+		return;
+	}
+
+	unsetenv("DYLD_IMAGE_SUFFIX");
+	unsetenv("DYLD_INSERT_LIBRARIES");
+	unsetenv("DYLD_LIBRARY_PATH");
+
+	unsetenv("MallocStackLogging");
+	unsetenv("MallocStackLoggingNoCompact");
+
+	snprintf(pidstr, sizeof(pidstr), "%d", pid);
+
+	char* args[] = { "./leaks-wrapper", pidstr, NULL };
+	res = posix_spawnp(&pid, args[0], NULL, NULL, args, get_environment());
+	if (res == 0 && pid > 0) {
+		int status;
+		waitpid(pid, &status, 0);
+		test_long(name, status, 0);
+	} else {
+		perror(args[0]);
+	}
+}
+
+void
+test_leaks(const char *name)
+{
+	test_leaks_pid(name, getpid());
+}
+
+void
+test_stop_after_delay(void *delay)
+{
+	if (delay != NULL) {
+		sleep((uint)(intptr_t)delay);
+	}
+
+	test_leaks(NULL);
+
+	fflush(stdout);
+	_exit(_test_exit_code);
+}
+
+void
+test_stop(void)
+{
+	test_stop_after_delay((void *)(intptr_t)0);
+}
diff --git a/tests/bsdtests.h b/tests/bsdtests.h
new file mode 100644
index 0000000..6792e38
--- /dev/null
+++ b/tests/bsdtests.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+#ifndef __BSD_TEST_H__
+#define __BSD_TEST_H__
+
+#include <errno.h>
+#ifdef __APPLE__
+#include <mach/error.h>
+#endif
+#if defined(__APPLE__) || defined(HAVE_COREFOUNDATION)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#include <string.h>
+
+static inline const char*
+__BASENAME__(const char *_str_)
+{
+	const char *_s_ = strrchr(_str_, '/');
+	return (_s_ ? _s_ : _str_ - 1) + 1;
+}
+#define __SOURCE_FILE__	__BASENAME__(__FILE__)
+
+__BEGIN_DECLS
+
+/**
+ * test_start() provides the TEST token. Use this once per test "tool"
+ */
+void test_start(const char* desc);
+
+/**
+ * Explicitly runs the 'leaks' test without stopping the process.
+ */
+void test_leaks_pid(const char *name, pid_t pid);
+void test_leaks(const char *name);
+
+/**
+ * test_stop() checks for leaks during the tests using leaks-wrapper. Use this at the end of each "tool"
+ */
+void test_stop(void) __attribute__((__noreturn__));
+void test_stop_after_delay(void *delay) __attribute__((__noreturn__));
+
+/**
+ * Each test "tool" can used one or more of these functions to perform actual
+ * testing and provide a PASS/FAIL token. All APIs take a descriptive string
+ * that is printed after the token.
+ */
+void _test_ptr_null(const char* file, long line, const char* desc, const void* ptr);
+#define test_ptr_null(a,b) _test_ptr_null(__SOURCE_FILE__, __LINE__, a, b)
+void test_ptr_null_format(void *ptr, const char *format, ...);
+
+void _test_ptr_notnull(const char* file, long line, const char* desc, const void* ptr);
+#define test_ptr_notnull(a,b) _test_ptr_notnull(__SOURCE_FILE__, __LINE__, a, b)
+void test_ptr_notnull_format(const void *ptr, const char *format, ...) __printflike(2, 3);
+
+void _test_ptr_not(const char* file, long line, const char* desc, const void* actual, const void* expected);
+#define test_ptr_not(a, b, c) _test_ptr_not(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_ptr_not_format(const void* actual, const void* expected, const char *format, ...);
+
+void _test_ptr(const char* file, long line, const char* desc, const void* actual, const void* expected);
+#define test_ptr(a,b,c) _test_ptr(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_ptr_format(const void* actual, const void* expected, const char *format, ...) __printflike(3,4);
+
+void _test_uint32(const char* file, long line, const char* desc, uint32_t actual, uint32_t expected);
+#define test_uint32(a,b,c) _test_uint32(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_uint32_format(uint32_t actual, uint32_t expected, const char *format, ...) __printflike(3,4);
+
+void _test_int32(const char* file, long line, const char* desc, int32_t actual, int32_t expected);
+#define test_int32(a,b,c) _test_int32(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_int32_format(int32_t actual, int32_t expected, const char* format, ...) __printflike(3,4);
+
+void _test_long(const char* file, long line, const char* desc, long actual, long expected);
+#define test_long(a,b,c) _test_long(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_long_format(long actual, long expected, const char *format, ...) __printflike(3,4);
+
+void _test_uint64(const char* file, long line, const char* desc, uint64_t actual, uint64_t expected);
+#define test_uint64(a,b,c) _test_uint64(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_uint64_format(uint64_t actual, uint64_t expected, const char* desc, ...);
+
+void _test_int64(const char* file, long line, const char* desc, int64_t actual, int64_t expected);
+#define test_int64(a,b,c) _test_uint64(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_int64_format(int64_t actual, int64_t expected, const char* desc, ...);
+
+void _test_long_less_than(const char* file, long line, const char* desc, long actual, long max_expected);
+#define test_long_less_than(a,b,c) _test_long_less_than(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_long_less_than_format(long actual, long max_expected, const char *format, ...) __printflike(3,4);
+
+void _test_long_less_than_or_equal(const char* file, long line, const char* desc, long actual, long max_expected);
+#define test_long_less_than_or_equal(a,b,c) _test_long_less_than_or_equal(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_long_less_than_or_equal_format(long actual, long max_expected, const char *format, ...) __printflike(3,4);
+
+void _test_long_greater_than_or_equal(const char* file, long line, const char* desc, long actual, long expected_min);
+#define test_long_greater_than_or_equal(a,b,c) _test_long_greater_than_or_equal(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_long_greater_than_or_equal_format(long actual, long expected_min, const char *format, ...) __printflike(3,4);
+
+void _test_double_less_than_or_equal(const char* file, long line, const char* desc, double val, double max_expected);
+#define test_double_less_than_or_equal(d, v, m) _test_double_less_than_or_equal(__SOURCE_FILE__, __LINE__, d, v, m)
+void test_double_less_than_or_equal_format(double val, double max_expected, const char *format, ...) __printflike(3,4);
+
+void _test_double_less_than(const char* file, long line, const char* desc, double val, double max_expected);
+#define test_double_less_than(d, v, m) _test_double_less_than(__SOURCE_FILE__, __LINE__, d, v, m)
+void test_double_less_than_format(double val, double max_expected, const char *format, ...) __printflike(3,4);
+
+void _test_double_equal(const char* file, long line, const char* desc, double val, double expected);
+#define test_double_equal(d, v, m) _test_double_equal(__SOURCE_FILE__, __LINE__, d, v, m)
+void test_double_equal_format(double val, double expected, const char *format, ...) __printflike(3,4);
+
+void _test_errno(const char* file, long line, const char* desc, int actual, int expected);
+#define test_errno(a,b,c) _test_errno(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_errno_format(int actual, int expected, const char *format, ...) __printflike(3,4);
+
+#ifndef __linux__
+void _test_mach_error(const char* file, long line, const char* desc, mach_error_t actual, mach_error_t expected);
+#define test_mach_error(a,b,c) _test_mach_error(__SOURCE_FILE__, __LINE__, a, b, c)
+void test_mach_error_format(mach_error_t actual, mach_error_t expected, const char *format, ...) __printflike(3,4);
+#endif
+
+#if defined(__APPLE__) || defined(HAVE_COREFOUNDATION)
+void test_cferror(const char* desc, CFErrorRef actual, CFIndex expectedCode);
+void test_cferror_format(CFErrorRef actual, CFIndex expectedCode, const char *format, ...) __printflike(3,4);
+#endif
+
+void _test_skip(const char* file, long line, const char* desc);
+#define test_skip(m) _test_skip(__SOURCE_FILE__, __LINE__, m)
+#define test_skip2(m) _test_skip("", 0, m)
+void test_skip_format(const char *format, ...) __printflike(1,2);
+
+__END_DECLS
+
+#endif /* __BSD_TEST_H__ */
diff --git a/tests/bsdtestsummarize.c b/tests/bsdtestsummarize.c
new file mode 100644
index 0000000..d0568d7
--- /dev/null
+++ b/tests/bsdtestsummarize.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2008-2011 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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+int
+has_prefix(const char* str, const char* prefix)
+{
+	return (strncmp(str, prefix, strlen(prefix)) == 0);
+}
+
+int
+print_summary(FILE* f, long total, long pass, long fail, long skip)
+{
+	double dpass = 100.0 ,dfail = 0.0, dskip = 0.0;
+	fprintf(f, "Total:  %ld\n", total);
+	if (total) {
+		dpass = ((double)pass / (double)(total - skip)) * 10000.0;
+		dpass = floor(dpass) / 100.0;
+
+		dfail = ((double)fail / (double)(total - skip)) * 10000.0;
+		dfail = ceil(dfail) / 100.0;
+
+		dskip = ((double)skip / (double)total) * 10000.0;
+		dskip = ceil(dskip) / 100.0;
+	}
+	fprintf(f, "Passed: %ld (%0.2lf%%)\nFailed: %ld (%0.2lf%%)\nSkipped: %ld (%0.2lf%%)\n\n", pass, dpass, fail, dfail, skip, dskip);
+	return 0;
+}
+
+int
+main(int argc, char* argv[])
+{
+	if (argc > 1) {
+		fprintf(stderr, "%s: usage: summarize\n", argv[0]);
+		exit(1);
+	}
+
+	/*
+	FILE* f = fopen(argv[1], "w");
+	if (f == NULL) {
+		perror(argv[1]);
+		exit(1);
+	}
+	*/
+	FILE* f = stdout;
+
+	fprintf(f, "\n==================================================\n");
+	fprintf(f, "[SUMMARY] Test Summary\n");
+	fprintf(f, "==================================================\n\n");
+
+	size_t len;
+	char* ln, lastln[1024];
+	int  first_test = 1;
+	long total = 0;
+	long pass = 0;
+	long fail = 0;
+	long skip = 0;
+	long total_total = 0;
+	long total_pass = 0;
+	long total_fail = 0;
+	long total_skip = 0;
+	for(;;) {
+		ln = fgetln(stdin, &len);
+		//if (ln) fprintf(stdout, "%.*s", (int)len, ln);
+		if (ln == NULL || (has_prefix(ln, "[TEST]") &&
+				strncmp(ln, lastln, MIN(len,1024)))) {
+			if (total || !first_test) {
+				print_summary(f, total, pass, fail, skip);
+				first_test = 0;
+			}
+			total_total += total;
+			total_pass += pass;
+			total_fail += fail;
+			total_skip += skip;
+			total = 0;
+			pass = 0;
+			fail = 0;
+			skip = 0;
+			if (ln) {
+				fprintf(f, "%.*s", (int)len, ln);
+				strncpy(lastln, ln, MIN(len,1024));
+			} else {
+				fprintf(f, "[TOTAL]\n");
+				print_summary(f, total_total, total_pass, total_fail, total_skip);
+				break;
+			}
+		} else if (has_prefix(ln, "[PASS]")) {
+			++total;
+			++pass;
+		} else if (has_prefix(ln, "[FAIL]")) {
+			++total;
+			++fail;
+		} else if (has_prefix(ln, "[SKIP]")) {
+			++total;
+			++skip;
+		}
+	}
+
+	return (total_fail ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/tests/cffd.c b/tests/cffd.c
new file mode 100644
index 0000000..7ba91ee
--- /dev/null
+++ b/tests/cffd.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/queue.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static int long kevent_data = 0;
+
+#if 0
+int debug = 0;
+
+#define DEBUG(...) do { \
+		if (debug) fprintf(stderr, __VA_ARGS__); \
+	} while(0);
+#endif
+
+#define assert_errno(str, expr) do { \
+	if (!(expr)) { \
+		fprintf(stderr, "%s: %s\n", (str), strerror(errno)); \
+		exit(1); \
+	} } while(0);
+
+int
+init_kqueue(void)
+{
+	int kq;
+	int res;
+	struct kevent ke;
+	static struct timespec t0;
+
+	kq = kqueue();
+	assert_errno("kqueue", kq >= 0);
+
+	EV_SET(&ke, 1, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, USEC_PER_SEC/10, 0);
+
+	res = kevent(kq, &ke, 1, NULL, 0, &t0);
+	assert_errno("kevent", res == 0);
+
+	return kq;
+}
+
+int
+read_kevent(int kq)
+{
+	int res;
+	struct kevent ke;
+	//static struct timespec t0;
+
+	res = kevent(kq, NULL, 0, &ke, 1, NULL);
+	assert_errno("kevent", res >= 0);
+
+	kevent_data += ke.data;
+	fprintf(stdout, "kevent.data = %ld\n", ke.data);
+
+	return (res < 0);
+}
+
+
+static void
+cffd_callback(CFFileDescriptorRef cffd,
+	CFOptionFlags callBackTypes __attribute__((unused)),
+	void *info __attribute__((unused)))
+{
+	int kq;
+
+	kq = CFFileDescriptorGetNativeDescriptor(cffd);
+	if (read_kevent(kq) == 0) {
+		// ...
+	}
+
+	CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack);
+}
+
+#if 0
+void
+timer()
+{
+	dispatch_source_t ds;
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
+	assert(ds);
+	dispatch_source_set_timer(ds, dispatch_time(0, 1*NSEC_PER_SEC), NSEC_PER_SEC, 0);
+	dispatch_source_set_event_handler(ds, ^{
+		printf("ping\n");
+	});
+	dispatch_resume(ds);
+}
+
+void
+hangup()
+{
+	dispatch_source_t ds;
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, dispatch_get_main_queue());
+	assert(ds);
+	dispatch_source_set_event_handler(ds, ^{
+		printf("hangup\n");
+	});
+	dispatch_resume(ds);
+}
+#endif
+
+int
+main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
+{
+	int kq;
+	CFFileDescriptorRef cffd;
+	CFRunLoopSourceRef  rls;
+	CFFileDescriptorContext ctx;
+
+	dispatch_test_start("CFFileDescriptor");
+
+#if 0
+	signal(SIGHUP, SIG_IGN);
+#endif
+
+	kq = init_kqueue();
+
+	memset(&ctx, 0, sizeof(CFFileDescriptorContext));
+	cffd = CFFileDescriptorCreate(NULL, kq, 1, cffd_callback, &ctx);
+	assert(cffd);
+
+	rls = CFFileDescriptorCreateRunLoopSource(NULL, cffd, 0);
+	assert(rls);
+	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+	CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack);
+
+#if 0
+	timer();
+	hangup();
+#endif
+
+	CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.05, false);
+	// Should fire at least 10 times ...
+	test_long_greater_than_or_equal("kevent data", kevent_data, 10);
+
+	test_stop();
+
+	return 0;
+}
+
diff --git a/tests/dispatch_after.c b/tests/dispatch_after.c
new file mode 100644
index 0000000..6c95a3b
--- /dev/null
+++ b/tests/dispatch_after.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+
+#include <bsdtests.h>
+#include <Block.h>
+
+#include "dispatch_test.h"
+
+static void
+done(void *arg /*__unused */)
+{
+	(void)arg;
+	sleep(1);
+	test_stop();
+}
+
+static void
+test_after(void)
+{
+	__block dispatch_time_t time_a_min, time_a, time_a_max;
+	__block dispatch_time_t time_b_min, time_b, time_b_max;
+	__block dispatch_time_t time_c_min, time_c, time_c_max;
+
+	dispatch_test_start("Dispatch After");
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+		time_a_min = dispatch_time(0,  (int64_t)(5.5*NSEC_PER_SEC));
+		time_a     = dispatch_time(0,   (int64_t)(6*NSEC_PER_SEC));
+		time_a_max = dispatch_time(0,  (int64_t)(6.5*NSEC_PER_SEC));
+		dispatch_after(time_a, dispatch_get_main_queue(), ^{
+			dispatch_time_t now_a = dispatch_time(0, 0);
+			test_long_less_than("can't finish faster than 5.5s", 0, (long)(now_a - time_a_min));
+			test_long_less_than("must finish faster than  6.5s", 0, (long)(time_a_max - now_a));
+
+			time_b_min = dispatch_time(0,  (int64_t)(1.5*NSEC_PER_SEC));
+			time_b     = dispatch_time(0,  (int64_t)(2*NSEC_PER_SEC));
+			time_b_max = dispatch_time(0,  (int64_t)(2.5*NSEC_PER_SEC));
+			dispatch_after(time_b, dispatch_get_main_queue(), ^{
+				dispatch_time_t now_b = dispatch_time(0, 0);
+				test_long_less_than("can't finish faster than 1.5s", 0, (long)(now_b - time_b_min));
+				test_long_less_than("must finish faster than  2.5s", 0, (long)(time_b_max - now_b));
+
+				time_c_min = dispatch_time(0,  0*NSEC_PER_SEC);
+				time_c     = dispatch_time(0,  0*NSEC_PER_SEC);
+				time_c_max = dispatch_time(0,  (int64_t)(.5*NSEC_PER_SEC));
+				dispatch_after(time_c, dispatch_get_main_queue(), ^{
+					dispatch_time_t now_c = dispatch_time(0, 0);
+					test_long_less_than("can't finish faster than 0s", 0, (long)(now_c - time_c_min));
+					test_long_less_than("must finish faster than .5s", 0, (long)(time_c_max - now_c));
+
+					dispatch_async_f(dispatch_get_main_queue(), NULL, done);
+				});
+			});
+		});
+	});
+}
+
+int
+main(void)
+{
+	test_after();
+	dispatch_main();
+	return 1;
+}
diff --git a/tests/dispatch_api.c b/tests/dispatch_api.c
new file mode 100644
index 0000000..07540e7
--- /dev/null
+++ b/tests/dispatch_api.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008-2011 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 <stdlib.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static void
+work(void *context __attribute__((unused)))
+{
+	test_stop();
+	exit(0);
+}
+
+int
+main(void)
+{
+	dispatch_queue_t q;
+	dispatch_test_start("Dispatch (Public) API");
+	q = dispatch_get_main_queue();
+	test_ptr_notnull("dispatch_get_main_queue", q);
+
+	dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+	dispatch_main();
+	return 0;
+}
diff --git a/tests/dispatch_apply.c b/tests/dispatch_apply.c
new file mode 100644
index 0000000..380fd35
--- /dev/null
+++ b/tests/dispatch_apply.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+#include <sys/types.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static volatile int32_t busy_threads_started, busy_threads_finished;
+
+/*
+ * Keep a thread busy, spinning on the CPU.
+ */
+static volatile int all_done = 0;
+
+/* Fiddling with j in the middle and hitting this global will hopefully keep
+ * the optimizer from cutting the whole thing out as dead code.
+ */
+static volatile unsigned int busythread_useless;
+static void busythread(void *ignored)
+{
+	(void)ignored;
+	/* prevent i and j been optimized out */
+	volatile uint64_t i = 0, j = 0;
+
+	OSAtomicIncrement32(&busy_threads_started);
+
+	while(!all_done)
+	{
+		if(i == 500000) { j -= busythread_useless; }
+		j += i;
+		i += 1;
+	}
+
+	OSAtomicIncrement32(&busy_threads_finished);
+}
+
+/*
+ * Test that dispatch_apply can make progress and finish, even if there are
+ * so many other running and unblocked workqueue threads that the apply's
+ * helper threads never get a chance to come up.
+ *
+ * <rdar://problem/10718199> dispatch_apply should not block waiting on other
+ * threads while calling thread is available
+ */
+static void test_apply_contended(dispatch_queue_t dq)
+{
+	uint32_t activecpu;
+#ifdef __linux__
+	activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN);
+#else
+	size_t s = sizeof(activecpu);
+	sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0);
+#endif
+	int tIndex, n_threads = (int)activecpu;
+	dispatch_group_t grp = dispatch_group_create();
+
+	for(tIndex = 0; tIndex < n_threads; tIndex++) {
+		dispatch_group_async_f(grp, dq, NULL, busythread);
+	}
+
+	// Spin until all the threads have actually started
+	while(busy_threads_started < n_threads) {
+		usleep(1);
+	}
+
+	volatile __block int32_t count = 0;
+	const int32_t final = 32;
+
+	int32_t before = busy_threads_started;
+	dispatch_apply(final, dq, ^(size_t i __attribute__((unused))) {
+		OSAtomicIncrement32(&count);
+	});
+	int32_t after = busy_threads_finished;
+
+	test_long("contended: threads started before apply", before, n_threads);
+	test_long("contended: count", count, final);
+	test_long("contended: threads finished before apply", after, 0);
+
+	/* Release busy threads by setting all_done to 1 */
+        all_done = 1;
+
+	dispatch_group_wait(grp, DISPATCH_TIME_FOREVER);
+	dispatch_release(grp);
+
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Apply");
+
+	volatile __block int32_t count = 0;
+	const int32_t final = 32;
+
+	dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+	test_ptr_notnull("dispatch_get_global_queue", queue);
+
+	dispatch_apply(final, queue, ^(size_t i __attribute__((unused))) {
+		OSAtomicIncrement32(&count);
+	});
+	test_long("count", count, final);
+
+	count = 0; // rdar://problem/9294578
+	dispatch_apply(final, queue, ^(size_t i __attribute__((unused))) {
+		dispatch_apply(final, queue, ^(size_t ii __attribute__((unused))) {
+			dispatch_apply(final, queue, ^(size_t iii __attribute__((unused))) {
+				OSAtomicIncrement32(&count);
+			});
+		});
+	});
+	test_long("nested count", count, final * final * final);
+
+	test_apply_contended(queue);
+
+	test_stop();
+
+	return 0;
+}
diff --git a/tests/dispatch_c99.c b/tests/dispatch_c99.c
new file mode 100644
index 0000000..a4531e3
--- /dev/null
+++ b/tests/dispatch_c99.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdlib.h>
+
+#ifdef __linux__
+// On Linux normally comes from libbsd overlay files,
+// but the headers are not c99 compliant so we compile
+// this test case without $(BSD_OVERLAY_CFLAGS)
+#define __printflike(a,b) __attribute__((format(printf, a, b)))
+#include <inttypes.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static void
+work(void *context __attribute__((unused)))
+{
+	test_stop();
+	exit(0);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch C99");
+	dispatch_queue_t q = dispatch_get_main_queue();
+	test_ptr_notnull("dispatch_get_main_queue", q);
+
+	dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+	dispatch_main();
+	return 0;
+}
diff --git a/tests/dispatch_cascade.c b/tests/dispatch_cascade.c
new file mode 100644
index 0000000..ad5a359
--- /dev/null
+++ b/tests/dispatch_cascade.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2008-2011 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 <stdio.h>
+#include <dispatch/dispatch.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+int done = 0;
+
+#define QUEUES 80
+dispatch_queue_t queues[QUEUES];
+
+#define BLOCKS 10000
+union {
+	size_t index;
+	char padding[64];
+} indices[BLOCKS];
+
+size_t iterations = QUEUES * BLOCKS * 0.25;
+
+static void
+noop(void *ctxt __attribute__((unused)))
+{
+	return;
+}
+
+static void
+cleanup(void *ctxt __attribute__((unused)))
+{
+	size_t q;
+	for (q = 0; q < QUEUES; ++q) {
+		dispatch_sync_f(queues[q], NULL, noop);
+		dispatch_release(queues[q]);
+	}
+	test_stop();
+	exit(0);
+}
+
+void
+histogram(void)
+{
+	size_t counts[QUEUES] = {};
+	size_t maxcount = 0;
+
+	size_t q;
+	for (q = 0; q < QUEUES; ++q) {
+		size_t i;
+		for (i = 0; i < BLOCKS; ++i) {
+			if (indices[i].index == q) {
+				++counts[q];
+			}
+		}
+	}
+
+	for (q = 0; q < QUEUES; ++q) {
+		if (counts[q] > maxcount) {
+			maxcount = counts[q];
+		}
+	}
+
+	printf("maxcount = %zd\n", maxcount);
+
+	size_t x,y;
+	for (y = 20; y > 0; --y) {
+		for (x = 0; x < QUEUES; ++x) {
+			double fraction = (double)counts[x] / (double)maxcount;
+			double value = fraction * (double)20;
+			printf("%s", (value > y) ? "*" : " ");
+		}
+		printf("\n");
+	}
+}
+
+void
+cascade(void* context)
+{
+	size_t idx, *idxptr = context;
+
+	if (done) return;
+
+	idx = *idxptr + 1;
+
+	if (idx < QUEUES) {
+		*idxptr = idx;
+		dispatch_async_f(queues[idx], context, cascade);
+	}
+
+	if (__sync_sub_and_fetch(&iterations, 1) == 0) {
+		done = 1;
+		histogram();
+		dispatch_async_f(dispatch_get_main_queue(), NULL, cleanup);
+	}
+}
+
+int
+main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
+{
+	int i;
+
+	dispatch_test_start("Dispatch Cascade");
+
+	for (i = 0; i < QUEUES; ++i) {
+		queues[i] = dispatch_queue_create(NULL, NULL);
+	}
+
+	for (i = 0; i < BLOCKS; ++i) {
+		cascade(&indices[i].index);
+	}
+
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_cf_main.c b/tests/dispatch_cf_main.c
new file mode 100644
index 0000000..4d11cd2
--- /dev/null
+++ b/tests/dispatch_cf_main.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010-2011 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 <dispatch/dispatch.h>
+#include <stdio.h>
+#include <CoreFoundation/CoreFoundation.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+const int32_t final = 10;
+static volatile int32_t count;
+
+static void
+work(void* ctxt __attribute__((unused)))
+{
+	int32_t c = OSAtomicIncrement32(&count);
+	if (c < final-1) {
+		dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+		CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
+			fprintf(stderr, "CFRunLoopPerformBlock %d\n", c);
+			test_long_less_than("CFRunLoopPerformBlock", count, final);
+		});
+	}
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch CF main queue"); // <rdar://problem/7760523>
+	dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+	dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
+			dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+		test_long("done", count, final);
+		test_stop();
+	});
+	CFRunLoopRun();
+
+	return 0;
+}
diff --git a/tests/dispatch_concur.c b/tests/dispatch_concur.c
new file mode 100644
index 0000000..ac62292
--- /dev/null
+++ b/tests/dispatch_concur.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2010-2011 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 <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static volatile size_t done, concur;
+static int use_group_async;
+static uint32_t activecpu;
+static uint32_t min_acceptable_concurrency;
+
+static dispatch_queue_t q;
+static dispatch_group_t g, gw;
+
+const size_t workers = 4;
+
+static void
+nop(void* ctxt __attribute__((unused)))
+{
+	return;
+}
+
+static void
+work(void* ctxt __attribute__((unused)))
+{
+	usleep(1000);
+	__sync_add_and_fetch(&done, 1);
+
+	if (!use_group_async) dispatch_group_leave(gw);
+}
+
+static void
+submit_work(void* ctxt)
+{
+	size_t c = __sync_add_and_fetch(&concur, 1), *m = (size_t *)ctxt, i;
+	if (c > *m) *m = c;
+
+	for (i = 0; i < workers; ++i) {
+		if (use_group_async) {
+			dispatch_group_async_f(gw, q, NULL, work);
+		} else {
+			dispatch_group_enter(gw);
+			dispatch_async_f(q, NULL, work);
+		}
+	}
+
+	usleep(10000);
+	__sync_sub_and_fetch(&concur, 1);
+
+	if (!use_group_async) dispatch_group_leave(g);
+}
+
+static void
+test_concur_async(size_t n, size_t qw)
+{
+	size_t i, max_concur = 0, *mcs = calloc(n, sizeof(size_t)), *mc;
+	done = concur = 0;
+
+	dispatch_suspend(q);
+	for (i = 0, mc = mcs; i < n; i++, mc++) {
+		if (use_group_async) {
+			dispatch_group_async_f(g, q, mc, submit_work);
+		} else {
+			dispatch_group_enter(g);
+			dispatch_async_f(q, mc, submit_work);
+		}
+	}
+	dispatch_resume(q);
+
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+	if (qw > 1) {
+		size_t concurrency = MIN(n * workers, qw);
+		if (done > min_acceptable_concurrency) {
+			test_long_less_than_or_equal("concurrently completed workers", done, concurrency);
+		} else {
+			test_long("concurrently completed workers", done, concurrency);
+		}
+	} else {
+		test_long_less_than_or_equal("concurrently completed workers", done, 1);
+	}
+
+	for (i = 0, mc = mcs; i < n; i++, mc++) {
+		if (*mc > max_concur) max_concur = *mc;
+	}
+	free(mcs);
+
+	size_t expect = MIN(n, qw);
+	if (max_concur > min_acceptable_concurrency) {
+		test_long_less_than_or_equal("max submission concurrency", max_concur, expect);
+	} else {
+		test_long("max submission concurrency", max_concur, expect);
+	}
+
+	dispatch_group_wait(gw, DISPATCH_TIME_FOREVER);
+	usleep(1000);
+}
+
+static void
+sync_work(void* ctxt)
+{
+	size_t c = __sync_add_and_fetch(&concur, 1), *m = (size_t *)ctxt;
+	if (c > *m) *m = c;
+
+	usleep(10000);
+	__sync_sub_and_fetch(&concur, 1);
+}
+
+static void
+test_concur_sync(size_t n, size_t qw)
+{
+	size_t i, max_concur = 0, *mcs = calloc(n, sizeof(size_t)), *mc;
+	concur = 0;
+
+	for (i = 0, mc = mcs; i < n; i++, mc++) {
+		dispatch_group_async(g,
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,
+				DISPATCH_QUEUE_OVERCOMMIT), ^{
+			usleep(100000);
+			dispatch_sync_f(q, mc, sync_work);
+		});
+	}
+
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+	for (i = 0, mc = mcs; i < n; i++, mc++) {
+		if (*mc > max_concur) max_concur = *mc;
+	}
+	free(mcs);
+
+	size_t expect = qw == 1 ? 1 : n;
+	if (max_concur > min_acceptable_concurrency) {
+		test_long_less_than_or_equal("max sync concurrency", max_concur, expect);
+	} else {
+		test_long("max sync concurrency", max_concur, expect);
+	}
+}
+
+static void
+apply_work(void* ctxt, size_t i)
+{
+	size_t c = __sync_add_and_fetch(&concur, 1), *m = ((size_t *)ctxt) + i;
+	if (c > *m) *m = c;
+
+	usleep(100000);
+	__sync_sub_and_fetch(&concur, 1);
+}
+
+static void
+test_concur_apply(size_t n, size_t qw)
+{
+	size_t i, max_concur = 0, *mcs = calloc(n, sizeof(size_t)), *mc;
+	concur = 0;
+
+	dispatch_apply_f(n, q, mcs, apply_work);
+
+	for (i = 0, mc = mcs; i < n; i++, mc++) {
+		if (*mc > max_concur) max_concur = *mc;
+	}
+	free(mcs);
+
+	size_t expect = MIN(n, qw);
+	if (max_concur > min_acceptable_concurrency) {
+		test_long_less_than_or_equal("max apply concurrency", max_concur, expect);
+	} else {
+		test_long("max apply concurrency", max_concur, expect);
+	}
+}
+
+static dispatch_queue_t
+create_queue(long width, dispatch_queue_t tq, long *qw, const char **ql)
+{
+	if (!width) {
+		*qw = LONG_MAX;
+		*ql = "global";
+		return dispatch_get_global_queue(0, 0);
+	};
+	dispatch_queue_t queue;
+	dispatch_queue_attr_t qattr = NULL;
+
+	*qw = width;
+	*ql = width < LONG_MAX ? ( width == 1 ? "serial": "wide" ) : "concurrent";
+#if DISPATCH_API_VERSION >= 20100518 // <rdar://problem/7790099>
+	qattr = width < LONG_MAX ? NULL : DISPATCH_QUEUE_CONCURRENT;
+#endif
+	queue = dispatch_queue_create(*ql, qattr);
+	if (!qattr) {
+		dispatch_queue_set_width(queue, width);
+	}
+	if (tq) {
+		dispatch_set_target_queue(queue, tq);
+	}
+	if (!qattr || tq) {
+		dispatch_barrier_sync_f(queue, NULL, nop); // wait for changes to take effect
+	}
+	return queue;
+}
+
+int
+main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
+{
+	dispatch_test_start("Dispatch Private Concurrent/Wide Queue"); // <rdar://problem/8049506&8169448&8186485>
+
+#ifdef __linux__
+	activecpu = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+	size_t s = sizeof(activecpu);
+	sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0);
+#endif
+	size_t n = activecpu / 2 > 1 ? activecpu / 2 : 1, w = activecpu * 2;
+	min_acceptable_concurrency = n;
+	dispatch_queue_t tq, ttq;
+	long qw, tqw, ttqw;
+	const char *ql, *tql, *ttql;
+	size_t qi, tqi, ttqi;
+	long qws[] = {
+		0, LONG_MAX, w, 1, // 0 <=> global queue
+	};
+
+	g = dispatch_group_create();
+	gw = dispatch_group_create();
+
+	for (ttqi = 0; ttqi < sizeof(qws)/sizeof(*qws); ttqi++) {
+		ttq = create_queue(qws[ttqi], NULL, &ttqw, &ttql);
+		for (tqi = 0; tqi < sizeof(qws)/sizeof(*qws); tqi++) {
+			if (!qws[tqi] && qws[ttqi]) continue;
+			tq = create_queue(qws[tqi], ttq, &tqw, &tql);
+			for (qi = 0; qi < sizeof(qws)/sizeof(*qws); qi++) {
+				if (!qws[qi] && qws[tqi]) continue;
+				q = create_queue(qws[qi], tq, &qw, &ql);
+				for (use_group_async = 0; use_group_async < 2; use_group_async++) {
+					fprintf(stdout, "Testing dispatch%s_async on "
+							"queue hierarchy: %s -> %s -> %s\n",
+							use_group_async ? "_group" : "", ql, tql, ttql);
+					fflush(stdout);
+					test_concur_async(n, MIN(qw, MIN(tqw, ttqw)));
+				}
+				fprintf(stdout, "Testing dispatch_sync on "
+						"queue hierarchy: %s -> %s -> %s\n", ql, tql, ttql);
+				fflush(stdout);
+				test_concur_sync(w, MIN(qw, MIN(tqw, ttqw)));
+				fprintf(stdout, "Testing dispatch_apply on "
+						"queue hierarchy: %s -> %s -> %s\n", ql, tql, ttql);
+				fflush(stdout);
+				test_concur_apply(activecpu, MIN(qw, MIN(tqw, ttqw)));
+				dispatch_release(q);
+			}
+			dispatch_release(tq);
+		}
+		dispatch_release(ttq);
+	}
+
+	dispatch_release(g);
+	dispatch_release(gw);
+
+	test_stop();
+	return 0;
+}
diff --git a/tests/dispatch_context_for_key.c b/tests/dispatch_context_for_key.c
new file mode 100644
index 0000000..c10a869
--- /dev/null
+++ b/tests/dispatch_context_for_key.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2010-2011 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 <dispatch/dispatch.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if DISPATCH_API_VERSION >= 20100825 && DISPATCH_API_VERSION != 20101110
+
+static char *ctxts[] = {"ctxt for app", "ctxt for key 1",
+		"ctxt for key 2", "ctxt for key 1 bis", "ctxt for key 4"};
+volatile long ctxts_destroyed;
+static dispatch_group_t g;
+
+static void
+destructor(void *ctxt)
+{
+	fprintf(stderr, "destructor of %s\n", (char*)ctxt);
+	(void)__sync_add_and_fetch(&ctxts_destroyed, 1);
+	dispatch_group_leave(g);
+}
+
+static void
+test_context_for_key(void)
+{
+	g = dispatch_group_create();
+	dispatch_queue_t q = dispatch_queue_create("q", NULL);
+#if DISPATCH_API_VERSION >= 20100518
+	dispatch_queue_t tq = dispatch_queue_create("tq", DISPATCH_QUEUE_CONCURRENT);
+#else
+	dispatch_queue_t tq = dispatch_queue_create("tq", NULL);
+	dispatch_queue_set_width(tq, LONG_MAX);
+#endif
+	dispatch_queue_t ttq = dispatch_get_global_queue(0, 0);
+	dispatch_group_enter(g);
+#if DISPATCH_API_VERSION >= 20101011
+	dispatch_queue_set_specific(tq, &ctxts[4], ctxts[4], destructor);
+#else
+	dispatch_set_context_for_key(tq, &ctxts[4], ctxts[4], ttq, destructor);
+#endif
+	dispatch_set_target_queue(tq, ttq);
+	dispatch_group_enter(g);
+	dispatch_set_context(q, ctxts[0]);
+	dispatch_set_target_queue(q, tq);
+	dispatch_set_finalizer_f(q, destructor);
+
+	dispatch_async(q, ^{
+		dispatch_group_enter(g);
+#if DISPATCH_API_VERSION >= 20101011
+		dispatch_queue_set_specific(q, &ctxts[1], ctxts[1], destructor);
+#else
+		dispatch_set_context_for_key(q, &ctxts[1], ctxts[1], ttq, destructor);
+#endif
+	});
+	dispatch_retain(q);
+	dispatch_async(dispatch_get_global_queue(0, 0), ^{
+		dispatch_group_enter(g);
+#if DISPATCH_API_VERSION >= 20101011
+		dispatch_queue_set_specific(q, &ctxts[2], ctxts[2], destructor);
+#else
+		dispatch_set_context_for_key(q, &ctxts[2], ctxts[2], ttq, destructor);
+#endif
+		dispatch_async(dispatch_get_global_queue(0, 0), ^{
+			void *ctxt;
+#if DISPATCH_API_VERSION >= 20101011
+			ctxt = dispatch_queue_get_specific(q, &ctxts[2]);
+#else
+			ctxt = dispatch_get_context_for_key(q, &ctxts[2]);
+#endif
+			test_ptr("get context for key 2", ctxt, ctxts[2]);
+			dispatch_release(q);
+		});
+	});
+	dispatch_async(q, ^{
+		void *ctxt;
+#if DISPATCH_API_VERSION >= 20101011
+		ctxt = dispatch_get_specific(&ctxts[1]);
+		test_ptr("get current context for key 1", ctxt, ctxts[1]);
+		ctxt = dispatch_get_specific(&ctxts[4]);
+		test_ptr("get current context for key 4 (on target queue)", ctxt, ctxts[4]);
+		ctxt = dispatch_queue_get_specific(q, &ctxts[1]);
+#else
+		ctxt = dispatch_get_context_for_key(tq, &ctxts[4]);
+		test_ptr("get context for key 4 (on target queue)", ctxt, ctxts[4]);
+		ctxt = dispatch_get_context_for_key(q, &ctxts[1]);
+#endif
+		test_ptr("get context for key 1", ctxt, ctxts[1]);
+	});
+	dispatch_async(q, ^{
+		dispatch_group_enter(g);
+		void *ctxt;
+#if DISPATCH_API_VERSION >= 20101011
+		dispatch_queue_set_specific(q, &ctxts[1], ctxts[3], destructor);
+		ctxt = dispatch_queue_get_specific(q, &ctxts[1]);
+#else
+		dispatch_set_context_for_key(q, &ctxts[1], ctxts[3], ttq, destructor);
+		ctxt = dispatch_get_context_for_key(q, &ctxts[1]);
+#endif
+		test_ptr("get context for key 1", ctxt, ctxts[3]);
+	});
+	dispatch_async(q, ^{
+		void *ctxt;
+#if DISPATCH_API_VERSION >= 20101011
+		dispatch_queue_set_specific(q, &ctxts[1], NULL, destructor);
+		ctxt = dispatch_queue_get_specific(q, &ctxts[1]);
+#else
+		dispatch_set_context_for_key(q, &ctxts[1], NULL, ttq, destructor);
+		ctxt = dispatch_get_context_for_key(q, &ctxts[1]);
+#endif
+		test_ptr("get context for key 1", ctxt, NULL);
+	});
+	void *ctxt = dispatch_get_context(q);
+	test_ptr("get context for app", ctxt, ctxts[0]);
+	dispatch_release(tq);
+	dispatch_release(q);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+	test_long("contexts destroyed", ctxts_destroyed, 5);
+	dispatch_release(g);
+}
+#endif
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Queue Specific"); // rdar://problem/8429188
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+#if DISPATCH_API_VERSION >= 20100825 && DISPATCH_API_VERSION != 20101110
+		test_context_for_key();
+#endif
+		test_stop();
+	});
+	dispatch_main();
+}
diff --git a/tests/dispatch_data.c b/tests/dispatch_data.c
new file mode 100644
index 0000000..2c69a6f
--- /dev/null
+++ b/tests/dispatch_data.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2009-2011 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 <stdio.h>
+#include <stdlib.h>
+
+#include <dispatch/dispatch.h>
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#ifndef DISPATCHTEST_DATA
+#if DISPATCH_API_VERSION >= 20100226 && DISPATCH_API_VERSION != 20101110
+#define DISPATCHTEST_DATA 1
+#endif
+#endif
+
+dispatch_group_t g;
+
+#if DISPATCHTEST_DATA
+static void
+test_concat(void)
+{
+	dispatch_group_enter(g);
+	dispatch_async(dispatch_get_main_queue(), ^{
+		char* buffer1 = "This is buffer1 ";
+		size_t size1 = 17;
+		char* buffer2 = "This is buffer2 ";
+		size_t size2 = 17;
+		__block bool buffer2_destroyed = false;
+
+		dispatch_data_t data1 = dispatch_data_create(buffer1, size1, NULL, NULL);
+		dispatch_data_t data2 = dispatch_data_create(buffer2, size2,
+					dispatch_get_main_queue(), ^{
+			buffer2_destroyed = true;
+		});
+		dispatch_data_t concat = dispatch_data_create_concat(data1, data2);
+
+		dispatch_release(data1);
+		dispatch_release(data2);
+
+		test_long("Data size of concatenated dispatch data",
+				  (long)dispatch_data_get_size(concat), 34);
+
+		const void* contig;
+		size_t contig_size;
+		dispatch_data_t contig_data =
+			dispatch_data_create_map(concat, &contig, &contig_size);
+
+		dispatch_release(concat);
+		dispatch_release(contig_data);
+		test_long("Contiguous memory size", (long)contig_size, 34);
+		dispatch_async(dispatch_get_main_queue(), ^{
+			test_long("buffer2 destroyed", buffer2_destroyed, true);
+			dispatch_group_leave(g);
+		});
+	});
+}
+
+static void
+test_cleanup(void) // <rdar://problem/9843440>
+{
+	static char buffer4[16];
+	dispatch_group_enter(g);
+	dispatch_async(dispatch_get_main_queue(), ^{
+		void *buffer3 = malloc(1024);
+		dispatch_data_t data3 = dispatch_data_create(buffer3, 0,
+				dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
+		__block bool buffer4_destroyed = false;
+		dispatch_data_t data4 = dispatch_data_create(buffer4, 16,
+				dispatch_get_main_queue(), ^{
+			buffer4_destroyed = true;
+		});
+		dispatch_release(data3);
+		dispatch_release(data4);
+		dispatch_async(dispatch_get_main_queue(), ^{
+			test_long("buffer4 destroyed", buffer4_destroyed, true);
+			dispatch_group_leave(g);
+		});
+	});
+}
+#endif
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Data");
+	g = dispatch_group_create();
+
+#if DISPATCHTEST_DATA
+	test_concat();
+	test_cleanup();
+#endif
+
+	dispatch_group_notify(g, dispatch_get_main_queue(), ^{
+		dispatch_release(g);
+		test_stop();
+	});
+	dispatch_main();
+}
diff --git a/tests/dispatch_deadname.c b/tests/dispatch_deadname.c
new file mode 100644
index 0000000..805944e
--- /dev/null
+++ b/tests/dispatch_deadname.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if TEST_MACHPORT_DEBUG
+#define test_mach_assume_zero(x) ({kern_return_t _kr = (x); \
+		if (_kr) fprintf(stderr, "mach error 0x%x \"%s\": %s\n", \
+		_kr, mach_error_string(_kr), #x); (void)kr; })
+void
+test_mach_debug_port(mach_port_t name, const char *str, unsigned int line)
+{
+	mach_port_type_t type;
+	mach_msg_bits_t ns = 0, nr = 0, nso = 0, nd = 0;
+	unsigned int dnreqs = 0, dnrsiz;
+	kern_return_t kr = mach_port_type(mach_task_self(), name, &type);
+	if (kr) {
+		fprintf(stderr, "machport[0x%08x] = { error(0x%x) \"%s\" }: %s %u\n",
+				name, kr, mach_error_string(kr), str, line);
+		return;
+	}
+	if (type & MACH_PORT_TYPE_SEND) {
+		test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
+				MACH_PORT_RIGHT_SEND, &ns));
+	}
+	if (type & MACH_PORT_TYPE_SEND_ONCE) {
+		test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
+				MACH_PORT_RIGHT_SEND_ONCE, &nso));
+	}
+	if (type & MACH_PORT_TYPE_DEAD_NAME) {
+		test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
+				MACH_PORT_RIGHT_DEAD_NAME, &nd));
+	}
+	if (type & (MACH_PORT_TYPE_RECEIVE|MACH_PORT_TYPE_SEND)) {
+		test_mach_assume_zero(mach_port_dnrequest_info(mach_task_self(), name,
+				&dnrsiz, &dnreqs));
+		}
+	if (type & MACH_PORT_TYPE_RECEIVE) {
+		mach_port_status_t status = { .mps_pset = 0, };
+		mach_msg_type_number_t cnt = MACH_PORT_RECEIVE_STATUS_COUNT;
+		test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
+				MACH_PORT_RIGHT_RECEIVE, &nr));
+		test_mach_assume_zero(mach_port_get_attributes(mach_task_self(), name,
+				MACH_PORT_RECEIVE_STATUS, (void*)&status, &cnt));
+		fprintf(stderr, "machport[0x%08x] = { R(%03u) S(%03u) SO(%03u) D(%03u) "
+				"dnreqs(%03u) spreq(%s) nsreq(%s) pdreq(%s) srights(%s) "
+				"sorights(%03u) qlim(%03u) msgcount(%03u) mkscount(%03u) "
+				"seqno(%03u) }: %s %u\n", name, nr, ns, nso, nd, dnreqs,
+				type & MACH_PORT_TYPE_SPREQUEST ? "Y":"N",
+				status.mps_nsrequest ? "Y":"N", status.mps_pdrequest ? "Y":"N",
+				status.mps_srights ? "Y":"N", status.mps_sorights,
+				status.mps_qlimit, status.mps_msgcount, status.mps_mscount,
+				status.mps_seqno, str, line);
+	} else if (type & (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_SEND_ONCE|
+			MACH_PORT_TYPE_DEAD_NAME)) {
+		fprintf(stderr, "machport[0x%08x] = { R(%03u) S(%03u) SO(%03u) D(%03u) "
+				"dnreqs(%03u) spreq(%s) }: %s %u\n", name, nr, ns, nso, nd,
+				dnreqs, type & MACH_PORT_TYPE_SPREQUEST ? "Y":"N", str, line);
+	} else {
+		fprintf(stderr, "machport[0x%08x] = { type(0x%08x) }: %s %u\n", name,
+				type, str, line);
+	}
+	fflush(stderr);
+}
+#define test_mach_debug_port(x) test_mach_debug_port(x, __func__, __LINE__)
+#else
+#define test_mach_debug_port(x) (void)(x)
+#endif
+
+static dispatch_group_t g;
+static volatile long sent, received;
+
+void
+test_dead_name(void)
+{
+	dispatch_group_enter(g);
+	dispatch_async(dispatch_get_global_queue(0, 0), ^{
+		dispatch_source_t ds0;
+		kern_return_t kr;
+
+		mach_port_t mp = pthread_mach_thread_np(pthread_self());
+		assert(mp);
+		kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
+		test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
+		ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
+				DISPATCH_MACH_SEND_DEAD, dispatch_get_main_queue());
+		test_ptr_notnull("DISPATCH_SOURCE_TYPE_MACH_SEND", ds0);
+		dispatch_source_set_event_handler(ds0, ^{
+			test_long("DISPATCH_MACH_SEND_DEAD",
+					dispatch_source_get_handle(ds0), mp);
+			dispatch_source_cancel(ds0);
+		});
+		dispatch_source_set_cancel_handler(ds0, ^{
+			kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
+			test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
+			dispatch_release(ds0);
+			dispatch_group_leave(g);
+		});
+		dispatch_resume(ds0);
+
+		// give the mgr queue time to start, otherwise the mgr queue will run
+		// on this thread, thus defeating the test which assumes that this
+		// thread will die.
+		usleep(100000);
+	});
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+}
+
+void
+test_register_already_dead_name(void)
+{
+	dispatch_source_t ds0;
+	kern_return_t kr;
+	mach_port_t mp;
+
+	dispatch_group_enter(g);
+	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
+	test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
+	kr = mach_port_insert_right(mach_task_self(), mp, mp,
+			MACH_MSG_TYPE_MAKE_SEND);
+	test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
+
+	kr = mach_port_mod_refs(mach_task_self(), mp,
+			MACH_PORT_RIGHT_RECEIVE, -1); // turn send right into dead name
+	test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
+
+	ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
+			DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
+	dispatch_source_set_event_handler(ds0, ^{
+		test_long("DISPATCH_MACH_SEND_DEAD",
+				dispatch_source_get_handle(ds0), mp);
+		dispatch_source_cancel(ds0);
+		dispatch_release(ds0);
+	});
+	dispatch_source_set_cancel_handler(ds0, ^{
+		kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
+		test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
+		dispatch_group_leave(g);
+	});
+	dispatch_resume(ds0);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+}
+
+void
+test_receive_and_dead_name(void)
+{
+	dispatch_source_t ds0, ds;
+	kern_return_t kr;
+	mach_port_t mp;
+
+	received = 0;
+	dispatch_group_enter(g);
+	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
+	test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
+	kr = mach_port_insert_right(mach_task_self(), mp, mp,
+			MACH_MSG_TYPE_MAKE_SEND);
+	test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
+	ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
+			DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
+	dispatch_source_set_event_handler(ds0, ^{
+		test_long("DISPATCH_MACH_SEND_DEAD",
+				dispatch_source_get_handle(ds0), mp);
+		dispatch_source_cancel(ds0);
+		dispatch_release(ds0);
+	});
+	dispatch_source_set_cancel_handler(ds0, ^{
+		kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
+		test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
+		dispatch_group_leave(g);
+	});
+	dispatch_resume(ds0);
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
+			dispatch_get_global_queue(0, 0));
+	dispatch_source_set_event_handler(ds, ^{
+		__sync_add_and_fetch(&received, 1);
+		usleep(100000); // rdar://problem/7676437 race with send source re-arm
+		mach_msg_empty_rcv_t msg = { .header = {
+			.msgh_size = sizeof(mach_msg_empty_rcv_t),
+			.msgh_local_port = mp,
+		}};
+		kern_return_t kr = mach_msg_receive(&msg.header);
+		test_mach_error("mach_msg_receive", kr, KERN_SUCCESS);
+	});
+	dispatch_source_set_cancel_handler(ds, ^{
+		kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
+				MACH_PORT_RIGHT_RECEIVE, -1); // turns send right into dead name
+		test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
+	});
+	dispatch_resume(ds);
+	mach_msg_empty_send_t msg = { .header = {
+		.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
+		.msgh_size = sizeof(mach_msg_empty_send_t),
+		.msgh_remote_port = mp,
+	}};
+	kr = mach_msg_send(&msg.header);
+	test_mach_error("mach_msg_send", kr, KERN_SUCCESS);
+	usleep(200000);
+	dispatch_source_cancel(ds);
+	dispatch_release(ds);
+	test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, 1);
+	if (received > 1 ) {
+		test_stop();
+	}
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+}
+
+#if DISPATCH_API_VERSION >= 20110201 && defined(MACH_NOTIFY_SEND_POSSIBLE) && \
+		defined(MACH_SEND_NOTIFY)
+
+#define TEST_SP_MSGCOUNT 11 // (2*qlim)+1
+
+static bool
+send_until_timeout(mach_port_t mp)
+{
+	kern_return_t kr;
+
+	do {
+		test_mach_debug_port(mp);
+		mach_msg_empty_send_t msg = { .header = {
+			.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
+			.msgh_size = sizeof(mach_msg_empty_send_t),
+			.msgh_remote_port = mp,
+		}};
+		kr = mach_msg(&msg.header,
+				MACH_SEND_MSG|MACH_SEND_NOTIFY|MACH_SEND_TIMEOUT,
+				msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+				MACH_PORT_NULL);
+		if (kr == MACH_SEND_TIMED_OUT) {
+			mach_msg_destroy(&msg.header);
+			test_mach_error("mach_msg(MACH_SEND_MSG) timed out", kr,
+					MACH_SEND_TIMED_OUT);
+		} else {
+			test_mach_error("mach_msg(MACH_SEND_MSG)", kr, KERN_SUCCESS);
+			if (kr) test_stop();
+		}
+	} while (!kr && __sync_add_and_fetch(&sent, 1) < TEST_SP_MSGCOUNT);
+	test_mach_debug_port(mp);
+	return kr;
+}
+
+void
+test_send_possible(void) // rdar://problem/8758200
+{
+	dispatch_source_t ds0, ds, dsp;
+	kern_return_t kr;
+	mach_port_t mp;
+
+	sent = 0;
+	received = 0;
+	dispatch_group_enter(g);
+	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
+	test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
+	test_mach_debug_port(mp);
+	kr = mach_port_insert_right(mach_task_self(), mp, mp,
+			MACH_MSG_TYPE_MAKE_SEND);
+	test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
+	test_mach_debug_port(mp);
+	ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
+			DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
+	dispatch_source_set_registration_handler(ds0, ^{
+		test_long("DISPATCH_MACH_SEND_DEAD registered",
+				dispatch_source_get_handle(ds0), mp);
+		test_mach_debug_port(mp);
+	});
+	dispatch_source_set_event_handler(ds0, ^{
+		test_long("DISPATCH_MACH_SEND_DEAD delivered",
+				dispatch_source_get_handle(ds0), mp);
+		test_mach_debug_port(mp);
+		dispatch_source_cancel(ds0);
+		dispatch_release(ds0);
+	});
+	dispatch_source_set_cancel_handler(ds0, ^{
+		test_long("DISPATCH_MACH_SEND_DEAD canceled",
+				dispatch_source_get_handle(ds0), mp);
+		test_mach_debug_port(mp);
+		kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
+		test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
+		test_mach_debug_port(mp);
+		dispatch_group_leave(g);
+	});
+	dispatch_resume(ds0);
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
+			dispatch_get_global_queue(0, 0));
+	dispatch_source_set_registration_handler(ds, ^{
+		test_long("DISPATCH_SOURCE_TYPE_MACH_RECV registered",
+				dispatch_source_get_handle(ds), mp);
+		test_mach_debug_port(mp);
+	});
+	dispatch_source_set_event_handler(ds, ^{
+		test_long("DISPATCH_SOURCE_TYPE_MACH_RECV delivered",
+				dispatch_source_get_handle(ds), mp);
+		kern_return_t kr;
+		do {
+			test_mach_debug_port(mp);
+			usleep(10000); // simulate slow receiver
+			mach_msg_empty_rcv_t msg = { .header = {
+				.msgh_size = sizeof(mach_msg_empty_rcv_t),
+				.msgh_local_port = mp,
+			}};
+			kr = mach_msg(&msg.header,
+					MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, msg.header.msgh_size,
+					msg.header.msgh_local_port, MACH_MSG_TIMEOUT_NONE,
+					MACH_PORT_NULL);
+			if (kr == MACH_RCV_TIMED_OUT) {
+				test_mach_error("mach_msg(MACH_RCV_MSG) timed out", kr,
+						MACH_RCV_TIMED_OUT);
+			} else {
+				test_mach_error("mach_msg(MACH_RCV_MSG)", kr, KERN_SUCCESS);
+				if (kr) test_stop();
+			}
+		} while (!kr && __sync_add_and_fetch(&received, 1));
+		test_mach_debug_port(mp);
+	});
+	dispatch_source_set_cancel_handler(ds, ^{
+		test_long("DISPATCH_SOURCE_TYPE_MACH_RECV canceled",
+				dispatch_source_get_handle(ds), mp);
+		test_mach_debug_port(mp);
+		kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
+				MACH_PORT_RIGHT_RECEIVE, -1); // trigger dead name notification
+		test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
+		test_mach_debug_port(mp);
+	});
+	dispatch_resume(ds);
+	dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
+			DISPATCH_MACH_SEND_POSSIBLE, dispatch_get_global_queue(0, 0));
+	dispatch_source_set_registration_handler(dsp, ^{
+		test_long("DISPATCH_MACH_SEND_POSSIBLE registered",
+				dispatch_source_get_handle(dsp), mp);
+		if (!send_until_timeout(mp)) {
+			dispatch_source_cancel(dsp); // stop sending
+			dispatch_release(dsp);
+		}
+	});
+	dispatch_source_set_event_handler(dsp, ^{
+		test_long("DISPATCH_MACH_SEND_POSSIBLE delivered",
+				dispatch_source_get_handle(dsp), mp);
+		if (!send_until_timeout(mp)) {
+			dispatch_source_cancel(dsp); // stop sending
+			dispatch_release(dsp);
+		}
+	});
+	dispatch_source_set_cancel_handler(dsp, ^{
+		test_long("DISPATCH_MACH_SEND_POSSIBLE canceled",
+				dispatch_source_get_handle(dsp), mp);
+		test_mach_debug_port(mp);
+		dispatch_source_cancel(ds); // stop receving
+		dispatch_release(ds);
+	});
+	dispatch_resume(dsp);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+	test_long("DISPATCH_SOURCE_TYPE_MACH_SEND", sent, TEST_SP_MSGCOUNT);
+	test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, TEST_SP_MSGCOUNT);
+}
+
+#else
+#define test_send_possible()
+#endif
+
+static boolean_t
+test_mig_callback(mach_msg_header_t *message __attribute__((unused)),
+		mach_msg_header_t *reply)
+{
+	__sync_add_and_fetch(&received, 1);
+	reply->msgh_remote_port = 0;
+	return false;
+}
+
+void
+test_mig_server_large_msg(void) // rdar://problem/8422992
+{
+	dispatch_source_t ds;
+	kern_return_t kr;
+	mach_port_t mp;
+
+	received = 0;
+	dispatch_group_enter(g);
+	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
+	test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
+	kr = mach_port_insert_right(mach_task_self(), mp, mp,
+			MACH_MSG_TYPE_MAKE_SEND);
+	test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
+			dispatch_get_global_queue(0, 0));
+	dispatch_source_set_event_handler(ds, ^{
+		mach_msg_return_t r = dispatch_mig_server(ds, sizeof(mach_msg_header_t),
+				test_mig_callback);
+		test_mach_error("dispatch_mig_server", r, MACH_RCV_TOO_LARGE);
+		dispatch_group_leave(g);
+	});
+	dispatch_source_set_cancel_handler(ds, ^{
+		kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
+				MACH_PORT_RIGHT_RECEIVE, -1);
+		test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
+		kr = mach_port_deallocate(mach_task_self(), mp);
+		test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
+		dispatch_group_leave(g);
+	});
+	dispatch_resume(ds);
+
+	struct { mach_msg_header_t header; char payload[4096]; } msg = {
+		.header = {
+			.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
+			.msgh_size = sizeof(mach_msg_header_t) + 4096,
+			.msgh_remote_port = mp,
+			.msgh_id = 0xfeedface,
+		}
+	};
+	kr = mach_msg_send(&msg.header);
+	test_mach_error("mach_msg_send", kr, KERN_SUCCESS);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+	dispatch_group_enter(g);
+	dispatch_source_cancel(ds);
+	dispatch_release(ds);
+	test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, 0);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch dead-name and send-possible notifications");
+
+	dispatch_async(dispatch_get_global_queue(0, 0), ^{
+		g = dispatch_group_create();
+		test_dead_name();
+		test_register_already_dead_name();
+		test_receive_and_dead_name();
+		test_send_possible();
+		test_mig_server_large_msg();
+		test_stop();
+	});
+
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_debug.c b/tests/dispatch_debug.c
new file mode 100644
index 0000000..858c572
--- /dev/null
+++ b/tests/dispatch_debug.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008-2011 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+int
+main(void)
+{
+	setenv("LIBDISPATCH_LOG", "stderr", 1); // rdar://problem/8493990
+	dispatch_test_start("Dispatch Debug");
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	dispatch_debug(main_q, "dispatch_queue_t");
+
+	dispatch_queue_t default_q = dispatch_get_global_queue(0, 0);
+	dispatch_debug(default_q, "dispatch_queue_t");
+
+	dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	dispatch_source_set_timer(s, DISPATCH_TIME_FOREVER, 1000000000ull, 100);
+	dispatch_debug(s, "dispatch_source_t");
+
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_debug(g, "dispatch_group_t");
+
+	return 0;
+}
diff --git a/tests/dispatch_drift.c b/tests/dispatch_drift.c
new file mode 100644
index 0000000..22f82ee
--- /dev/null
+++ b/tests/dispatch_drift.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#endif
+#include <dispatch/dispatch.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if LENIENT_DEADLINES
+#define ACCEPTABLE_DRIFT 0.1
+#else
+#define ACCEPTABLE_DRIFT 0.001
+#endif
+
+int
+main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
+{
+	__block uint32_t count = 0;
+	__block double last_jitter = 0;
+	__block double drift_sum = 0;
+	// 100 times a second
+	uint64_t interval = 1000000000 / 100;
+	double interval_d = interval / 1000000000.0;
+	// for 25 seconds
+	unsigned int target = 25 / interval_d;
+
+	dispatch_test_start("Dispatch Timer Drift");
+
+	dispatch_source_t t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
+	test_ptr_notnull("dispatch_source_create", t);
+
+	dispatch_source_set_timer(t, dispatch_time(DISPATCH_TIME_NOW, interval), interval, 0);
+
+	dispatch_source_set_event_handler(t, ^{
+		struct timeval now_tv;
+		static double first = 0;
+		gettimeofday(&now_tv, NULL);
+		double now = now_tv.tv_sec + now_tv.tv_usec / 1000000.0;
+
+		if (count == 0) {
+			// Because this is taken at 1st timer fire,
+			// later jitter values may be negitave.
+			// This doesn't effect the drift calculation.
+			first = now;
+		}
+		double goal = first + interval_d * count;
+		double jitter = goal - now;
+		double drift = jitter - last_jitter;
+		drift_sum += drift;
+
+		printf("%4d: jitter %f, drift %f\n", count, jitter, drift);
+
+		if (target <= ++count) {
+			drift_sum /= count - 1;
+			if (drift_sum < 0) {
+				drift_sum = -drift_sum;
+			}
+			double acceptable_drift = ACCEPTABLE_DRIFT;
+			test_double_less_than("drift", drift_sum, acceptable_drift);
+			test_stop();
+		}
+		last_jitter = jitter;
+	});
+
+	dispatch_resume(t);
+
+	dispatch_main();
+	return 0;
+}
diff --git a/tests/dispatch_group.c b/tests/dispatch_group.c
new file mode 100644
index 0000000..708cf0d
--- /dev/null
+++ b/tests/dispatch_group.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+#include <math.h>
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC 1000000000
+#endif
+
+#if TARGET_OS_EMBEDDED
+#define LOOP_COUNT 50000
+#else
+#define LOOP_COUNT 200000
+#endif
+
+static void test_group_notify(void*);
+
+static dispatch_group_t
+create_group(size_t count, unsigned int delay)
+{
+	size_t i;
+
+	dispatch_group_t group = dispatch_group_create();
+
+	for (i = 0; i < count; ++i) {
+		dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
+		assert(queue);
+
+		dispatch_group_async(group, queue, ^{
+			if (delay) {
+				fprintf(stderr, "sleeping...\n");
+				sleep(delay);
+				fprintf(stderr, "done.\n");
+			}
+		});
+
+		dispatch_release(queue);
+		}
+	return group;
+}
+
+static void
+test_group(void *ctxt __attribute__((unused)))
+{
+	long res;
+	dispatch_group_t group;
+
+	group = create_group(100, 0);
+	test_ptr_notnull("dispatch_group_async", group);
+
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+
+	// should be OK to re-use a group
+	dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{});
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+
+	dispatch_release(group);
+	group = NULL;
+
+	group = create_group(3, 7);
+	test_ptr_notnull("dispatch_group_async", group);
+
+	res = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC));
+	test_long("dispatch_group_wait", !res, 0);
+
+	// retry after timeout (this time succeed)
+	res = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC));
+	test_long("dispatch_group_wait", res, 0);
+
+	dispatch_release(group);
+	group = NULL;
+
+	group = create_group(100, 0);
+	test_ptr_notnull("dispatch_group_async", group);
+
+	dispatch_group_notify(group, dispatch_get_main_queue(), ^{
+		dispatch_test_current("Notification Received", dispatch_get_main_queue());
+		dispatch_async_f(dispatch_get_main_queue(), NULL, test_group_notify);
+	});
+
+	dispatch_release(group);
+	group = NULL;
+}
+
+static long completed;
+
+static void
+test_group_notify2(long cycle, dispatch_group_t tested)
+{
+	static dispatch_queue_t rq, nq;
+	static dispatch_once_t once;
+	dispatch_once(&once, ^{
+		rq = dispatch_queue_create("release", 0);
+		dispatch_suspend(rq);
+		nq = dispatch_queue_create("notify", 0);
+	});
+	dispatch_resume(rq);
+
+	// n=4 works great for a 4CPU Mac Pro, this might work for a wider range of
+	// systems.
+	const int n = 1 + arc4random() % 8;
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_queue_t qa[n];
+
+	dispatch_group_enter(group);
+	for (int i = 0; i < n; i++) {
+		char buf[48];
+		sprintf(buf, "T%ld-%d", cycle, i);
+		qa[i] = dispatch_queue_create(buf, 0);
+	}
+
+	__block float eh = 0;
+	for (int i = 0; i < n; i++) {
+		dispatch_queue_t q = qa[i];
+		dispatch_group_async(group, q, ^{
+			// Seems to trigger a little more reliably with some work being
+			// done in this block
+			assert(cycle && "cycle must be non-zero");
+			eh = (float)sin(M_1_PI / cycle);
+		});
+	}
+	dispatch_group_leave(group);
+
+	dispatch_group_notify(group, nq, ^{
+		completed = cycle;
+		dispatch_group_leave(tested);
+	});
+
+	// Releasing qa's queues here seems to avoid the race, so we are arranging
+	// for the current iteration's queues to be released on the next iteration.
+	dispatch_sync(rq, ^{});
+	dispatch_suspend(rq);
+	for (int i = 0; i < n; i++) {
+		dispatch_queue_t q = qa[i];
+		dispatch_async(rq, ^{ dispatch_release(q); });
+	}
+	dispatch_release(group);
+}
+
+static void
+test_group_notify(void *ctxt __attribute__((unused)))
+{
+	// <rdar://problem/11445820>
+	dispatch_group_t tested = dispatch_group_create();
+	test_ptr_notnull("dispatch_group_create", tested);
+	long i;
+	for (i = 1; i <= LOOP_COUNT; i++) {
+		if (!(i % (LOOP_COUNT/10))) {
+			fprintf(stderr, "#%ld\n", i);
+		}
+		dispatch_group_enter(tested);
+		test_group_notify2(i, tested);
+		if (dispatch_group_wait(tested, dispatch_time(DISPATCH_TIME_NOW,
+				NSEC_PER_SEC))) {
+			break;
+		}
+	}
+	test_long("dispatch_group_notify", i - 1, LOOP_COUNT);
+	test_stop();
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Group");
+	dispatch_async_f(dispatch_get_main_queue(), NULL, test_group);
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_io.c b/tests/dispatch_io.c
new file mode 100644
index 0000000..b7fe378
--- /dev/null
+++ b/tests/dispatch_io.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2009-2011 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fts.h>
+#ifdef __APPLE__
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <libkern/OSAtomic.h>
+#include <TargetConditionals.h>
+#endif
+#ifdef __linux__
+#include <sys/resource.h>
+#endif
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#ifndef DISPATCHTEST_IO
+#if DISPATCH_API_VERSION >= 20100226 && DISPATCH_API_VERSION != 20101110
+#define DISPATCHTEST_IO 1
+#if DISPATCH_API_VERSION >= 20100723
+#define DISPATCHTEST_IO_PATH 1 // rdar://problem/7738093
+#endif
+#endif
+#endif
+
+void
+test_fin(void *cxt)
+{
+	test_ptr("test_fin run", cxt, cxt);
+	test_stop();
+}
+
+#if DISPATCHTEST_IO
+
+#if TARGET_OS_EMBEDDED
+#define LARGE_FILE "/System/Library/Fonts/Cache/STHeiti-Light.ttc" // 29MB file
+#define maxopenfiles 768
+#else
+#define LARGE_FILE "/System/Library/Speech/Voices/Alex.SpeechVoice/Contents/Resources/PCMWave" // 417MB file
+#define maxopenfiles 4096
+#endif
+
+static void
+test_io_close(int with_timer, bool from_path)
+{
+	#define chunks 4
+	#define READSIZE (512*1024)
+	unsigned int i;
+	const char *path = LARGE_FILE;
+	int fd = open(path, O_RDONLY);
+	if (fd == -1) {
+		if (errno == ENOENT) {
+			test_skip("Large file not found");
+			return;
+		}
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+#ifdef F_GLOBAL_NOCACHE
+	if (fcntl(fd, F_GLOBAL_NOCACHE, 1) == -1) {
+		test_errno("fcntl F_GLOBAL_NOCACHE", errno, 0);
+		test_stop();
+	}
+#endif
+	struct stat sb;
+	if (fstat(fd, &sb)) {
+		test_errno("fstat", errno, 0);
+		test_stop();
+	}
+	const size_t size = sb.st_size / chunks;
+	const int expected_error = with_timer? ECANCELED : 0;
+	dispatch_source_t t = NULL;
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_group_enter(g);
+	void (^cleanup_handler)(int error) = ^(int error) {
+		test_errno("create error", error, 0);
+		dispatch_group_leave(g);
+		close(fd);
+	};
+	dispatch_io_t io;
+	if (!from_path) {
+		io = dispatch_io_create(DISPATCH_IO_RANDOM, fd,
+				dispatch_get_global_queue(0, 0), cleanup_handler);
+	} else {
+#if DISPATCHTEST_IO_PATH
+		io = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path, O_RDONLY, 0,
+				dispatch_get_global_queue(0, 0), cleanup_handler);
+#endif
+	}
+	dispatch_io_set_high_water(io, READSIZE);
+	if (with_timer == 1) {
+		dispatch_io_set_low_water(io, READSIZE);
+		dispatch_io_set_interval(io,  2 * NSEC_PER_SEC,
+				DISPATCH_IO_STRICT_INTERVAL);
+	} else if (with_timer == 2) {
+		t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
+				dispatch_get_global_queue(0,0));
+		dispatch_retain(io);
+		dispatch_source_set_event_handler(t, ^{
+			dispatch_io_close(io, DISPATCH_IO_STOP);
+			dispatch_source_cancel(t);
+		});
+		dispatch_source_set_cancel_handler(t, ^{
+			dispatch_release(io);
+		});
+		dispatch_source_set_timer(t, dispatch_time(DISPATCH_TIME_NOW,
+				2 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
+		dispatch_resume(t);
+	}
+
+	size_t chunk_sizes[chunks] = {}, *chunk_size = chunk_sizes, total = 0;
+	dispatch_data_t data_chunks[chunks], *data = data_chunks;
+	for (i = 0; i < chunks; i++) {
+		data[i] = dispatch_data_empty;
+		dispatch_group_enter(g);
+		dispatch_io_read(io, i * size, size, dispatch_get_global_queue(0,0),
+				^(bool done, dispatch_data_t d, int error) {
+			if (d) {
+				chunk_size[i] += dispatch_data_get_size(d);
+				dispatch_data_t concat = dispatch_data_create_concat(data[i], d);
+				dispatch_release(data[i]);
+				data[i] = concat;
+				if ((dispatch_data_get_size(d) < READSIZE && !error && !done)) {
+					// The timer must have fired
+					dispatch_io_close(io, DISPATCH_IO_STOP);
+					return;
+				}
+			}
+			if (done) {
+				test_errno("read error", error,
+						error == expected_error ? expected_error : 0);
+				dispatch_group_leave(g);
+				dispatch_release(data[i]);
+			}
+		});
+	}
+	dispatch_io_close(io, 0);
+	dispatch_io_close(io, 0);
+	dispatch_io_read(io, 0, 1, dispatch_get_global_queue(0,0),
+			^(bool done, dispatch_data_t d, int error) {
+		test_long("closed done", done, true);
+		test_errno("closed error", error, ECANCELED);
+		test_ptr_null("closed data", d);
+	});
+	dispatch_release(io);
+	test_group_wait(g);
+	dispatch_release(g);
+	if (t) {
+		dispatch_source_cancel(t);
+		dispatch_release(t);
+	}
+	for (i = 0; i < chunks; i++) {
+		if (with_timer) {
+			test_long_less_than("chunk size", chunk_size[i], size + 1);
+		} else {
+			test_long("chunk size", chunk_size[i], size);
+		}
+		total += chunk_size[i];
+	}
+	if (with_timer) {
+		test_long_less_than("total size", total, chunks * size + 1);
+	} else {
+		test_long("total size", total, chunks * size);
+	}
+}
+
+static void
+test_io_stop(void) // rdar://problem/8250057
+{
+	int fds[2], *fd = fds;
+	if(pipe(fd) == -1) {
+		test_errno("pipe", errno, 0);
+		test_stop();
+	}
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_group_enter(g);
+	dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, *fd,
+			dispatch_get_global_queue(0, 0), ^(int error) {
+		test_errno("create error", error, 0);
+		close(*fd);
+		close(*(fd+1));
+		dispatch_group_leave(g);
+	});
+	dispatch_group_enter(g);
+	dispatch_io_read(io, 0, 1, dispatch_get_global_queue(0, 0),
+			^(bool done, dispatch_data_t d __attribute__((unused)), int error) {
+		if (done) {
+			test_errno("read error", error, ECANCELED);
+			dispatch_group_leave(g);
+		}
+	});
+	dispatch_source_t t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0,
+			0, dispatch_get_global_queue(0,0));
+	dispatch_retain(io);
+	dispatch_source_set_event_handler(t, ^{
+		dispatch_io_close(io, DISPATCH_IO_STOP);
+		dispatch_release(io);
+	});
+	dispatch_source_set_timer(t, dispatch_time(DISPATCH_TIME_NOW,
+			2 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
+	dispatch_resume(t);
+	dispatch_release(io);
+	test_group_wait(g);
+	dispatch_release(g);
+	dispatch_source_cancel(t);
+	dispatch_release(t);
+}
+
+static void
+test_io_read_write(void)
+{
+	const char *path_in = "/usr/bin/vi";
+	char path_out[] = "/tmp/dispatchtest_io.XXXXXX";
+
+	int in = open(path_in, O_RDONLY);
+	if (in == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+	struct stat sb;
+	if (fstat(in, &sb)) {
+		test_errno("fstat", errno, 0);
+		test_stop();
+	}
+	const size_t siz_in = MIN(1024 * 1024, sb.st_size);
+
+	int out = mkstemp(path_out);
+	if (out == -1) {
+		test_errno("mkstemp", errno, 0);
+		test_stop();
+	}
+	if (unlink(path_out) == -1) {
+		test_errno("unlink", errno, 0);
+		test_stop();
+	}
+	dispatch_queue_t q = dispatch_get_global_queue(0,0);
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_group_enter(g);
+	dispatch_io_t io_in = dispatch_io_create(DISPATCH_IO_STREAM, in,
+			q, ^(int error) {
+		test_errno("dispatch_io_create", error, 0);
+		close(in);
+		dispatch_group_leave(g);
+	});
+	dispatch_io_set_high_water(io_in, siz_in/4);
+	dispatch_group_enter(g);
+	dispatch_io_t io_out = dispatch_io_create(DISPATCH_IO_STREAM, out,
+			q, ^(int error) {
+		test_errno("dispatch_io_create", error, 0);
+		dispatch_group_leave(g);
+	});
+	dispatch_io_set_high_water(io_out, siz_in/16);
+	__block dispatch_data_t data = dispatch_data_empty;
+	dispatch_group_enter(g);
+	dispatch_io_read(io_in, 0, siz_in, q,
+			^(bool done_in, dispatch_data_t data_in, int err_in) {
+		test_long_less_than("read size", dispatch_data_get_size(data_in),
+				siz_in);
+		if (data_in) {
+			dispatch_group_enter(g);
+			dispatch_io_write(io_out, 0, data_in, q,
+					^(bool done_out, dispatch_data_t data_out, int err_out) {
+				if (done_out) {
+					test_errno("dispatch_io_write", err_out, 0);
+					test_long("remaining write size",
+							data_out ? dispatch_data_get_size(data_out) : 0, 0);
+					dispatch_group_leave(g);
+				} else {
+					test_long_less_than("remaining write size",
+							dispatch_data_get_size(data_out), siz_in);
+				}
+			});
+			dispatch_data_t concat = dispatch_data_create_concat(data, data_in);
+			dispatch_release(data);
+			data = concat;
+		}
+		if (done_in) {
+			test_errno("dispatch_io_read", err_in, 0);
+			dispatch_release(io_out);
+			dispatch_group_leave(g);
+		}
+	});
+	dispatch_release(io_in);
+	test_group_wait(g);
+	lseek(out, 0, SEEK_SET);
+	dispatch_group_enter(g);
+	dispatch_read(out, siz_in, q,
+			^(dispatch_data_t cmp, int err_cmp) {
+		if (err_cmp) {
+			test_errno("dispatch_read", err_cmp, 0);
+			test_stop();
+		}
+		close(out);
+		size_t siz_cmp = dispatch_data_get_size(cmp);
+		test_long("readback size", siz_cmp, siz_in);
+		const void *data_buf, *cmp_buf;
+		dispatch_data_t data_map, cmp_map;
+		data_map = dispatch_data_create_map(data, &data_buf, NULL);
+		cmp_map = dispatch_data_create_map(cmp, &cmp_buf, NULL);
+		test_long("readback memcmp",
+				memcmp(data_buf, cmp_buf, MIN(siz_in, siz_cmp)), 0);
+		dispatch_release(cmp_map);
+		dispatch_release(data_map);
+		dispatch_release(data);
+		dispatch_group_leave(g);
+	});
+	test_group_wait(g);
+	dispatch_release(g);
+}
+
+enum {
+	DISPATCH_ASYNC_READ_ON_CONCURRENT_QUEUE = 0,
+	DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE,
+	DISPATCH_READ_ON_CONCURRENT_QUEUE,
+	DISPATCH_IO_READ_ON_CONCURRENT_QUEUE,
+	DISPATCH_IO_READ_FROM_PATH_ON_CONCURRENT_QUEUE,
+};
+
+static void
+test_async_read(char *path, size_t size, int option, dispatch_queue_t queue,
+		void (^process_data)(size_t))
+{
+	int fd = open(path, O_RDONLY);
+	if (fd == -1) {
+		// Don't stop for access permission issues
+		if (errno == EACCES) {
+			process_data(size);
+			return;
+		}
+		test_errno("Failed to open file", errno, 0);
+		test_stop();
+	}
+#ifdef F_GLOBAL_NOCACHE
+	// disable caching also for extra fd opened by dispatch_io_create_with_path
+	if (fcntl(fd, F_GLOBAL_NOCACHE, 1) == -1) {
+		test_errno("fcntl F_GLOBAL_NOCACHE", errno, 0);
+		test_stop();
+	}
+#endif
+	switch (option) {
+		case DISPATCH_ASYNC_READ_ON_CONCURRENT_QUEUE:
+		case DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE:
+			dispatch_async(queue, ^{
+				char* buffer = valloc(size);
+				ssize_t r = read(fd, buffer, size);
+				if (r == -1) {
+					test_errno("async read error", errno, 0);
+					test_stop();
+				}
+				free(buffer);
+				close(fd);
+				process_data(r);
+			});
+			break;
+		case DISPATCH_READ_ON_CONCURRENT_QUEUE:
+			dispatch_read(fd, size, queue, ^(dispatch_data_t d, int error) {
+				if (error) {
+					test_errno("dispatch_read error", error, 0);
+					test_stop();
+				}
+				close(fd);
+				process_data(dispatch_data_get_size(d));
+			});
+			break;
+		case DISPATCH_IO_READ_ON_CONCURRENT_QUEUE:
+		case DISPATCH_IO_READ_FROM_PATH_ON_CONCURRENT_QUEUE: {
+			__block dispatch_data_t d = dispatch_data_empty;
+			void (^cleanup_handler)(int error) = ^(int error) {
+				if (error) {
+					test_errno("dispatch_io_create error", error, 0);
+					test_stop();
+				}
+				close(fd);
+				process_data(dispatch_data_get_size(d));
+				dispatch_release(d);
+			};
+			dispatch_io_t io = NULL;
+			if (option == DISPATCH_IO_READ_FROM_PATH_ON_CONCURRENT_QUEUE) {
+#if DISPATCHTEST_IO_PATH
+				io = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path,
+						O_RDONLY, 0, queue, cleanup_handler);
+#endif
+			} else {
+				io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue,
+						cleanup_handler);
+			}
+			if (!io) {
+				test_ptr_notnull("dispatch_io_create", io);
+				test_stop();
+			}
+
+			// Timeout after 20 secs
+			dispatch_io_set_interval(io, 20 * NSEC_PER_SEC,
+					DISPATCH_IO_STRICT_INTERVAL);
+
+			dispatch_io_read(io, 0, size, queue,
+					^(bool done, dispatch_data_t data, int error) {
+				if (!done && !error && !dispatch_data_get_size(data)) {
+					// Timer fired, and no progress from last delivery
+					dispatch_io_close(io, DISPATCH_IO_STOP);
+				}
+				if (data) {
+					dispatch_data_t c = dispatch_data_create_concat(d, data);
+					dispatch_release(d);
+					d = c;
+				}
+				if (error) {
+					test_errno("dispatch_io_read error", error, 0);
+					if (error != ECANCELED) {
+						test_stop();
+					}
+				}
+			});
+			dispatch_release(io);
+			break;
+		}
+	}
+}
+
+static int
+test_read_dirs(char **paths, dispatch_queue_t queue, dispatch_group_t g,
+		dispatch_semaphore_t s, volatile uint32_t *bytes, int option)
+{
+	FTS *tree = fts_open(paths, FTS_PHYSICAL|FTS_XDEV, NULL);
+	if (!tree) {
+		test_ptr_notnull("fts_open failed", tree);
+		test_stop();
+	}
+	unsigned int files_opened = 0;
+	size_t size, total_size = 0;
+	FTSENT *node;
+	while ((node = fts_read(tree)) &&
+			!(node->fts_info == FTS_ERR || node->fts_info == FTS_NS)) {
+		if (node->fts_level > 0 && node->fts_name[0] == '.') {
+			fts_set(tree, node, FTS_SKIP);
+		} else if (node->fts_info == FTS_F) {
+			dispatch_group_enter(g);
+			dispatch_semaphore_wait(s, DISPATCH_TIME_FOREVER);
+			size = node->fts_statp->st_size;
+			total_size += size;
+			files_opened++;
+			test_async_read(node->fts_path, size, option, queue, ^(size_t len){
+				OSAtomicAdd32(len, bytes);
+				dispatch_semaphore_signal(s);
+				dispatch_group_leave(g);
+			});
+		}
+	}
+	if ((!node && errno) || (node && (node->fts_info == FTS_ERR ||
+			node->fts_info == FTS_NS))) {
+		test_errno("fts_read failed", !node ? errno : node->fts_errno, 0);
+		test_stop();
+	}
+	if (fts_close(tree)) {
+		test_errno("fts_close failed", errno, 0);
+		test_stop();
+	}
+	test_group_wait(g);
+	test_long("total size", *bytes, total_size);
+	return files_opened;
+}
+
+extern __attribute__((weak_import)) void
+_dispatch_iocntl(uint32_t param, uint64_t value);
+
+enum {
+	DISPATCH_IOCNTL_CHUNK_PAGES = 1,
+	DISPATCH_IOCNTL_LOW_WATER_CHUNKS,
+	DISPATCH_IOCNTL_INITIAL_DELIVERY,
+};
+
+static void
+test_read_many_files(void)
+{
+	char *paths[] = {"/usr/lib", NULL};
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_semaphore_t s = dispatch_semaphore_create(maxopenfiles);
+	uint64_t start;
+	volatile uint32_t bytes;
+	unsigned int files_read, i;
+
+	const dispatch_queue_t queues[] = {
+		[DISPATCH_ASYNC_READ_ON_CONCURRENT_QUEUE] =
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
+		[DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE] =
+				dispatch_queue_create("read", NULL),
+		[DISPATCH_READ_ON_CONCURRENT_QUEUE] =
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
+		[DISPATCH_IO_READ_ON_CONCURRENT_QUEUE] =
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
+#if DISPATCHTEST_IO_PATH
+		[DISPATCH_IO_READ_FROM_PATH_ON_CONCURRENT_QUEUE] =
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
+#endif
+	};
+	dispatch_set_target_queue(queues[DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE],
+			dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
+	static const char *names[] = {
+		[DISPATCH_ASYNC_READ_ON_CONCURRENT_QUEUE] =
+			"dispatch_async(^{read();}) on concurrent queue",
+		[DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE] =
+			"dispatch_async(^{read();}) on serial queue",
+		[DISPATCH_READ_ON_CONCURRENT_QUEUE] =
+			"dispatch_read() on concurrent queue",
+		[DISPATCH_IO_READ_ON_CONCURRENT_QUEUE] =
+			"dispatch_io_read() on concurrent queue",
+		[DISPATCH_IO_READ_FROM_PATH_ON_CONCURRENT_QUEUE] =
+			"dispatch_io_read() from path on concurrent queue",
+	};
+
+	if (_dispatch_iocntl) {
+		const size_t chunk_pages = 3072;
+		_dispatch_iocntl(DISPATCH_IOCNTL_CHUNK_PAGES, (uint64_t)chunk_pages);
+	}
+	struct rlimit l;
+	if (!getrlimit(RLIMIT_NOFILE, &l) && l.rlim_cur < 2 * maxopenfiles + 256) {
+		l.rlim_cur = 2 * maxopenfiles + 256;
+		setrlimit(RLIMIT_NOFILE, &l);
+	}
+	for (i = 0; i < sizeof(queues)/sizeof(dispatch_queue_t); ++i) {
+		fprintf(stdout, "%s:\n", names[i]);
+		bytes = 0;
+		start = mach_absolute_time();
+		files_read = test_read_dirs(paths, queues[i], g, s, &bytes, i);
+		double elapsed = (double)(mach_absolute_time() - start) / NSEC_PER_SEC;
+		double throughput = ((double)bytes / elapsed)/(1024 * 1024);
+		fprintf(stdout, "Total Files read: %u, Total MBytes %g, "
+				"Total time: %g s, Throughput: %g MB/s\n", files_read,
+				(double)bytes / (1024 * 1024), elapsed, throughput);
+	}
+	dispatch_release(queues[DISPATCH_ASYNC_READ_ON_SERIAL_QUEUE]);
+	dispatch_release(s);
+	dispatch_release(g);
+}
+
+static void
+test_io_from_io(void) // rdar://problem/8388909
+{
+#if DISPATCH_API_VERSION >= 20101012
+	const size_t siz_in = 10240;
+	dispatch_queue_t q = dispatch_get_global_queue(0, 0);
+	char path[] = "/tmp/dispatchtest_io.XXXXXX/file.name";
+	char *tmp = strrchr(path, '/');
+	*tmp = '\0';
+	if (!mkdtemp(path)) {
+		test_ptr_notnull("mkdtemp failed", path);
+		test_stop();
+	}
+#ifdef UF_IMMUTABLE
+	// Make the directory immutable
+	if (chflags(path, UF_IMMUTABLE) == -1) {
+		test_errno("chflags", errno, 0);
+		test_stop();
+	}
+#else
+	// Make the directory non-read/writeable
+	if (chmod(path, 0) == -1) {
+		test_errno("chmod", errno, 0);
+		test_stop();
+	}
+#endif
+	*tmp = '/';
+	dispatch_io_t io = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path,
+			O_CREAT|O_RDWR, 0600, q, ^(int error) {
+				if (error) {
+					test_errno("channel cleanup called with error", error, 0);
+					test_stop();
+				}
+				test_errno("channel cleanup called", error, 0);
+			});
+
+	dispatch_group_t g = dispatch_group_create();
+	char *foo = malloc(256);
+	dispatch_data_t tdata;
+	tdata = dispatch_data_create(foo, 256, NULL, DISPATCH_DATA_DESTRUCTOR_FREE);
+	dispatch_group_enter(g);
+	dispatch_io_write(io, 0, tdata, q, ^(bool done, dispatch_data_t data_out,
+			int err_out) {
+#ifdef UF_IMMUTABLE
+		test_errno("error from write to immutable directory", err_out, EPERM);
+#else
+		test_errno("error from write to write protected directory", err_out, EACCES);
+#endif
+		test_long("unwritten data", dispatch_data_get_size(data_out), 256);
+		if (!err_out && done) {
+			test_stop();
+		}
+		if (done) {
+			dispatch_group_leave(g);
+		}
+	});
+	dispatch_release(tdata);
+	dispatch_release(io);
+	test_group_wait(g);
+	*tmp = '\0';
+#ifdef UF_IMMUTABLE
+	// Change the directory to mutable
+	if (chflags(path, 0) == -1) {
+		test_errno("chflags", errno, 0);
+		test_stop();
+	}
+#else
+	// Change the directory to user read/write/execute
+	if (chmod(path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
+		test_errno("chmod", errno, 0);
+		test_stop();
+	}
+#endif
+	const char *path_in = "/dev/urandom";
+	int in = open(path_in, O_RDONLY);
+	if (in == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+	*tmp = '/';
+	dispatch_group_enter(g);
+
+	io = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path,
+			O_CREAT|O_RDWR, 0600, q, ^(int error) {
+		if (error) {
+			test_errno("channel cleanup called with error", error, 0);
+			test_stop();
+		}
+		test_errno("channel cleanup called", error, 0);
+	});
+	dispatch_read(in, siz_in, q, ^(dispatch_data_t data_in, int err_in ) {
+		if (err_in) {
+			test_errno("dispatch_read", err_in, 0);
+			test_stop();
+		}
+		dispatch_io_write(io, 0, data_in, q,
+				^(bool done, dispatch_data_t data_out, int err_out) {
+			if (done) {
+				test_errno("dispatch_io_write", err_out, 0);
+				test_long("remaining write size",
+						data_out ? dispatch_data_get_size(data_out) : 0, 0);
+				dispatch_group_leave(g);
+			} else {
+				test_long_less_than("remaining write size",
+						dispatch_data_get_size(data_out), siz_in);
+			}
+		});
+	});
+	test_group_wait(g);
+	dispatch_io_t io2 = dispatch_io_create_with_io(DISPATCH_IO_STREAM, io, q,
+			^(int error) {
+		if (error) {
+			test_errno("dispatch_io_create_with_io", error, 0);
+			test_stop();
+		}
+	});
+	dispatch_release(io);
+	dispatch_group_enter(g);
+	__block dispatch_data_t data_out = dispatch_data_empty;
+	dispatch_io_read(io2, 0, siz_in, q,
+			^(bool done, dispatch_data_t d, int error) {
+		if (d) {
+			dispatch_data_t concat = dispatch_data_create_concat(data_out, d);
+			dispatch_release(data_out);
+			data_out = concat;
+		}
+		if (done) {
+			test_errno("read error from channel created_with_io", error, 0);
+			dispatch_group_leave(g);
+		}
+	});
+	dispatch_release(io2);
+	test_group_wait(g);
+	dispatch_release(g);
+	test_long("readback size", dispatch_data_get_size(data_out), siz_in);
+	dispatch_release(data_out);
+#endif
+}
+
+#endif // DISPATCHTEST_IO
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch IO");
+	dispatch_async(dispatch_get_main_queue(), ^{
+#if DISPATCHTEST_IO
+		int i; bool from_path = false;
+		do {
+			for (i = 0; i < 3; i++) {
+				test_io_close(i, from_path);
+			}
+#if DISPATCHTEST_IO_PATH
+			from_path = !from_path;
+#endif
+		} while (from_path);
+		test_io_stop();
+		test_io_from_io();
+		test_io_read_write();
+		test_read_many_files();
+#endif
+		test_fin(NULL);
+	});
+	dispatch_main();
+}
diff --git a/tests/dispatch_io_net.c b/tests/dispatch_io_net.c
new file mode 100644
index 0000000..4d02751
--- /dev/null
+++ b/tests/dispatch_io_net.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2010-2011 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <spawn.h>
+#ifdef __APPLE__
+#include <crt_externs.h>
+#include <mach-o/dyld.h>
+#endif
+#include <Block.h>
+#include <bsdtests.h>
+#include "dispatch_test.h"
+#include <dispatch/dispatch.h>
+
+extern char **environ;
+
+#ifndef DISPATCHTEST_IO
+#if DISPATCH_API_VERSION >= 20100226 && DISPATCH_API_VERSION != 20101110
+#define DISPATCHTEST_IO 1
+#endif
+#endif
+
+#ifdef __linux__
+#define _NSGetExecutablePath(ef,bs) (*(bs)=(size_t)snprintf(ef,*(bs),"%s",argv[0]),0)
+#endif
+
+#if DISPATCHTEST_IO
+int
+main(int argc, char** argv)
+{
+	struct hostent *he;
+	int sockfd, clientfd;
+	struct sockaddr_in addr1, addr2, server;
+	socklen_t addr2len;
+	socklen_t addr1len;
+	pid_t clientid;
+
+	const char *path = "/usr/bin/vi";
+	int read_fd, fd;
+
+	if (argc == 2) {
+		// Client
+		dispatch_test_start(NULL);
+
+		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+			test_errno("Client-socket()", errno, 0);
+			test_stop();
+		}
+
+		if ((he = gethostbyname("localhost")) == NULL) {
+			fprintf(stderr, "Client-gethostbyname() failed\n");
+			test_stop();
+		}
+
+		memcpy(&server.sin_addr, he->h_addr_list[0], (size_t)he->h_length);
+		server.sin_family = AF_INET;
+		server.sin_port = (in_port_t)atoi(argv[1]);
+
+		fprintf(stderr, "Client-connecting on port ... %d\n", server.sin_port);
+
+		if (connect(sockfd, (struct sockaddr *)&server, sizeof(server))) {
+			test_errno("client-connect()", errno, 0);
+			test_stop();
+		}
+
+		// Read from the socket and compare the contents are what we expect
+
+		fd = open(path, O_RDONLY);
+		if (fd == -1) {
+			test_errno("client-open", errno, 0);
+			test_stop();
+		}
+#ifdef F_NOCACHE
+		if (fcntl(fd, F_NOCACHE, 1)) {
+			test_errno("client-fcntl F_NOCACHE", errno, 0);
+			test_stop();
+		}
+#else
+		// investigate what the impact of lack of file cache disabling has 
+		// for this test
+#endif
+		struct stat sb;
+		if (fstat(fd, &sb)) {
+			test_errno("client-fstat", errno, 0);
+			test_stop();
+		}
+		size_t size = (size_t)sb.st_size;
+
+		__block dispatch_data_t g_d1 = dispatch_data_empty;
+		__block dispatch_data_t g_d2 = dispatch_data_empty;
+		__block int g_error = 0;
+
+		dispatch_group_t g = dispatch_group_create();
+		dispatch_group_enter(g);
+		dispatch_read(fd, size, dispatch_get_global_queue(0, 0),
+				^(dispatch_data_t d1, int error) {
+			test_errno("Client-dict-read error", error, 0);
+			test_long("Client-dict-dispatch data size",
+					  (long)dispatch_data_get_size(d1), (long)size);
+			dispatch_retain(d1);
+			g_d1 = d1;
+			dispatch_group_leave(g);
+		});
+
+		__block void (^b)(dispatch_data_t, int);
+		b = Block_copy(^(dispatch_data_t d2, int error) {
+			dispatch_data_t concat = dispatch_data_create_concat(g_d2, d2);
+			dispatch_release(g_d2);
+			g_d2 = concat;
+			if (!error && dispatch_data_get_size(d2)) {
+				dispatch_read(sockfd, SIZE_MAX,
+						dispatch_get_global_queue(0, 0), b);
+			} else {
+				g_error = error;
+				dispatch_group_leave(g);
+			}
+		});
+		dispatch_group_enter(g);
+		dispatch_read(sockfd, SIZE_MAX, dispatch_get_global_queue(0, 0), b);
+		test_group_wait(g);
+		test_errno("Client-read error", g_error, 0);
+		test_long("Client-dispatch data size", (long)dispatch_data_get_size(g_d2),
+				  (long)size);
+
+		size_t dict_contig_size, socket_contig_size;
+		const void *dict_contig_buf, *socket_contig_buf;
+		dispatch_data_t dict_data = dispatch_data_create_map(g_d1,
+				&dict_contig_buf, &dict_contig_size);
+		dispatch_data_t socket_data = dispatch_data_create_map(g_d2,
+				&socket_contig_buf, &socket_contig_size);
+		test_long("Client-dispatch data contents",
+				 memcmp(dict_contig_buf, socket_contig_buf,
+				 MIN(dict_contig_size, socket_contig_size)), 0);
+
+		close(fd);
+		close(sockfd);
+		dispatch_release(g_d1);
+		dispatch_release(g_d2);
+		dispatch_release(dict_data);
+		dispatch_release(socket_data);
+		dispatch_release(g);
+		test_stop();
+	} else {
+		// Server
+		dispatch_test_start("Dispatch IO Network test");
+
+		if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+			test_errno("Server-socket()", errno, 0);
+			test_stop();
+		}
+
+		addr1.sin_family = AF_INET;
+		addr1.sin_addr.s_addr = INADDR_ANY;
+		addr1.sin_port = 0;
+
+		if (bind(sockfd, (struct sockaddr *)&addr1, sizeof(struct sockaddr)) ==
+				-1) {
+			test_errno("Server-bind()", errno, 0);
+			test_stop();
+		}
+
+		addr1len = sizeof(struct sockaddr);
+		if (getsockname(sockfd, (struct sockaddr*)&addr1, &addr1len) == -1) {
+			test_errno("Server-getsockname()", errno, 0);
+			test_stop();
+		}
+
+		if(listen(sockfd, 3) == -1) {
+			test_errno("Server-listen()", errno, 0);
+			test_stop();
+		}
+
+		fprintf(stderr, "Server started and listening on port %d\n",
+				addr1.sin_port);
+
+		char exec_filename [256] = {};
+		size_t bufsize = 256;
+
+		if (_NSGetExecutablePath(exec_filename, &bufsize) == -1) {
+			fprintf(stderr, "Failed to get path name for running executable\n");
+			test_stop();
+		}
+
+		char port_str[10] = {};
+		snprintf(port_str, 10, " %d", addr1.sin_port);
+
+		char *arguments [3] = {};
+		arguments[0] = exec_filename;
+		arguments[1] = port_str;
+		arguments[2] = NULL;
+
+		int error;
+		if ((error = posix_spawnp(&clientid, exec_filename, NULL, NULL,
+				arguments, environ)) != 0) {
+			test_errno("Server-posix_spawnp()", error, 0);
+			test_stop();
+		}
+
+		addr2len = sizeof(struct sockaddr_in);
+		clientfd = accept(sockfd, (struct sockaddr *)&addr2, &addr2len);
+		if(clientfd == -1) {
+			test_errno("Server-accept()", errno, 0);
+			test_stop();
+		}
+
+		fprintf(stderr, "Server accepted connection. Server now writing\n");
+		read_fd = open(path, O_RDONLY);
+		if (read_fd == -1) {
+			test_errno("open", errno, 0);
+			goto stop_test;
+		}
+#ifdef F_NOCACHE
+		if (fcntl(read_fd, F_NOCACHE, 1)) {
+			test_errno("fcntl F_NOCACHE", errno, 0);
+			goto stop_test;
+		}
+#else
+		// investigate what the impact of lack of file cache disabling has 
+		// for this test
+#endif
+		struct stat sb;
+		if (fstat(read_fd, &sb)) {
+			test_errno("fstat", errno, 0);
+			goto stop_test;
+		}
+		size_t size = (size_t)sb.st_size;
+
+		dispatch_group_t g = dispatch_group_create();
+		dispatch_group_enter(g);
+		dispatch_read(read_fd, size, dispatch_get_global_queue(0, 0),
+				^(dispatch_data_t d, int r_err){
+			fprintf(stderr, "Server-dispatch_read()\n");
+			test_errno("Server-read error", r_err, 0);
+			test_long("Server-dispatch data size", (long)dispatch_data_get_size(d),
+					  (long)size);
+
+			// convenience method handlers should only be called once
+			if (dispatch_data_get_size(d)!= size) {
+				fprintf(stderr, "Reading of data didn't complete\n");
+				close(read_fd);
+				close(clientfd);
+				close(sockfd);
+				test_stop();
+			}
+			dispatch_group_enter(g);
+			dispatch_write(clientfd, d, dispatch_get_global_queue(0, 0),
+					^(dispatch_data_t remaining, int w_err) {
+				test_errno("Server-write error", w_err, 0);
+				test_ptr_null("Server-dispatch write remaining data",remaining);
+				// convenience method handlers should only be called once
+				if (remaining) {
+					fprintf(stderr, "Server-dispatch_write() incomplete .. "
+							"%zu bytes\n", dispatch_data_get_size(remaining));
+					close(read_fd);
+					close(clientfd);
+					close(sockfd);
+					test_stop();
+				}
+				close(clientfd); // Sending the client EOF
+				dispatch_group_leave(g);
+			});
+			close(read_fd);
+			dispatch_group_leave(g);
+		});
+		test_group_wait(g);
+		dispatch_release(g);
+		fprintf(stderr, "Shutting down server\n");
+		close(sockfd);
+		test_stop();
+
+stop_test:
+		close(read_fd);
+		close(clientfd);
+		close(sockfd);
+		test_stop();
+	}
+}
+#else
+int
+main()
+{
+	dispatch_test_start("Dispatch IO Network test - No Dispatch IO");
+	test_stop();
+}
+#endif
diff --git a/tests/dispatch_overcommit.c b/tests/dispatch_overcommit.c
new file mode 100644
index 0000000..c103c68
--- /dev/null
+++ b/tests/dispatch_overcommit.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+#ifdef __linux__
+// for asprintf
+#define _GNU_SOURCE 1
+#endif
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+int32_t count = 0;
+const int32_t final = 32;
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Overcommit");
+
+	int i;
+	for (i = 0; i < final; ++i) {
+		char* name;
+		asprintf(&name, "test.overcommit.%d", i);
+
+		dispatch_queue_t queue = dispatch_queue_create(name, NULL);
+		test_ptr_notnull("dispatch_queue_create", queue);
+		free(name);
+		dispatch_set_target_queue(queue, dispatch_get_global_queue(0, DISPATCH_QUEUE_OVERCOMMIT));
+
+		dispatch_async(queue, ^{
+			OSAtomicIncrement32(&count);
+			if (count == final) {
+				test_long("count", count, final);
+				test_stop();
+			} else {
+				while (1); // spin
+			}
+		});
+	}
+
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_pingpong.c b/tests/dispatch_pingpong.c
new file mode 100644
index 0000000..8664ddb
--- /dev/null
+++ b/tests/dispatch_pingpong.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdio.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+uint32_t count = 0;
+const uint32_t final = 1000000; // 10M
+
+void
+pingpongloop(dispatch_group_t group, dispatch_queue_t ping, dispatch_queue_t pong, size_t counter)
+{
+	//printf("[%p] %s: %lu\n", (void*)(uintptr_t)pthread_self(), dispatch_queue_get_label(dispatch_get_current_queue()), counter);
+	if (counter < final) {
+		dispatch_group_async(group, pong, ^{ pingpongloop(group, pong, ping, counter+1); });
+	} else {
+		count = counter;
+	}
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Ping Pong");
+
+	dispatch_queue_t ping = dispatch_queue_create("ping", NULL);
+	test_ptr_notnull("dispatch_queue_create(ping)", ping);
+	dispatch_queue_t pong = dispatch_queue_create("pong", NULL);
+	test_ptr_notnull("dispatch_queue_create(pong)", pong);
+
+	dispatch_group_t group = dispatch_group_create();
+	test_ptr_notnull("dispatch_group_create", group);
+
+	pingpongloop(group, ping, pong, 0);
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+
+	test_long("count", count, final);
+
+	dispatch_release(ping);
+	dispatch_release(pong);
+	dispatch_release(group);
+
+	test_stop();
+
+	return 0;
+}
diff --git a/tests/dispatch_plusplus.cpp b/tests/dispatch_plusplus.cpp
new file mode 100644
index 0000000..19191f3
--- /dev/null
+++ b/tests/dispatch_plusplus.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch C++");
+	dispatch_queue_t q = dispatch_get_main_queue();
+	test_ptr_notnull("dispatch_get_main_queue", q);
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+		test_stop();
+		exit(0);
+	});
+	dispatch_main();
+	return 0;
+}
diff --git a/tests/dispatch_priority.c b/tests/dispatch_priority.c
new file mode 100644
index 0000000..3cbb7d9
--- /dev/null
+++ b/tests/dispatch_priority.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2008-2011 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 <stdio.h>
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+#include <sys/types.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static volatile int done;
+
+#ifdef DISPATCH_QUEUE_PRIORITY_BACKGROUND // <rdar://problem/7439794>
+#define USE_BACKGROUND_PRIORITY 1
+#else
+#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
+#endif
+
+#define QUEUE_PRIORITY_PTHREAD INT_MAX
+
+#if DISPATCH_API_VERSION < 20100518 // <rdar://problem/7790099>
+#define DISPATCH_QUEUE_CONCURRENT NULL
+#endif
+
+#if TARGET_OS_EMBEDDED
+#define LOOP_COUNT 5000000
+const int importance = 24; // priority 55
+#else
+#define LOOP_COUNT 100000000
+const int importance = 4; // priority 35
+#endif
+
+char *labels[] = { "BACKGROUND", "LOW", "DEFAULT", "HIGH", };
+int levels[] = {
+	DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_PRIORITY_LOW,
+	DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_HIGH,
+};
+#define PRIORITIES (sizeof(levels)/sizeof(*levels))
+
+static union {
+	long count;
+	char padding[64];
+} counts[PRIORITIES];
+
+static volatile long iterations;
+static long total;
+static size_t prio0, priorities = PRIORITIES;
+
+int
+n_blocks(void)
+{
+	static dispatch_once_t pred;
+	static int n;
+	dispatch_once(&pred, ^{
+#ifdef __linux__
+		n = sysconf(_SC_NPROCESSORS_CONF);
+#else
+		size_t l = sizeof(n);
+		int rc = sysctlbyname("hw.ncpu", &n, &l, NULL, 0);
+		assert(rc == 0);
+#endif
+		n *= 32;
+	});
+	return n;
+}
+
+void
+histogram(void)
+{
+	long completed = 0;
+	size_t x, y, i;
+	printf("\n");
+	for (y = prio0; y < prio0 + priorities; ++y) {
+		printf("%s: %ld\n", labels[y], counts[y].count);
+		completed += counts[y].count;
+
+		double fraction = (double)counts[y].count / (double)n_blocks();
+		double value = fraction * (double)80;
+		for (x = 0; x < 80; ++x) {
+			printf("%s", (value > x) ? "*" : " ");
+		}
+		printf("\n");
+	}
+
+	test_long("blocks completed", completed, total);
+	for (i = prio0; i < prio0 + priorities; i++) {
+		if (levels[i] == DISPATCH_QUEUE_PRIORITY_HIGH) {
+			test_long_less_than_or_equal("high priority precedence",
+					counts[i-2].count, counts[i].count);
+		}
+#if USE_BACKGROUND_PRIORITY
+		if (levels[i] == DISPATCH_QUEUE_PRIORITY_BACKGROUND) {
+			test_long_less_than_or_equal("background priority precedence",
+					counts[i].count, counts[i+2].count);
+		}
+#endif
+	}
+}
+
+void
+cpubusy(void* context)
+{
+	if (done) return;
+	size_t idx;
+	for (idx = 0; idx < LOOP_COUNT; ++idx) {
+		if (done) break;
+	}
+
+	volatile long *count = context;
+	long iterdone = __sync_sub_and_fetch(&iterations, 1);
+
+	if (iterdone >= 0) {
+		__sync_add_and_fetch(count, 1);
+		if (!iterdone) {
+			__sync_add_and_fetch(&done, 1);
+			usleep(100000);
+			histogram();
+			dispatch_time_t delay = DISPATCH_TIME_NOW;
+			dispatch_after(delay, dispatch_get_main_queue(), ^{
+				test_stop();
+			});
+		}
+	}
+}
+
+void
+submit_work(dispatch_queue_t queue, void* context)
+{
+	int i;
+
+	for (i = n_blocks(); i; --i) {
+		dispatch_async_f(queue, context, cpubusy);
+	}
+
+}
+
+int
+main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
+{
+	dispatch_queue_t q[PRIORITIES];
+	size_t i;
+
+#if !USE_BACKGROUND_PRIORITY
+	prio0++;
+	priorities--;
+#endif
+
+	iterations = total = (priorities * n_blocks()) * 0.50;
+
+#if USE_SET_TARGET_QUEUE
+	dispatch_test_start("Dispatch Priority (Set Target Queue)");
+#else
+	dispatch_test_start("Dispatch Priority");
+#endif
+
+	for (i = prio0; i < prio0 + priorities; i++) {
+		dispatch_queue_t rq = dispatch_get_global_queue(levels[i], 0);
+#if USE_SET_TARGET_QUEUE
+		q[i] = dispatch_queue_create(labels[i], DISPATCH_QUEUE_CONCURRENT);
+		test_ptr_notnull("q[i]", q[i]);
+		assert(q[i]);
+		dispatch_suspend(q[i]);
+		dispatch_set_target_queue(q[i], rq);
+		if (DISPATCH_QUEUE_CONCURRENT != NULL) {
+			dispatch_queue_set_width(q[i], LONG_MAX);
+		}
+		dispatch_release(rq);
+#else
+		q[i] = rq;
+#endif
+	}
+
+	for (i = prio0; i < prio0 + priorities; i++) {
+		submit_work(q[i], &counts[i].count);
+	}
+
+	for (i = prio0; i < prio0 + priorities; i++) {
+		dispatch_resume(q[i]);
+		dispatch_release(q[i]);
+	}
+
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_proc.c b/tests/dispatch_proc.c
new file mode 100644
index 0000000..6c3b701
--- /dev/null
+++ b/tests/dispatch_proc.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <spawn.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define PID_CNT 5
+
+static long event_cnt;
+
+void
+test_proc(pid_t bad_pid)
+{
+	dispatch_source_t proc_s[PID_CNT], proc;
+	int res;
+	pid_t pid, monitor_pid;
+
+	event_cnt = 0;
+	// Creates a process and register multiple observers.  Send a signal,
+	// exit the process, etc., and verify all observers were notified.
+
+	posix_spawnattr_t attr;
+	res = posix_spawnattr_init(&attr);
+	assert(res == 0);
+	res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
+	assert(res == 0);
+
+	char* args[] = {
+		"/bin/sleep", "2", NULL
+	};
+
+	res = posix_spawnp(&pid, args[0], NULL, &attr, args, NULL);
+	if (res < 0) {
+		perror(args[0]);
+		exit(127);
+	}
+
+	res = posix_spawnattr_destroy(&attr);
+	assert(res == 0);
+
+	dispatch_group_t group = dispatch_group_create();
+
+	assert(pid > 0);
+	monitor_pid = bad_pid ? bad_pid : pid; // rdar://problem/8090801
+
+	int i;
+	for (i = 0; i < PID_CNT; ++i) {
+		dispatch_group_enter(group);
+		proc = proc_s[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC,
+				monitor_pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(0, 0));
+		test_ptr_notnull("dispatch_source_proc_create", proc);
+		dispatch_source_set_event_handler(proc, ^{
+			long flags = dispatch_source_get_data(proc);
+			test_long("DISPATCH_PROC_EXIT", flags, DISPATCH_PROC_EXIT);
+			event_cnt++;
+			dispatch_source_cancel(proc);
+		});
+		dispatch_source_set_cancel_handler(proc, ^{
+			dispatch_group_leave(group);
+		});
+		dispatch_resume(proc);
+	}
+	kill(pid, SIGCONT);
+	if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 10*NSEC_PER_SEC))) {
+		for (i = 0; i < PID_CNT; ++i) {
+			dispatch_source_cancel(proc_s[i]);
+		}
+		dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+	}
+	for (i = 0; i < PID_CNT; ++i) {
+		dispatch_release(proc_s[i]);
+	}
+	dispatch_release(group);
+	// delay 5 seconds to give a chance for any bugs that
+	// result in too many events to be noticed
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+		int status;
+		int res2 = waitpid(pid, &status, 0);
+		assert(res2 != -1);
+		//int passed = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
+		test_long("Sub-process exited", WEXITSTATUS(status) | WTERMSIG(status), 0);
+		test_long("Event count", event_cnt, PID_CNT);
+		if (bad_pid) {
+			test_stop();
+		} else {
+			dispatch_async(dispatch_get_main_queue(), ^{
+				test_proc(pid);
+			});
+		}
+	});
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Proc");
+	test_proc(0);
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_queue_finalizer.c b/tests/dispatch_queue_finalizer.c
new file mode 100644
index 0000000..1b190a2
--- /dev/null
+++ b/tests/dispatch_queue_finalizer.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+void *ctxt_magic = NULL;
+
+static void
+finalize(void *ctxt)
+{
+	test_ptr_null("finalizer ran", NULL);
+	test_ptr("correct context", ctxt, ctxt_magic);
+	test_stop();
+}
+
+static void
+never_call(void *ctxt)
+{
+	test_ptr_notnull("never_call should not run", NULL);
+	test_ptr("correct context", ctxt, NULL);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Queue Finalizer");
+
+#if defined(__LP64__) || defined(_WIN64)
+	ctxt_magic = (void*)((uintptr_t)arc4random() << 32 | arc4random());
+#else
+	ctxt_magic = (void*)arc4random();
+#endif
+
+	// we need a non-NULL value for the tests to work properly
+	if (ctxt_magic == NULL) {
+		ctxt_magic = &ctxt_magic;
+	}
+
+	dispatch_queue_t q = dispatch_queue_create("com.apple.testing.finalizer", NULL);
+	test_ptr_notnull("dispatch_queue_new", q);
+
+	dispatch_set_finalizer_f(q, finalize);
+
+	dispatch_queue_t q_null_context = dispatch_queue_create("com.apple.testing.finalizer.context_null", NULL);
+
+	dispatch_set_context(q_null_context, NULL);
+	dispatch_set_finalizer_f(q_null_context, never_call);
+	dispatch_release(q_null_context);
+
+	// Don't test k
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+		// Usign async to set the context helps test that blocks are
+		// run before the release as opposed to just thrown away.
+		dispatch_async(q, ^{
+			dispatch_set_context(q, ctxt_magic);
+		});
+
+		dispatch_release(q);
+	});
+
+	dispatch_main();
+	
+	return 0;
+}
diff --git a/tests/dispatch_read.c b/tests/dispatch_read.c
new file mode 100644
index 0000000..f8a576c
--- /dev/null
+++ b/tests/dispatch_read.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2008-2011 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 <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static size_t bytes_total;
+static size_t bytes_read;
+
+void
+test_fin(void *cxt)
+{
+	test_ptr("test_fin run", cxt, cxt);
+	test_stop();
+}
+
+int
+main(void)
+{
+	const char *path = "/usr/bin/vi";
+	struct stat sb;
+
+	dispatch_test_start("Dispatch Source Read");
+
+	int infd = open(path, O_RDONLY);
+	if (infd == -1) {
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+	if (fstat(infd, &sb) == -1) {
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+	bytes_total = sb.st_size;
+
+	if (fcntl(infd, F_SETFL, O_NONBLOCK) != 0) {
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!dispatch_test_check_evfilt_read_for_fd(infd)) {
+		test_skip("EVFILT_READ kevent not firing for test file");
+		test_fin(NULL);
+	}
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	test_ptr_notnull("dispatch_get_main_queue", main_q);
+
+	dispatch_source_t reader = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, infd, 0, main_q);
+	test_ptr_notnull("dispatch_source_create", reader);
+	assert(reader);
+
+	dispatch_source_set_event_handler(reader, ^{
+		size_t estimated = dispatch_source_get_data(reader);
+		fprintf(stderr, "bytes available: %zu\n", estimated);
+		test_double_less_than_or_equal("estimated", estimated, bytes_total - bytes_read);
+		const ssize_t bufsiz = 1024*500; // 500 KB buffer
+		static char buffer[1024*500];	// 500 KB buffer
+		ssize_t actual = read(infd, buffer, sizeof(buffer));
+		bytes_read += actual;
+		printf("bytes read: %zd\n", actual);
+		if (actual < bufsiz) {
+			actual = read(infd, buffer, sizeof(buffer));
+			bytes_read += actual;
+			// confirm EOF condition
+			test_long("EOF", actual, 0);
+			dispatch_source_cancel(reader);
+		}
+	});
+
+	dispatch_source_set_cancel_handler(reader, ^{
+		test_long("Bytes read", bytes_read, bytes_total);
+		int res = close(infd);
+		test_errno("close", res == -1 ? errno : 0, 0);
+		dispatch_release(reader);
+	});
+
+	dispatch_set_context(reader, reader);
+	dispatch_set_finalizer_f(reader, test_fin);
+
+	dispatch_resume(reader);
+
+	dispatch_main();
+}
diff --git a/tests/dispatch_read2.c b/tests/dispatch_read2.c
new file mode 100644
index 0000000..1bc0ef2
--- /dev/null
+++ b/tests/dispatch_read2.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2010-2011 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fts.h>
+#ifdef __APPLE__
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <libkern/OSAtomic.h>
+#include <TargetConditionals.h>
+#endif
+#include <Block.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#ifndef DISPATCHTEST_IO
+#if DISPATCH_API_VERSION >= 20100226 && DISPATCH_API_VERSION != 20101110
+#define DISPATCHTEST_IO 1
+#endif
+#endif
+
+void
+test_fin(void *cxt)
+{
+	test_ptr("test_fin run", cxt, cxt);
+	test_stop();
+}
+
+#if DISPATCHTEST_IO
+
+/*
+ Basic way of implementing dispatch_io's dispatch_read without
+ using dispatch channel api's
+ */
+static void
+dispatch_read2(dispatch_fd_t fd,
+			  size_t length,
+			  dispatch_queue_t queue,
+			  void (^handler)(dispatch_data_t d, int error))
+{
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {
+		test_errno("fcntl O_NONBLOCK", errno, 0);
+		test_stop();
+	}
+	dispatch_source_t reader = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
+			fd, 0, queue);
+	test_ptr_notnull("reader", reader);
+
+	__block size_t bytes_read = 0;
+	__block dispatch_data_t data = dispatch_data_empty;
+	__block int err = 0;
+	dispatch_source_set_event_handler(reader, ^{
+		const ssize_t bufsiz = 1024*512; // 512KB buffer
+		char *buffer = valloc(bufsiz);
+		ssize_t actual = read(fd, buffer, bufsiz);
+		if (actual == -1) {
+			err = errno;
+		}
+		if (actual > 0) {
+			bytes_read += actual;
+			dispatch_data_t tmp_data = dispatch_data_create(buffer, actual,
+					NULL, DISPATCH_DATA_DESTRUCTOR_FREE);
+			dispatch_data_t concat = dispatch_data_create_concat(data,tmp_data);
+			dispatch_release(tmp_data);
+			dispatch_release(data);
+			data = concat;
+		}
+		// If we reached EOF or we read as much we were asked to.
+		if (actual < bufsiz || bytes_read >= length) {
+			char foo[2];
+			actual = read(fd, foo, 2);
+			bytes_read += actual;
+			// confirm EOF condition
+			test_long("EOF", actual, 0);
+			dispatch_source_cancel(reader);
+		}
+	});
+
+	dispatch_source_set_cancel_handler(reader, ^{
+		dispatch_data_t d = dispatch_data_create_subrange(data, 0, length);
+		dispatch_release(data);
+		handler(d, err);
+		dispatch_release(d);
+		dispatch_release(reader);
+	});
+
+	dispatch_resume(reader);
+}
+
+static void
+test_read(void)
+{
+	const char *path = "/usr/bin/vi";
+	int fd = open(path, O_RDONLY);
+	if (fd == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+#ifdef F_NOCACHE
+	if (fcntl(fd, F_NOCACHE, 1)) {
+		test_errno("fcntl F_NOCACHE", errno, 0);
+		test_stop();
+	}
+#else
+	// investigate what the impact of lack of file cache disabling has 
+	// for this test
+#endif
+	struct stat sb;
+	if (fstat(fd, &sb)) {
+		test_errno("fstat", errno, 0);
+		test_stop();
+	}
+	size_t size = sb.st_size;
+	dispatch_group_t g = dispatch_group_create();
+	void (^b)(dispatch_data_t, int) = ^(dispatch_data_t d, int error) {
+		test_errno("read error", error, 0);
+		test_long("dispatch data size", d ? dispatch_data_get_size(d) : 0, size);
+		if (d) {
+			const void *contig_buf;
+			size_t contig_size;
+			dispatch_data_t tmp = dispatch_data_create_map(d, &contig_buf,
+					&contig_size);
+			test_long("dispatch data contig size", contig_size, size);
+			if (contig_size) {
+				// Validate the copied buffer is similar to what we expect
+				char *buf = (char*)malloc(size);
+				pread(fd, buf, size, 0);
+				test_long("dispatch data contents", memcmp(buf, contig_buf,
+						size), 0);
+				free(buf);
+			}
+			dispatch_release(tmp);
+		}
+		dispatch_group_leave(g);
+	};
+	dispatch_group_enter(g);
+	dispatch_read(fd, SIZE_MAX, dispatch_get_global_queue(0, 0), b); // rdar://problem/7795794
+	test_group_wait(g);
+	lseek(fd, 0, SEEK_SET);
+	if (dispatch_test_check_evfilt_read_for_fd(fd)) {
+		dispatch_group_enter(g);
+		dispatch_read2(fd, size, dispatch_get_global_queue(0,0), b);
+		test_group_wait(g);
+	} else {
+		test_skip("EVFILT_READ kevent not firing for test file");
+	}
+	dispatch_release(g);
+	close(fd);
+}
+
+static void
+test_read_write(void)
+{
+	const char *path_in = "/dev/urandom";
+	char path_out[] = "/tmp/dispatchtest_io.XXXXXX";
+	const size_t siz_in = 10240;
+
+	int in = open(path_in, O_RDONLY);
+	if (in == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+	int out = mkstemp(path_out);
+	if (out == -1) {
+		test_errno("mkstemp", errno, 0);
+		test_stop();
+	}
+	if (unlink(path_out) == -1) {
+		test_errno("unlink", errno, 0);
+		test_stop();
+	}
+	dispatch_queue_t q = dispatch_get_global_queue(0,0);
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_group_enter(g);
+	__block dispatch_data_t data;
+	dispatch_read(in, siz_in, q, ^(dispatch_data_t data_in, int err_in) {
+		if (err_in) {
+			test_errno("dispatch_read", err_in, 0);
+			test_stop();
+		}
+		close(in);
+		size_t siz_out = dispatch_data_get_size(data_in);
+		test_long("read size", siz_out, siz_in);
+		dispatch_retain(data_in);
+		data = data_in;
+		dispatch_write(out, data, q, ^(dispatch_data_t data_out, int err_out) {
+			if (err_out || data_out) {
+				test_errno("dispatch_write", err_out, 0);
+				test_stop();
+			}
+			lseek(out, 0, SEEK_SET);
+			dispatch_read(out, siz_out, q,
+					^(dispatch_data_t cmp, int err_cmp) {
+				if (err_cmp) {
+					test_errno("dispatch_read", err_cmp, 0);
+					test_stop();
+				}
+				close(out);
+				size_t siz_cmp = dispatch_data_get_size(cmp);
+				test_long("readback size", siz_cmp, siz_out);
+				const void *data_buf, *cmp_buf;
+				dispatch_data_t data_map, cmp_map;
+				data_map = dispatch_data_create_map(data, &data_buf, NULL);
+				cmp_map = dispatch_data_create_map(cmp, &cmp_buf, NULL);
+				test_long("readback memcmp",
+						memcmp(data_buf, cmp_buf, MIN(siz_out, siz_cmp)), 0);
+				dispatch_release(cmp_map);
+				dispatch_release(data_map);
+				dispatch_release(data);
+				dispatch_group_leave(g);
+			});
+		});
+	});
+	test_group_wait(g);
+	dispatch_release(g);
+}
+
+static void
+test_read_writes(void) // <rdar://problem/7785143>
+{
+	const char *path_in = "/dev/urandom";
+	char path_out[] = "/tmp/dispatchtest_io.XXXXXX";
+	const size_t chunks_out = 320;
+	const size_t siz_chunk = 32, siz_in = siz_chunk * chunks_out;
+
+	int in = open(path_in, O_RDONLY);
+	if (in == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+	int out = mkstemp(path_out);
+	if (out == -1) {
+		test_errno("mkstemp", errno, 0);
+		test_stop();
+	}
+	if (unlink(path_out) == -1) {
+		test_errno("unlink", errno, 0);
+		test_stop();
+	}
+	dispatch_queue_t q = dispatch_get_global_queue(0,0);
+	dispatch_group_t g = dispatch_group_create();
+	dispatch_group_enter(g);
+	__block dispatch_data_t data;
+	__block size_t siz_out;
+	dispatch_read(in, siz_in, q, ^(dispatch_data_t data_in, int err_in) {
+		if (err_in) {
+			test_errno("dispatch_read", err_in, 0);
+			test_stop();
+		}
+		close(in);
+		siz_out = dispatch_data_get_size(data_in);
+		test_long("read size", siz_out, siz_in);
+		dispatch_retain(data_in);
+		data = data_in;
+		dispatch_data_t data_chunks[chunks_out];
+		size_t i;
+		for (i = 0; i < chunks_out; i++) {
+			data_chunks[i] = dispatch_data_create_subrange(data_in,
+					i * siz_chunk, siz_chunk);
+		}
+		for (i = 0; i < chunks_out; i++) {
+			dispatch_data_t d = data_chunks[i];
+			dispatch_group_enter(g);
+			dispatch_write(out, d, q, ^(dispatch_data_t data_out,
+					int err_out) {
+				if (err_out || data_out) {
+					test_errno("dispatch_write", err_out, 0);
+					test_stop();
+				}
+				dispatch_group_leave(g);
+			});
+		}
+		for (i = 0; i < chunks_out; i++) {
+			dispatch_release(data_chunks[i]);
+		}
+		dispatch_group_leave(g);
+	});
+	test_group_wait(g);
+	dispatch_group_enter(g);
+	lseek(out, 0, SEEK_SET);
+	dispatch_read(out, siz_in, q,
+			^(dispatch_data_t cmp, int err_cmp) {
+		if (err_cmp) {
+			test_errno("dispatch_read", err_cmp, 0);
+			test_stop();
+		}
+		close(out);
+		size_t siz_cmp = dispatch_data_get_size(cmp);
+		test_long("readback size", siz_cmp, siz_out);
+		const void *data_buf, *cmp_buf;
+		dispatch_data_t data_map, cmp_map;
+		data_map = dispatch_data_create_map(data, &data_buf, NULL);
+		cmp_map = dispatch_data_create_map(cmp, &cmp_buf, NULL);
+		test_long("readback memcmp",
+				memcmp(data_buf, cmp_buf, MIN(siz_out, siz_cmp)), 0);
+		dispatch_release(cmp_map);
+		dispatch_release(data_map);
+		dispatch_release(data);
+		dispatch_group_leave(g);
+	});
+	test_group_wait(g);
+	dispatch_release(g);
+}
+
+static void
+test_writes_reads_eagain(void) // rdar://problem/8333366
+{
+	int in = open("/dev/urandom", O_RDONLY);
+	if (in == -1) {
+		test_errno("open", errno, 0);
+		test_stop();
+	}
+	int fds[2], *fd = fds;
+	if(pipe(fd) == -1) {
+		test_errno("pipe", errno, 0);
+		test_stop();
+	}
+	const size_t chunks = 320;
+	const size_t siz_chunk = 32, siz = siz_chunk * chunks;
+
+	dispatch_queue_t q = dispatch_get_global_queue(0,0);
+	dispatch_group_t g = dispatch_group_create();
+	__block size_t siz_acc = 0, deliveries = 0;
+	__block void (^b)(dispatch_data_t, int);
+	b = Block_copy(^(dispatch_data_t data, int err) {
+		if (err) {
+			test_errno("dispatch_read", err, 0);
+			test_stop();
+		}
+		deliveries++;
+		siz_acc += dispatch_data_get_size(data);
+		if (siz_acc < siz) {
+			dispatch_group_enter(g);
+			dispatch_read(*fd, siz, q, b);
+		}
+		dispatch_group_leave(g);
+	});
+	dispatch_group_enter(g);
+	dispatch_read(*fd, siz, q, b);
+	char *buf[siz_chunk];
+	size_t i;
+	for (i = 0; i < chunks; i++) {
+		ssize_t s = read(in, buf, siz_chunk);
+		if (s < (ssize_t)siz_chunk) {
+			test_errno("read", errno, 0);
+			test_stop();
+		}
+		s = write(*(fd+1), buf, siz_chunk);
+		if (s < (ssize_t)siz_chunk) {
+			test_errno("write", errno, 0);
+			test_stop();
+		}
+		usleep(10000);
+	}
+	close(in);
+	close(*(fd+1));
+	test_group_wait(g);
+	test_long("dispatch_read deliveries", deliveries, chunks);
+	test_long("dispatch_read data size", siz_acc, siz);
+	close(*fd);
+	Block_release(b);
+	dispatch_release(g);
+}
+
+#endif // DISPATCHTEST_IO
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch IO Convenience Read/Write");
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+#if DISPATCHTEST_IO
+		test_read();
+		test_read_write();
+		test_read_writes();
+		test_writes_reads_eagain();
+#endif
+		test_fin(NULL);
+	});
+	dispatch_main();
+}
diff --git a/tests/dispatch_readsync.c b/tests/dispatch_readsync.c
new file mode 100644
index 0000000..207e60f
--- /dev/null
+++ b/tests/dispatch_readsync.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+#include <assert.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define LAPS 10000
+#define INTERVAL 100
+
+#if TARGET_OS_EMBEDDED
+#define BUSY 10000
+#define NTHREADS 16
+#else
+#define BUSY 1000000
+#define NTHREADS 64
+#endif
+
+static dispatch_group_t g;
+static volatile size_t r_count, w_count, workers, readers, writers, crw, count, drain;
+
+static void
+writer(void *ctxt)
+{
+	size_t w = __sync_add_and_fetch(&writers, 1), *m = (size_t *)ctxt;
+	if (w > *m) *m = w;
+
+	usleep(10000);
+	size_t busy = BUSY;
+	while (busy--) if (readers) __sync_add_and_fetch(&crw, 1);
+
+	if (__sync_sub_and_fetch(&w_count, 1) == 0) {
+		if (r_count == 0) {
+			dispatch_async(dispatch_get_main_queue(), ^{test_stop();});
+		}
+	}
+	__sync_sub_and_fetch(&writers, 1);
+	dispatch_group_leave(g);
+}
+
+static void
+reader(void *ctxt)
+{
+	size_t r = __sync_add_and_fetch(&readers, 1), *m = (size_t *)ctxt;
+	if (r > *m) *m = r;
+
+	usleep(10000);
+	size_t busy = BUSY;
+	while (busy--) if (writers) __sync_add_and_fetch(&crw, 1);
+
+	if (__sync_sub_and_fetch(&r_count, 1) == 0) {
+		if (r_count == 0) {
+			dispatch_async(dispatch_get_main_queue(), ^{test_stop();});
+		}
+	}
+	__sync_sub_and_fetch(&readers, 1);
+}
+
+static void
+test_readsync(dispatch_queue_t rq, dispatch_queue_t wq, size_t n)
+{
+	size_t i, max_readers = 0, max_writers = 0;
+	size_t *mrs = calloc(n, sizeof(size_t)), *mr, *mw = &max_writers;
+
+	r_count = LAPS * 2;
+	w_count = LAPS / INTERVAL;
+	workers = readers = writers = crw = count = 0;
+
+	for (i = 0, mr = mrs; i < n; i++, mr++) {
+		dispatch_group_async(g,
+				dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,
+				DISPATCH_QUEUE_OVERCOMMIT), ^{
+			__sync_add_and_fetch(&workers, 1);
+			do {
+				usleep(100000);
+			} while (workers < n);
+			for (;;) {
+				size_t idx = __sync_add_and_fetch(&count, 1);
+				if (idx > LAPS) break;
+				dispatch_sync_f(rq, mr, reader);
+				if (!(idx % INTERVAL)) {
+					dispatch_group_enter(g);
+					dispatch_barrier_async_f(wq, mw, writer);
+				}
+				dispatch_sync_f(rq, mr, reader);
+				if (!(idx % (INTERVAL*10))) {
+					// Let the queue drain
+					__sync_add_and_fetch(&drain, 1);
+					usleep(10000);
+					dispatch_barrier_sync(wq, ^{});
+					__sync_sub_and_fetch(&drain, 1);
+				} else while (drain) usleep(1000);
+			}
+		});
+	}
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+	for (i = 0, mr = mrs; i < n; i++, mr++) {
+		if (*mr > max_readers) max_readers = *mr;
+	}
+	free(mrs);
+
+	test_long("max readers", max_readers, n);
+	test_long("max writers", max_writers, 1);
+	test_long("concurrent readers & writers", crw, 0);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Reader/Writer Queues");
+
+	uint32_t activecpu, wq_max_threads;
+#ifdef __linux__
+	activecpu = sysconf(_SC_NPROCESSORS_ONLN);
+	// don't want to parse /proc/sys/kernel/threads-max
+	wq_max_threads = activecpu * NTHREADS + 2;
+#else
+	size_t s = sizeof(uint32_t);
+	sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0);
+	s = sizeof(uint32_t);
+	sysctlbyname("kern.wq_max_threads", &wq_max_threads, &s, NULL, 0);
+#endif
+
+	// cap at wq_max_threads - one wq thread for dq - one wq thread for manager
+	size_t n = MIN(activecpu * NTHREADS, wq_max_threads - 2);
+
+	g = dispatch_group_create();
+	dispatch_queue_attr_t qattr = NULL;
+#if DISPATCH_API_VERSION >= 20100518 // rdar://problem/7790099
+	qattr = DISPATCH_QUEUE_CONCURRENT;
+#endif
+	dispatch_queue_t dq = dispatch_queue_create("readsync", qattr);
+	assert(dq);
+	if (!qattr) {
+		dispatch_queue_set_width(dq, LONG_MAX); // rdar://problem/7919264
+		dispatch_barrier_sync(dq, ^{}); // wait for changes to take effect
+	}
+	test_readsync(dq, dq, n);
+
+	dispatch_queue_t tq = dispatch_queue_create("writebarrierasync", qattr);
+	assert(tq);
+	if (!qattr) {
+		dispatch_queue_set_width(tq, LONG_MAX);
+	}
+	dispatch_set_target_queue(dq, tq);
+	dispatch_barrier_sync(tq, ^{}); // wait for changes to take effect
+	test_readsync(dq, tq, n); // rdar://problem/8186485
+	dispatch_release(tq);
+
+	dispatch_release(dq);
+	dispatch_release(g);
+	dispatch_main();
+}
diff --git a/tests/dispatch_select.c b/tests/dispatch_select.c
new file mode 100644
index 0000000..2ec1c89
--- /dev/null
+++ b/tests/dispatch_select.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2010-2011 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 <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dispatch/dispatch.h>
+
+#include "dispatch_test.h"
+#include <bsdtests.h>
+
+static ssize_t actual;
+
+void stage1(int stage);
+void stage2(void);
+void finish(void* cxt);
+
+void
+stage1(int stage)
+{
+	const char *path = "/dev/random";
+
+	int fd = open(path, O_RDONLY);
+	if (fd == -1)
+	{
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	test_ptr_notnull("main_q", main_q);
+
+	dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, main_q);
+	test_ptr_notnull("select source", source);
+
+	dispatch_source_set_event_handler(source, ^{
+		size_t buffer_size = 500*1024;
+		char buffer[500*1024];
+		ssize_t sz = read(fd, buffer, buffer_size);
+		test_double_less_than_or_equal("kevent read 1", sz, buffer_size+1);
+		dispatch_source_cancel(source);
+	});
+
+	dispatch_source_set_cancel_handler(source, ^{
+		int res = close(fd);
+		test_errno("close", res ==  -1 ? errno : 0, 0);
+		dispatch_release(source);
+		if (stage == 1)
+		{
+			dispatch_async(dispatch_get_main_queue(), ^{
+				stage2();
+			});
+		}
+	});
+
+	if (stage == 3)
+	{
+		dispatch_set_context(source, source);
+		dispatch_set_finalizer_f(source, finish);
+	}
+
+	dispatch_resume(source);
+}
+
+void
+stage2(void)
+{
+	const char *path = "/usr/bin/vi";
+	struct stat sb;
+
+	int fd = open(path, O_RDONLY);
+	if (fd == -1)
+	{
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!dispatch_test_check_evfilt_read_for_fd(fd)) {
+		test_skip("EVFILT_READ kevent not firing for test file");
+		close(fd);
+		dispatch_async(dispatch_get_main_queue(), ^{
+			stage1(3);
+		});
+		return;
+	}
+
+	if (fstat(fd, &sb) == -1)
+	{
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+
+	ssize_t expected = sb.st_size;
+	actual = 0;
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	test_ptr_notnull("main_q", main_q);
+
+	dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, main_q);
+	test_ptr_notnull("kevent source", source);
+
+	dispatch_source_set_event_handler(source, ^{
+		size_t est = dispatch_source_get_data(source);
+		test_double_less_than_or_equal("estimated", est, expected - actual);
+		char buffer[500*1024];
+		ssize_t sz = read(fd, buffer, sizeof(buffer));
+		actual += sz;
+		if (sz < (ssize_t)sizeof(buffer))
+		{
+			sz = read(fd, buffer, sizeof(buffer));
+			actual += sz;
+			test_long("EOF", sz, 0);
+			dispatch_source_cancel(source);
+		}
+	});
+
+	dispatch_source_set_cancel_handler(source, ^{
+		test_long("bytes read", actual, expected);
+		int res = close(fd);
+		test_errno("close", res ==  -1 ? errno : 0, 0);
+		dispatch_release(source);
+		dispatch_async(dispatch_get_main_queue(), ^{
+			stage1(3);
+		});
+	});
+
+	dispatch_resume(source);
+}
+
+void
+finish(void* cxt)
+{
+	test_ptr("finish", cxt, cxt);
+	test_stop();
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch select workaround test"); // <rdar://problem/7678012>
+
+	dispatch_async(dispatch_get_main_queue(), ^{
+		stage1(1);
+	});
+
+	dispatch_main();
+}
diff --git a/tests/dispatch_sema.c b/tests/dispatch_sema.c
new file mode 100644
index 0000000..f428472
--- /dev/null
+++ b/tests/dispatch_sema.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008-2011 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 <dispatch/dispatch.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define LAPS 10000
+
+int
+main(void)
+{
+	static long total;
+	dispatch_semaphore_t dsema;
+
+	dispatch_test_start("Dispatch Semaphore");
+
+	dsema = dispatch_semaphore_create(1);
+	assert(dsema);
+
+	dispatch_apply(LAPS, dispatch_get_global_queue(0, 0), ^(size_t idx __attribute__((unused))) {
+		dispatch_semaphore_wait(dsema, DISPATCH_TIME_FOREVER);
+		total++;
+		dispatch_semaphore_signal(dsema);
+	});
+
+	dispatch_release(dsema);
+
+	test_long("count", total, LAPS);
+	test_stop();
+
+	return 0;
+}
diff --git a/tests/dispatch_starfish.c b/tests/dispatch_starfish.c
new file mode 100644
index 0000000..3609f71
--- /dev/null
+++ b/tests/dispatch_starfish.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+#include <dispatch/dispatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define COUNT	1000ul
+#define LAPS	10ul
+
+#if LENIENT_DEADLINES
+#define ACCEPTABLE_LATENCY 10000
+#elif TARGET_OS_EMBEDDED
+#define ACCEPTABLE_LATENCY 3000
+#else
+#define ACCEPTABLE_LATENCY 1000
+#endif
+
+static dispatch_queue_t queues[COUNT];
+static size_t lap_count_down = LAPS;
+static size_t count_down;
+static uint64_t start;
+static mach_timebase_info_data_t tbi;
+
+static void do_test(void);
+
+static void
+collect(void *context __attribute__((unused)))
+{
+	uint64_t delta;
+	long double math;
+	size_t i;
+
+	if (--count_down) {
+		return;
+	}
+
+	delta = mach_absolute_time() - start;
+	delta *= tbi.numer;
+	delta /= tbi.denom;
+	math = delta;
+	math /= COUNT * COUNT * 2ul + COUNT * 2ul;
+
+	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);
+
+	for (i = 0; i < COUNT; i++) {
+		dispatch_release(queues[i]);
+	}
+
+	// our malloc could be a lot better,
+	// this result is really a malloc torture test
+	test_long_less_than("Latency" , (long)math, ACCEPTABLE_LATENCY);
+
+	if (--lap_count_down) {
+		return do_test();
+	}
+
+	// give the threads some time to settle before test_stop() runs "leaks"
+	// ...also note, this is a total cheat.   dispatch_after lets this
+	// thread go idle, so dispatch cleans up the continuations cache.
+	// Doign the "old style" sleep left that stuff around and leaks
+	// took a LONG TIME to complete.   Long enough that the test harness
+	// decided to kill us.
+	dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), NULL, test_stop_after_delay);
+}
+
+static void
+pong(void *context)
+{
+	dispatch_queue_t this_q = context;
+	size_t replies = (size_t)dispatch_get_context(this_q);
+
+	dispatch_set_context(this_q, (void *)--replies);
+	if (!replies) {
+		//printf("collect from: %s\n", dispatch_queue_get_label(dispatch_get_current_queue()));
+		dispatch_async_f(dispatch_get_main_queue(), NULL, collect);
+	}
+}
+
+static void
+ping(void *context)
+{
+	dispatch_queue_t reply_q = context;
+
+	dispatch_async_f(reply_q, reply_q, pong);
+}
+
+static void
+start_node(void *context)
+{
+	dispatch_queue_t this_q = context;
+	size_t i;
+
+	dispatch_set_context(this_q, (void *)COUNT);
+
+	for (i = 0; i < COUNT; i++) {
+		dispatch_async_f(queues[i], this_q, ping);
+	}
+}
+
+void
+do_test(void)
+{
+	dispatch_queue_t soup = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
+	kern_return_t kr;
+	char buf[1000];
+	size_t i;
+
+	count_down = COUNT;
+
+	kr = mach_timebase_info(&tbi);
+	assert(kr == 0);
+
+	start = mach_absolute_time();
+
+	for (i = 0; i < COUNT; 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);
+	}
+
+	for (i = 0; i < COUNT; i++) {
+		dispatch_async_f(queues[i], queues[i], start_node);
+	}
+
+	for (i = 0; i < COUNT; i++) {
+		dispatch_resume(queues[i]);
+	}
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Starfish");
+
+	do_test();
+
+	dispatch_main();
+}
diff --git a/tests/dispatch_suspend_timer.c b/tests/dispatch_suspend_timer.c
new file mode 100644
index 0000000..566b039
--- /dev/null
+++ b/tests/dispatch_suspend_timer.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008-2011 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+dispatch_source_t tweedledee;
+dispatch_source_t tweedledum;
+
+void
+fini(void *cxt)
+{
+	test_ptr_notnull("finalizer ran", cxt);
+	if (cxt == tweedledum) {
+		test_stop();
+	}
+}
+
+void
+test_timer(void)
+{
+	dispatch_test_start("Dispatch Suspend Timer");
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
+
+	__block int i = 0, i_prime = 0;
+	__block int j = 0;
+
+	tweedledee = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	test_ptr_notnull("dispatch_source_timer_create", tweedledee);
+
+	dispatch_source_set_timer(tweedledee, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), NSEC_PER_SEC, 0);
+
+	dispatch_source_set_cancel_handler(tweedledee, ^{
+		dispatch_release(tweedledee);
+	});
+
+	dispatch_source_set_event_handler(tweedledee, ^{
+		i_prime += dispatch_source_get_data(tweedledee);
+		fprintf(stderr, "tweedledee %d (%d)\n", ++i, i_prime);
+		if (i == 10) {
+			dispatch_source_cancel(tweedledee);
+		}
+	});
+
+	dispatch_set_context(tweedledee, tweedledee);
+	dispatch_set_finalizer_f(tweedledee, fini);
+	dispatch_resume(tweedledee);
+
+	tweedledum = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	test_ptr_notnull("dispatch_source_timer_create", tweedledum);
+
+	dispatch_source_set_timer(tweedledum, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC + NSEC_PER_SEC / 2), 3 * NSEC_PER_SEC, 0);
+
+	dispatch_source_set_cancel_handler(tweedledum, ^{
+		dispatch_release(tweedledum);
+	});
+
+	dispatch_source_set_event_handler(tweedledum, ^{
+		switch(++j) {
+			case 1:
+				fprintf(stderr, "suspending timer for 3 seconds\n");
+				dispatch_suspend(tweedledee);
+				break;
+			case 2:
+				fprintf(stderr, "resuming timer\n");
+				test_long("tweedledee tick count", i, 3);
+				test_long("tweedledee virtual tick count", i_prime, 3);
+				dispatch_resume(tweedledee);
+				break;
+			default:
+				test_long("tweedledee tick count", i, 7);
+				test_long("tweedledee virtual tick count", i_prime, 9);
+				dispatch_source_cancel(tweedledum);
+				break;
+		}
+	});
+
+	dispatch_set_context(tweedledum, tweedledum);
+	dispatch_set_finalizer_f(tweedledum, fini);
+	dispatch_resume(tweedledum);
+}
+
+int
+main(void)
+{
+	test_timer();
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_sync_on_main.c b/tests/dispatch_sync_on_main.c
new file mode 100644
index 0000000..227120c
--- /dev/null
+++ b/tests/dispatch_sync_on_main.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009-2011 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 <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+const int32_t final = 10;
+int global_count = 0;
+
+static void
+work(void* ctxt __attribute__((unused)))
+{
+	if (global_count == INT_MAX) {
+		test_stop();
+	}
+	printf("Firing timer on main %d\n", ++global_count);
+	dispatch_after_f(dispatch_time(0, 100000*NSEC_PER_USEC),
+			dispatch_get_main_queue(), NULL, work);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Sync on main"); // <rdar://problem/7181849>
+
+	dispatch_queue_t dq = dispatch_queue_create("foo.bar", NULL);
+	dispatch_async(dq, ^{
+		dispatch_async_f(dispatch_get_main_queue(), NULL, work);
+		int i;
+		for (i=0; i<final; ++i) {
+			dispatch_sync(dispatch_get_main_queue(), ^{
+				printf("Calling sync %d\n", i);
+				test_long("sync on main", pthread_main_np(), 1);
+				if (i == final-1) {
+					global_count = INT_MAX;
+				}
+			});
+			const struct timespec t = {.tv_nsec = 50000*NSEC_PER_USEC};
+			nanosleep(&t, NULL);
+		}
+	});
+	dispatch_release(dq);
+
+	CFRunLoopRun();
+	return 0;
+}
diff --git a/tests/dispatch_test.c b/tests/dispatch_test.c
new file mode 100644
index 0000000..a8f40d2
--- /dev/null
+++ b/tests/dispatch_test.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2008-2011 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 "dispatch_test.h"
+#include "bsdtests.h"
+
+#ifdef __OBJC_GC__
+#include <objc/objc-auto.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#if __has_include(<sys/event.h>)
+#define HAS_SYS_EVENT_H 1
+#include <sys/event.h>
+#else
+#include <sys/poll.h>
+#endif
+#include <assert.h>
+
+#include <dispatch/dispatch.h>
+
+void test_start(const char* desc);
+
+void
+dispatch_test_start(const char* desc)
+{
+#if defined(__OBJC_GC__) && MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+	objc_startCollectorThread();
+#endif
+	test_start(desc);
+}
+
+bool
+dispatch_test_check_evfilt_read_for_fd(int fd)
+{
+#if HAS_SYS_EVENT_H
+	int kq = kqueue();
+	assert(kq != -1);
+	struct kevent ke = {
+		.ident = fd,
+		.filter = EVFILT_READ,
+		.flags = EV_ADD|EV_ENABLE,
+	};
+	struct timespec t = {
+		.tv_sec = 1,
+	};
+	int r = kevent(kq, &ke, 1, &ke, 1, &t);
+	close(kq);
+	return r > 0;
+#else
+	struct pollfd pfd = {
+		.fd = fd,
+		.events = POLLIN,
+	};
+	int rc;
+	do {
+		rc = poll(&pfd, 1, 0);
+	} while (rc == -1 && errno == EINTR);
+	assert(rc != -1);
+	return rc == 1;
+#endif
+}
+
+void
+_dispatch_test_current(const char* file, long line, const char* desc, dispatch_queue_t expected)
+{
+	dispatch_queue_t actual = dispatch_get_current_queue();
+	_test_ptr(file, line, desc, actual, expected);
+}
diff --git a/tests/dispatch_test.h b/tests/dispatch_test.h
new file mode 100644
index 0000000..392b7f9
--- /dev/null
+++ b/tests/dispatch_test.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008-2011 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 <sys/cdefs.h>
+#include <stdbool.h>
+#include <dispatch/dispatch.h>
+
+#ifdef __linux__
+#include <linux_port.h>
+#endif
+
+#define test_group_wait(g) do { \
+	if (dispatch_group_wait(g, dispatch_time(DISPATCH_TIME_NOW, \
+			25ull * NSEC_PER_SEC))) { \
+		test_long("group wait timed out", 1, 0); \
+		test_stop(); \
+	} } while (0)
+
+__BEGIN_DECLS
+
+void dispatch_test_start(const char* desc);
+
+bool dispatch_test_check_evfilt_read_for_fd(int fd);
+
+void _dispatch_test_current(const char* file, long line, const char* desc, dispatch_queue_t expected);
+#define dispatch_test_current(a,b) _dispatch_test_current(__SOURCE_FILE__, __LINE__, a, b)
+
+#ifndef __linux__
+int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
+		size_t *newpl);
+#endif
+
+__END_DECLS
diff --git a/tests/dispatch_timer.c b/tests/dispatch_timer.c
new file mode 100644
index 0000000..aeb91b2
--- /dev/null
+++ b/tests/dispatch_timer.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2008-2011 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 <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static bool finalized = false;
+
+static void
+test_fin(void *cxt)
+{
+	test_ptr("finalizer ran", cxt, cxt);
+	finalized = true;
+	test_stop();
+}
+
+static void
+test_timer(void)
+{
+	dispatch_test_start("Dispatch Source Timer");
+
+	const int stop_at = 3;
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
+
+	int64_t j;
+
+	// create timers in two classes:
+	//  * ones that should trigger before the test ends
+	//  * ones that shouldn't trigger before the test ends
+	for (j = 1; j <= 5; ++j)
+	{
+		dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
+		test_ptr_notnull("dispatch_source_create", s);
+
+		int64_t delta = (int64_t)((uint64_t)j * NSEC_PER_SEC + NSEC_PER_SEC / 10);
+		dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, delta), DISPATCH_TIME_FOREVER, 0);
+
+		dispatch_source_set_event_handler(s, ^{
+			if (!finalized) {
+				test_long_less_than("timer number", j, stop_at);
+				fprintf(stderr, "timer[%lu]\n", j);
+			}
+			dispatch_release(s);
+		});
+		dispatch_resume(s);
+	}
+
+	__block int i = 0;
+
+	dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	test_ptr_notnull("dispatch_source_create", s);
+
+	dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC, 0);
+
+	dispatch_source_set_cancel_handler(s, ^{
+		test_ptr_notnull("cancel handler run", s);
+		dispatch_release(s);
+	});
+
+	dispatch_source_set_event_handler(s, ^{
+		fprintf(stderr, "%d\n", ++i);
+		if (i >= stop_at) {
+			test_long("i", i, stop_at);
+			dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0),
+					DISPATCH_TIME_FOREVER, 0);
+			dispatch_source_cancel(s);
+		}
+	});
+
+	dispatch_set_context(s, s);
+	dispatch_set_finalizer_f(s, test_fin);
+
+	dispatch_resume(s);
+}
+
+int
+main(void)
+{
+	test_timer();
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_timer_bit31.c b/tests/dispatch_timer_bit31.c
new file mode 100644
index 0000000..eed17ae
--- /dev/null
+++ b/tests/dispatch_timer_bit31.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2008-2011 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static void
+test_timer(void)
+{
+	dispatch_test_start("Dispatch Source Timer, bit 31");
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
+
+	struct timeval start_time;
+
+	static dispatch_source_t s;
+	s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	test_ptr_notnull("dispatch_source_create", s);
+	dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0x80000000ull), 0x80000000ull, 0);
+	gettimeofday(&start_time, NULL);
+
+	dispatch_source_set_event_handler(s, ^{
+		dispatch_source_cancel(s);
+	});
+
+	dispatch_source_set_cancel_handler(s, ^{
+		struct timeval end_time;
+		gettimeofday(&end_time, NULL);
+		// check, s/b 2.0799... seconds, which is <4 seconds
+		// when it could end on a bad boundry.
+		test_long_less_than("needs to finish faster than 4 seconds", end_time.tv_sec - start_time.tv_sec, 4);
+		// And it has to take at least two seconds...
+		test_long_less_than("can't finish faster than 2 seconds", 1, end_time.tv_sec - start_time.tv_sec);
+		test_stop();
+	});
+
+	dispatch_resume(s);
+}
+
+int
+main(void)
+{
+	test_timer();
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_timer_bit63.c b/tests/dispatch_timer_bit63.c
new file mode 100644
index 0000000..84868ca
--- /dev/null
+++ b/tests/dispatch_timer_bit63.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008-2011 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static void
+test_timer(void)
+{
+	dispatch_test_start("Dispatch Source Timer, bit 63");
+
+	//uint64_t interval = 0xffffffffffffffffull;
+	uint64_t interval = 0x8000000000000001ull;
+
+	dispatch_queue_t mainq = dispatch_get_main_queue();
+
+	__block int i = 0;
+	struct timeval start_time;
+
+	gettimeofday(&start_time, NULL);
+
+	static dispatch_source_t ds;
+	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, mainq);
+	assert(ds);
+	dispatch_source_set_event_handler(ds, ^{
+		assert(i < 1);
+		printf("%d\n", i++);
+	});
+	dispatch_source_set_timer(ds, DISPATCH_TIME_NOW, interval, 0);
+	dispatch_resume(ds);
+
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC),
+		dispatch_get_main_queue(), ^{
+		test_stop();
+	});
+}
+
+int
+main(void)
+{
+	test_timer();
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_timer_set_time.c b/tests/dispatch_timer_set_time.c
new file mode 100644
index 0000000..5ffd63e
--- /dev/null
+++ b/tests/dispatch_timer_set_time.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008-2011 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 <sys/time.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+static void
+test_timer(void)
+{
+	dispatch_test_start("Dispatch Update Timer");
+
+	dispatch_queue_t main_q = dispatch_get_main_queue();
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
+
+	__block int i = 0;
+	struct timeval start_time;
+
+	gettimeofday(&start_time, NULL);
+
+	dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
+	test_ptr_notnull("dispatch_source_create", s);
+
+	dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), NSEC_PER_SEC, 0);
+
+	dispatch_source_set_cancel_handler(s, ^{
+		struct timeval end_time;
+		gettimeofday(&end_time, NULL);
+		// Make sure we actually managed to adjust the interval
+		// duration.  Fifteen one second ticks would blow past
+		// this.
+		test_long_less_than("total duration", end_time.tv_sec - start_time.tv_sec, 10);
+		test_stop();
+
+		dispatch_release(s);
+	});
+
+	dispatch_source_set_event_handler(s, ^{
+		fprintf(stderr, "%d\n", ++i);
+		if (i >= 15) {
+			dispatch_source_cancel(s);
+		} else if (i == 1) {
+			dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 10, 0);
+		}
+	});
+	test_ptr_notnull("dispatch_source_timer_create", s);
+
+	dispatch_resume(s);
+}
+
+int
+main(void) {
+	test_timer();
+	dispatch_main();
+
+	return 0;
+}
diff --git a/tests/dispatch_timer_short.c b/tests/dispatch_timer_short.c
new file mode 100644
index 0000000..da17775
--- /dev/null
+++ b/tests/dispatch_timer_short.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2010-2011 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 <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#include <libkern/OSAtomic.h>
+#endif
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define delay (1ull * NSEC_PER_SEC)
+#define interval (5ull * NSEC_PER_USEC)
+
+#define N 25000
+
+static dispatch_source_t t[N];
+static dispatch_queue_t q;
+static dispatch_group_t g;
+
+static volatile int32_t count;
+static mach_timebase_info_data_t tbi;
+static uint64_t start, last;
+
+#define elapsed_ms(x) (((now-(x))*tbi.numer/tbi.denom)/(1000ull*NSEC_PER_USEC))
+
+static
+void
+test_fin(void *cxt)
+{
+	unsigned long finalCount = (unsigned long)count;
+	fprintf(stderr, "Called back every %llu us on average\n",
+			(delay/finalCount)/NSEC_PER_USEC);
+	test_long_less_than("Frequency", 1, (long)ceil((double)delay/(finalCount*interval)));
+	int i;
+	for (i = 0; i < N; i++) {
+		dispatch_source_cancel(t[i]);
+		dispatch_release(t[i]);
+	}
+	dispatch_resume(q);
+	dispatch_release(q);
+	dispatch_release(g);
+	test_ptr("finalizer ran", cxt, cxt);
+	test_stop();
+}
+
+static
+void
+test_short_timer(void)
+{
+	// Add a large number of timers with suspended target queue in front of
+	// the timer being measured <rdar://problem/7401353>
+	g = dispatch_group_create();
+	q = dispatch_queue_create("q", NULL);
+	int i;
+	for (i = 0; i < N; i++) {
+		t[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q);
+		dispatch_source_set_timer(t[i], DISPATCH_TIME_NOW, interval, 0);
+		dispatch_group_enter(g);
+		dispatch_source_set_registration_handler(t[i], ^{
+			dispatch_suspend(t[i]);
+			dispatch_group_leave(g);
+		});
+		dispatch_resume(t[i]);
+	}
+	// Wait for registration & configuration of all timers
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+	dispatch_suspend(q);
+	for (i = 0; i < N; i++) {
+		dispatch_resume(t[i]);
+	}
+
+	dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
+			0, 0, dispatch_get_global_queue(0, 0));
+	test_ptr_notnull("dispatch_source_create", s);
+	dispatch_source_set_timer(s, DISPATCH_TIME_NOW, interval, 0);
+	dispatch_source_set_event_handler(s, ^{
+		uint64_t now = mach_absolute_time();
+		if (!count) {
+			dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay),
+					dispatch_get_global_queue(0, 0), ^{
+				dispatch_source_cancel(s);
+				dispatch_release(s);
+			});
+			fprintf(stderr, "First timer callback  (after %4llu ms)\n",
+					elapsed_ms(start));
+		}
+		OSAtomicIncrement32(&count);
+		if (elapsed_ms(last) >= 100) {
+			fprintf(stderr, "%5d timer callbacks (after %4llu ms)\n", count,
+					elapsed_ms(start));
+			last = now;
+		}
+	});
+	dispatch_set_context(s, s);
+	dispatch_set_finalizer_f(s, test_fin);
+	fprintf(stderr, "Scheduling %llu us timer\n", interval/NSEC_PER_USEC);
+	start = last = mach_absolute_time();
+	dispatch_resume(s);
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Short Timer"); // <rdar://problem/7765184>
+	mach_timebase_info(&tbi);
+	test_short_timer();
+	dispatch_main();
+	return 0;
+}
diff --git a/tests/dispatch_timer_timeout.c b/tests/dispatch_timer_timeout.c
new file mode 100644
index 0000000..f43409e
--- /dev/null
+++ b/tests/dispatch_timer_timeout.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010-2011 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch Source Timeout"); // <rdar://problem/8015967>
+
+	uint64_t mini_interval = 100ull; // 100 ns
+	uint64_t long_interval = 2000000000ull; // 2 secs
+
+	dispatch_queue_t timer_queue = dispatch_queue_create("timer_queue", NULL);
+
+	__block int value_to_be_changed = 5;
+	__block int fired = 0;
+
+	dispatch_source_t mini_timer, long_timer;
+	mini_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer_queue);
+	dispatch_source_set_event_handler(mini_timer, ^{
+		printf("Firing mini-timer %d\n", ++fired);
+		printf("Suspending mini-timer queue\n");
+		dispatch_suspend(timer_queue);
+	});
+	dispatch_source_set_timer(mini_timer, DISPATCH_TIME_NOW, mini_interval, 0);
+
+	long_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
+	dispatch_source_set_event_handler(long_timer, ^{
+		printf("Firing long timer\n");
+		value_to_be_changed = 10;
+		dispatch_source_cancel(long_timer);
+	});
+	dispatch_source_set_timer(long_timer,
+		dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC) ,
+		long_interval, 0);
+
+	dispatch_resume(mini_timer);
+	dispatch_resume(long_timer);
+	sleep(6);
+	test_long("Checking final value", value_to_be_changed, 10);
+	test_long("Mini-timer fired", fired, 1);
+	dispatch_source_cancel(mini_timer);
+	dispatch_release(mini_timer);
+	dispatch_resume(timer_queue);
+	dispatch_release(timer_queue);
+	dispatch_release(long_timer);
+	test_stop();
+	return 0;
+}
diff --git a/tests/dispatch_transform.c b/tests/dispatch_transform.c
new file mode 100644
index 0000000..85a4114
--- /dev/null
+++ b/tests/dispatch_transform.c
@@ -0,0 +1,875 @@
+/*
+ * Copyright (c) 2011-2012 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 <bsdtests.h>
+
+#if DISPATCH_API_VERSION >= 20111008 && !TARGET_OS_EMBEDDED
+
+#include <Security/Security.h>
+
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <fcntl.h>
+
+#define printf_data(p, s) ({ \
+	typeof(s) _i; \
+	for (_i=0; _i<s; _i++) { \
+		printf("%c", ((uint8_t *)p)[_i]); \
+	} \
+	printf("\n"); \
+})
+
+#define test_data_equal(a, b, c)	({ \
+	const void * ptr, * ptr2; \
+	size_t size, size2; \
+	dispatch_data_t map = dispatch_data_create_map(b, &ptr, &size); \
+	assert(map); \
+	dispatch_data_t map2 = dispatch_data_create_map(c, &ptr2, &size2); \
+	assert(map); \
+	test_long(a ": length", size, size2); \
+	test_long(a ": memcmp", memcmp(ptr, ptr2, size), 0); \
+	if (size != size2 || (memcmp(ptr, ptr2, size) != 0)) { \
+		printf_data(ptr, size); \
+		printf_data(ptr2, size2); \
+	} \
+	dispatch_release(map); \
+	dispatch_release(map2); \
+})
+
+static bool
+dispatch_data_equal(dispatch_data_t a, dispatch_data_t b)
+{
+	const void * ptr, * ptr2;
+	size_t size, size2;
+	bool equal = true;
+
+	dispatch_data_t map = dispatch_data_create_map(a, &ptr, &size); \
+	assert(map);
+	dispatch_data_t map2 = dispatch_data_create_map(b, &ptr2, &size2); \
+	assert(map2);
+
+	if (size == size2) {
+		if (memcmp(ptr, ptr2, size) != 0) {
+			equal = false;
+		}
+	} else {
+		equal = false;
+	}
+	dispatch_release(map);
+	dispatch_release(map2);
+	return equal;
+}
+
+static dispatch_data_t
+execute_sectransform(SecTransformRef transformRef, dispatch_data_t data)
+{
+	const void * bytes;
+	size_t size;
+
+	dispatch_data_t map = dispatch_data_create_map(data, &bytes, &size);
+	assert(map);
+
+	CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, bytes, size);
+	assert(dataRef);
+
+	dispatch_release(map);
+
+	SecTransformSetAttribute(transformRef, kSecTransformInputAttributeName, dataRef, NULL);
+
+	CFDataRef transformedDataRef = SecTransformExecute(transformRef, NULL);
+	assert(transformedDataRef);
+
+	CFRelease(dataRef);
+
+	dispatch_data_t output = dispatch_data_create(CFDataGetBytePtr(transformedDataRef), CFDataGetLength(transformedDataRef), dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+	CFRelease(transformedDataRef);
+
+	return output;
+}
+
+#pragma mark - UTF tests
+
+static uint8_t utf8[] = {
+	0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66, 0x6f,
+	0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xeb, 0x84, 0x88, 0xeb, 0xac,
+	0xb4, 0x20, 0xec, 0x98, 0xa4, 0xeb, 0x9e, 0x98, 0x20, 0xea, 0xb7, 0xb8, 0xeb, 0xa6, 0xac, 0xea, 0xb3, 0xa0, 0x20, 0xea, 0xb7,
+	0xb8, 0x20, 0xeb, 0x8f, 0x99, 0xec, 0x95, 0x88, 0x20, 0xeb, 0xa7, 0x9b, 0xec, 0x9e, 0x88, 0xeb, 0x8a, 0x94, 0x20, 0xec, 0x83,
+	0x9d, 0xec, 0x84, 0xa0, 0xec, 0x9d, 0x80, 0x20, 0xea, 0xb3, 0xa0, 0xeb, 0xa7, 0x88, 0xec, 0x9b, 0xa0, 0xec, 0x96, 0xb4, 0x2e,
+	0x20, 0xf0, 0x9f, 0x98, 0x84, 0xf0, 0x9f, 0x98, 0x8a, 0xf0, 0x9f, 0x98, 0x83, 0xe2, 0x98, 0xba, 0xf0, 0x9f, 0x98, 0x89, 0xf0,
+	0x9f, 0x98, 0x8d, 0xf0, 0x9f, 0x92, 0xa8, 0xf0, 0x9f, 0x92, 0xa9, 0xf0, 0x9f, 0x91, 0x8e, 0x2e,
+};
+
+static uint16_t utf16[] = {
+	0xfeff, 0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66,
+	0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xb108, 0xbb34, 0x20,
+	0xc624, 0xb798, 0x20, 0xadf8, 0xb9ac, 0xace0, 0x20, 0xadf8, 0x20, 0xb3d9, 0xc548, 0x20, 0xb9db, 0xc788, 0xb294, 0x20, 0xc0dd,
+	0xc120, 0xc740, 0x20, 0xace0, 0xb9c8, 0xc6e0, 0xc5b4, 0x2e, 0x20, 0xd83d, 0xde04, 0xd83d, 0xde0a, 0xd83d, 0xde03, 0x263a, 0xd83d,
+	0xde09, 0xd83d, 0xde0d, 0xd83d, 0xdca8, 0xd83d, 0xdca9, 0xd83d, 0xdc4e, 0x2e,
+};
+
+static uint16_t utf16be[] = {
+	0xfffe, 0x5300, 0x6f00, 0x2000, 0x6c00, 0x6f00, 0x6e00, 0x6700, 0x2000, 0x6100, 0x6e00, 0x6400, 0x2000, 0x7400, 0x6800, 0x6100,
+	0x6e00, 0x6b00, 0x7300, 0x2000, 0x6600, 0x6f00, 0x7200, 0x2000, 0x6100, 0x6c00, 0x6c00, 0x2000, 0x7400, 0x6800, 0x6500, 0x2000,
+	0x6600, 0x6900, 0x7300, 0x6800, 0x2e00, 0x2000, 0x8b1, 0x34bb, 0x2000, 0x24c6, 0x98b7, 0x2000, 0xf8ad, 0xacb9, 0xe0ac, 0x2000,
+	0xf8ad, 0x2000, 0xd9b3, 0x48c5, 0x2000, 0xdbb9, 0x88c7, 0x94b2, 0x2000, 0xddc0, 0x20c1, 0x40c7, 0x2000, 0xe0ac, 0xc8b9, 0xe0c6,
+	0xb4c5, 0x2e00, 0x2000, 0x3dd8, 0x4de, 0x3dd8, 0xade, 0x3dd8, 0x3de, 0x3a26, 0x3dd8, 0x9de, 0x3dd8, 0xdde, 0x3dd8, 0xa8dc,
+	0x3dd8, 0xa9dc, 0x3dd8, 0x4edc, 0x2e00,
+};
+
+// Invalid due to half missing surrogate
+static uint16_t utf16le_invalid[] = {
+	0xfeff, 0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66,
+	0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xb108, 0xbb34, 0x20,
+	0xc624, 0xb798, 0x20, 0xadf8, 0xb9ac, 0xace0, 0x20, 0xadf8, 0x20, 0xb3d9, 0xc548, 0x20, 0xb9db, 0xc788, 0xb294, 0x20, 0xc0dd,
+	0xc120, 0xc740, 0x20, 0xace0, 0xb9c8, 0xc6e0, 0xc5b4, 0x2e, 0x20, 0xd83d, 0xde04, 0xd83d, 0xde0a, 0xd83d, 0xde03, 0x263a, 0xd83d,
+	0xde09, 0xd83d, 0xde0d, 0xd83d, 0xdca8, 0xd83d, 0xd83d, 0xdc4e, 0x2e,
+};
+
+void
+invalid_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8 + sizeof(utf8) - 8, 8, NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
+	test_ptr_null("dispatch_data_create_with_transform (UTF8 (invalid start) -> UTF16LE)", transformed);
+
+	dispatch_release(utf8_data);
+
+	(void)context;
+}
+
+void
+truncated_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8) - 3, NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
+	test_ptr_null("dispatch_data_create_with_transform (UTF8 (truncated) -> UTF16LE)", transformed);
+
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf8_test);
+}
+
+void
+invalid_utf16le_surrogate_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16le_invalid, sizeof(utf16le_invalid), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_null("dispatch_data_create_with_transform (UTF16LE (missing surrogate) -> UTF8)", transformed);
+
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, truncated_utf8_test);
+}
+
+void
+invalid_utf16le_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, (sizeof(utf16) % 2) + 1, NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_null("dispatch_data_create_with_transform (UTF16LE (invalid) -> UTF8)", transformed);
+
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf16le_surrogate_test);
+}
+
+void
+utf16le_bytes_to_utf8_test(void * context)
+{
+	dispatch_data_t utf16_data = dispatch_data_empty;
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+
+	size_t i;
+	for (i=0; i<sizeof(utf16); i++) {
+		dispatch_data_t new = dispatch_data_create((char*)utf16 + i, 1, NULL, ^{});
+		dispatch_data_t concat = dispatch_data_create_concat(utf16_data, new);
+		dispatch_release(new);
+		dispatch_release(utf16_data);
+		utf16_data = concat;
+	}
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE (any, single bytes) -> UTF8)", transformed);
+	test_data_equal("utf16le_bytes_to_utf8_test", transformed, utf8_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf8_data);
+	dispatch_release(utf16_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf16le_test);
+}
+
+void
+utf8_bytes_to_utf16le_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_empty;
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
+
+	size_t i;
+	for (i=0; i<sizeof(utf8); i++) {
+		dispatch_data_t new = dispatch_data_create(utf8 + i, 1, NULL, ^{});
+		dispatch_data_t concat = dispatch_data_create_concat(utf8_data, new);
+		dispatch_release(new);
+		dispatch_release(utf8_data);
+		utf8_data = concat;
+	}
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF8 (any, single bytes) -> UTF16LE)", transformed);
+	test_data_equal("utf8_bytes_to_utf16le_test", transformed, utf16_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf8_data);
+	dispatch_release(utf16_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_bytes_to_utf8_test);
+}
+
+void
+utf16be_detect_to_utf16le_test(void * context)
+{
+	dispatch_data_t utf16be_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16be_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE (any) -> UTF16LE)", transformed);
+	test_data_equal("utf16be_detect_to_utf16le_test", transformed, utf16_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16be_data);
+	dispatch_release(utf16_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_bytes_to_utf16le_test);
+}
+
+void
+utf16be_detect_to_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE (any) -> UTF8)", transformed);
+	test_data_equal("utf16be_detect_to_utf8_test", transformed, utf8_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_detect_to_utf16le_test);
+}
+
+void
+utf16le_detect_to_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE (any) -> UTF8)", transformed);
+	test_data_equal("utf16le_detect_to_utf8_test", transformed, utf8_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_detect_to_utf8_test);
+}
+
+void
+utf16be_to_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16BE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE -> UTF8)", transformed);
+	test_data_equal("utf16be_to_utf8_test", transformed, utf8_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_detect_to_utf8_test);
+}
+
+void
+utf16le_to_utf8_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE -> UTF8)", transformed);
+	test_data_equal("utf16le_to_utf8_test", transformed, utf8_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_to_utf8_test);
+}
+
+void
+utf8_to_utf16be_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16BE);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF8 -> UTF16BE)", transformed);
+	test_data_equal("utf8_to_utf16be_test", transformed, utf16_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_to_utf8_test);
+}
+
+void
+utf8_to_utf16le_test(void * context)
+{
+	dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
+	dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
+
+	dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
+	test_ptr_notnull("dispatch_data_create_with_transform (UTF8 -> UTF16LE)", transformed);
+	test_data_equal("utf8_to_utf16le_test", transformed, utf16_data);
+
+	dispatch_release(transformed);
+	dispatch_release(utf16_data);
+	dispatch_release(utf8_data);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_to_utf16be_test);
+}
+
+#pragma mark - base32 tests
+
+void
+decode32_corrupt_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		void * corrupt_buffer = malloc(dispatch_data_get_size(sectransform_data));
+		const void * source;
+		size_t size;
+
+		dispatch_data_t map = dispatch_data_create_map(sectransform_data, &source, &size);
+		memcpy(corrupt_buffer, source, size);
+
+		size_t i;
+		for (i=0; i<size; i += (arc4random() % (int)(size * 0.05))) {
+			char x = arc4random() & 0xff;
+			while ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x >= '0' && x <= '9') || x == '/' || x == '+' || x == '=') {
+				x = arc4random() & 0xff;
+			}
+
+			((char*)corrupt_buffer)[i] = x;
+		}
+
+		dispatch_release(map);
+		dispatch_release(sectransform_data);
+
+		dispatch_data_t corrupt_data = dispatch_data_create(corrupt_buffer, size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
+
+		dispatch_data_t transform_data = dispatch_data_create_with_transform(corrupt_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
+		test_ptr_null("decode32_corrupt_test: dispatch_data_create_with_transform", transform_data);
+
+		dispatch_release(corrupt_data);
+
+		close(fd);
+
+		dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_to_utf16le_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+void
+chunking_decode32_test(void * context)
+{
+	(void)context;
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_data_t __block data = dispatch_data_empty;
+
+	int i;
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_queue_t queue = dispatch_queue_create("read", 0);
+	for (i=0; i<4096; i++) {
+		dispatch_group_enter(group);
+
+		dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
+			assert(error == 0);
+
+			dispatch_data_t concat = dispatch_data_create_concat(data, d);
+			dispatch_release(data);
+			data = concat;
+			dispatch_group_leave(group);
+		});
+	}
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+	dispatch_release(queue);
+	dispatch_release(group);
+
+	SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
+	assert(transformRef);
+
+	dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+	assert(sectransform_data);
+	CFRelease(transformRef);
+
+	dispatch_data_t transformed_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
+	test_ptr_notnull("chunking_decode32_test: dispatch_data_create_with_transform", transformed_data);
+	test_data_equal("chunking_decode32_test", transformed_data, data);
+
+	dispatch_release(sectransform_data);
+	dispatch_release(transformed_data);
+	dispatch_release(data);
+
+	close(fd);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, decode32_corrupt_test);
+}
+
+void
+chunking_encode32_test(void * context)
+{
+	(void)context;
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_data_t __block data = dispatch_data_empty;
+
+	int i;
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_queue_t queue = dispatch_queue_create("read", 0);
+	for (i=0; i<4096; i++) {
+		dispatch_group_enter(group);
+
+		dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
+			assert(error == 0);
+
+			dispatch_data_t concat = dispatch_data_create_concat(data, d);
+			dispatch_release(data);
+			data = concat;
+			dispatch_group_leave(group);
+		});
+	}
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+	dispatch_release(queue);
+	dispatch_release(group);
+
+	SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
+	assert(transformRef);
+
+	dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+	assert(sectransform_data);
+	CFRelease(transformRef);
+
+	dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE32);
+	test_ptr_notnull("chunking_encode32_test: dispatch_data_create_with_transform", transformed_data);
+	test_data_equal("chunking_encode32_test", transformed_data, sectransform_data);
+
+	dispatch_release(sectransform_data);
+	dispatch_release(transformed_data);
+	dispatch_release(data);
+
+	close(fd);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, chunking_decode32_test);
+}
+
+void
+decode32_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
+		test_ptr_notnull("decode32_test: dispatch_data_create_with_transform", transform_data);
+		test_data_equal("decode32_test", transform_data, data);
+
+		dispatch_release(sectransform_data);
+		dispatch_release(transform_data);
+
+		close(fd);
+
+		dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, chunking_encode32_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+void
+encode32_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE32);
+		test_ptr_notnull("encode32_test: dispatch_data_create_with_transform", transformed_data);
+		test_data_equal("encode32_test", transformed_data, sectransform_data);
+
+		dispatch_release(sectransform_data);
+		dispatch_release(transformed_data);
+
+		close(fd);
+
+		dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode32_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+#pragma mark - base64 tests
+
+void
+decode64_loop_test(void * context)
+{
+	if (getenv("LOOP_SKIP") == NULL)
+	{
+		int fd = open("/dev/random", O_RDONLY);
+		assert(fd >= 0);
+
+		dispatch_semaphore_t sema = dispatch_semaphore_create(0);
+		size_t i, __block tests = 0;
+
+		for (i=1; i<4097; i++) {
+			dispatch_read(fd, i, dispatch_get_global_queue(0, 0), ^(dispatch_data_t data, int error) {
+				assert(error == 0);
+
+				SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+				assert(transformRef);
+
+				dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+				assert(sectransform_data);
+				CFRelease(transformRef);
+
+				dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
+				if (dispatch_data_equal(transform_data, data)) {
+					tests++;
+				}
+
+				dispatch_release(sectransform_data);
+				dispatch_release(transform_data);
+
+				dispatch_semaphore_signal(sema);
+			});
+			dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+		}
+		dispatch_release(sema);
+		close(fd);
+		test_long("decode64_loop_test", tests, 4096);
+	}
+	dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, encode32_test);
+}
+
+void
+decode64_corrupt_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		void * corrupt_buffer = malloc(dispatch_data_get_size(sectransform_data));
+		const void * source;
+		size_t size;
+
+		dispatch_data_t map = dispatch_data_create_map(sectransform_data, &source, &size);
+		memcpy(corrupt_buffer, source, size);
+
+		size_t i;
+		for (i=0; i<size; i += (arc4random() % (int)(size * 0.05))) {
+			char x = arc4random() & 0xff;
+			while ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x >= '0' && x <= '9') || x == '/' || x == '+' || x == '=') {
+				x = arc4random() & 0xff;
+			}
+
+			((char*)corrupt_buffer)[i] = x;
+		}
+
+		dispatch_release(map);
+		dispatch_release(sectransform_data);
+
+		dispatch_data_t corrupt_data = dispatch_data_create(corrupt_buffer, size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
+
+		dispatch_data_t transform_data = dispatch_data_create_with_transform(corrupt_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
+		test_ptr_null("decode64_corrupt_test: dispatch_data_create_with_transform", transform_data);
+
+		dispatch_release(corrupt_data);
+
+		close(fd);
+
+		dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode64_loop_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+void
+chunking_decode64_test(void * context)
+{
+	(void)context;
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_data_t __block data = dispatch_data_empty;
+
+	int i;
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_queue_t queue = dispatch_queue_create("read", 0);
+	for (i=0; i<4096; i++) {
+		dispatch_group_enter(group);
+
+		dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
+			assert(error == 0);
+
+			dispatch_data_t concat = dispatch_data_create_concat(data, d);
+			dispatch_release(data);
+			data = concat;
+			dispatch_group_leave(group);
+		});
+	}
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+	dispatch_release(queue);
+	dispatch_release(group);
+
+	SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+	assert(transformRef);
+
+	dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+	assert(sectransform_data);
+	CFRelease(transformRef);
+
+	dispatch_data_t transformed_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
+	test_ptr_notnull("chunking_decode64_test: dispatch_data_create_with_transform", transformed_data);
+	test_data_equal("chunking_decode64_test", transformed_data, data);
+
+	dispatch_release(sectransform_data);
+	dispatch_release(transformed_data);
+	dispatch_release(data);
+
+	close(fd);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, decode64_corrupt_test);
+}
+
+void
+chunking_encode64_test(void * context)
+{
+	(void)context;
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_data_t __block data = dispatch_data_empty;
+
+	int i;
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_queue_t queue = dispatch_queue_create("read", 0);
+	for (i=0; i<4097; i++) {
+		dispatch_group_enter(group);
+
+		dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
+			assert(error == 0);
+
+			dispatch_data_t concat = dispatch_data_create_concat(data, d);
+			dispatch_release(data);
+			data = concat;
+			dispatch_group_leave(group);
+		});
+	}
+	dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+	dispatch_release(queue);
+	dispatch_release(group);
+
+	SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+	assert(transformRef);
+
+	dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+	assert(sectransform_data);
+	CFRelease(transformRef);
+
+	dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
+	test_ptr_notnull("chunking_encode64_test: dispatch_data_create_with_transform", transformed_data);
+	test_data_equal("chunking_encode64_test", transformed_data, sectransform_data);
+
+	dispatch_release(sectransform_data);
+	dispatch_release(transformed_data);
+	dispatch_release(data);
+
+	close(fd);
+
+	dispatch_group_async_f(context, dispatch_get_main_queue(), context, chunking_decode64_test);
+}
+
+void
+decode64_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
+		test_ptr_notnull("decode64_test: dispatch_data_create_with_transform", transform_data);
+		test_data_equal("decode64_test", transform_data, data);
+
+		dispatch_release(sectransform_data);
+		dispatch_release(transform_data);
+
+		close(fd);
+
+		dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, chunking_encode64_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+void
+encode64_test(void * context)
+{
+	dispatch_group_enter((dispatch_group_t)context);
+
+	int fd = open("/dev/random", O_RDONLY);
+	assert(fd >= 0);
+
+	dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
+		assert(error == 0);
+
+		SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
+		assert(transformRef);
+
+		dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
+		assert(sectransform_data);
+		CFRelease(transformRef);
+
+		dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
+		test_ptr_notnull("encode64_test: dispatch_data_create_with_transform", transformed_data);
+		test_data_equal("encode64_test", transformed_data, sectransform_data);
+
+		dispatch_release(sectransform_data);
+		dispatch_release(transformed_data);
+
+		close(fd);
+
+		dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode64_test);
+		dispatch_group_leave((dispatch_group_t)context);
+	});
+}
+
+#pragma mark - main
+
+int
+main(void)
+{
+	test_start("Dispatch data transforms test");
+
+	dispatch_group_t group = dispatch_group_create();
+	dispatch_group_async_f(group, dispatch_get_main_queue(), group, encode64_test);
+
+	dispatch_group_notify(group, dispatch_get_main_queue(), ^{
+		dispatch_release(group);
+		test_stop();
+		exit(0);
+	});
+
+	dispatch_main();
+	return 0;
+}
+
+#else
+
+int
+main(void)
+{
+  test_skip("Dispatch data transforms test");
+  return 0;
+}
+
+#endif
+
diff --git a/tests/dispatch_vm.c b/tests/dispatch_vm.c
new file mode 100644
index 0000000..6877411
--- /dev/null
+++ b/tests/dispatch_vm.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2010-2011 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 <sys/event.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#endif
+#include <assert.h>
+#ifdef __ANDROID__
+#include <linux/sysctl.h>
+#else
+#include <sys/sysctl.h>
+#endif /* __ANDROID__ */
+#include <stdarg.h>
+#include <time.h>
+
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#if defined(DISPATCH_SOURCE_TYPE_VM) && defined(NOTE_VM_PRESSURE)
+
+#if TARGET_OS_EMBEDDED
+#define ALLOC_SIZE ((size_t)(1024*1024*1ul))	// 1MB
+#define NOTIFICATIONS 1
+#else
+#define ALLOC_SIZE ((size_t)(1024*1024*20ul))	// 20MB
+#define NOTIFICATIONS 2
+#endif
+#define pg2mb(p) ((p) * ALLOC_SIZE/(1024*1024))
+#ifdef __LP64__
+#define MAXMEM ((size_t)SIZE_MAX)
+#else
+#define MAXMEM ((size_t)(3200ul*1024*1024))		// 3200MB
+#endif
+
+static char **pages;
+static volatile int32_t handler_call_count;
+static volatile int32_t page_count;
+static int32_t max_page_count;
+static dispatch_source_t vm_source;
+static dispatch_queue_t vm_queue;
+static time_t initial;
+static int interval = 16;
+
+#define log_msg(msg, ...) \
+do { \
+	fprintf(stderr, "[%2ds] " msg, (int)(time(NULL) - initial), ##__VA_ARGS__);\
+} while (0)
+
+static bool
+dispatch_test_check_evfilt_vm(void)
+{
+	int kq = kqueue();
+	assert(kq != -1);
+	struct kevent ke = {
+		.filter = EVFILT_VM,
+		.flags = EV_ADD|EV_ENABLE|EV_RECEIPT,
+		.fflags = NOTE_VM_PRESSURE,
+	};
+	int r = kevent(kq, &ke, 1, &ke, 1, NULL);
+	close(kq);
+	return !(r > 0 && ke.flags & EV_ERROR && ke.data == ENOTSUP);
+}
+
+static void
+cleanup(void)
+{
+	dispatch_source_cancel(vm_source);
+	dispatch_release(vm_source);
+	dispatch_release(vm_queue);
+
+	int32_t pc = 0, i;
+	for (i = 0; i < max_page_count; ++i) {
+	   if (pages[i]) {
+		   pc++;
+		   free(pages[i]);
+	   }
+	}
+	if (pc) {
+		log_msg("Freed %ldMB\n", pg2mb(pc));
+	}
+	free(pages);
+	test_stop();
+}
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch VM Pressure test"); // rdar://problem/7000945
+	if (!dispatch_test_check_evfilt_vm()) {
+		test_skip("EVFILT_VM not supported");
+		test_stop();
+		return 0;
+	}
+	initial = time(NULL);
+	uint64_t memsize;
+#ifdef __linux__
+	memsize = sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+#else
+	size_t s = sizeof(memsize);
+	int rc = sysctlbyname("hw.memsize", &memsize, &s, NULL, 0);
+	assert(rc == 0);
+#endif
+	max_page_count = MIN(memsize, MAXMEM) / ALLOC_SIZE;
+	pages = calloc(max_page_count, sizeof(char*));
+
+	vm_queue = dispatch_queue_create("VM Pressure", NULL);
+	vm_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VM, 0,
+			DISPATCH_VM_PRESSURE, vm_queue);
+	dispatch_source_set_event_handler(vm_source, ^{
+		if (!page_count) {
+			// Too much memory pressure already to start the test
+			test_skip("Memory pressure at start of test");
+			cleanup();
+		}
+		if (OSAtomicIncrement32Barrier(&handler_call_count) != NOTIFICATIONS) {
+			log_msg("Ignoring vm pressure notification\n");
+			interval = 1;
+			return;
+		}
+		test_long("dispatch_source_get_data()",
+				dispatch_source_get_data(vm_source), NOTE_VM_PRESSURE);
+		int32_t i, pc = page_count + 1;
+		for (i = 0; i < pc && pages[i]; ++i) {
+				free(pages[i]);
+				pages[i] = NULL;
+		}
+		log_msg("Freed %ldMB\n", pg2mb(i));
+	});
+	dispatch_resume(vm_source);
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
+			dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+		while (handler_call_count < NOTIFICATIONS &&
+				page_count < max_page_count) {
+			void *p = valloc(ALLOC_SIZE);
+			if (!p) {
+				break;
+			}
+			bzero(p, ALLOC_SIZE);
+			pages[page_count] = p;
+			if (!(OSAtomicIncrement32Barrier(&page_count) % interval)) {
+				log_msg("Allocated %ldMB\n", pg2mb(page_count));
+				usleep(200000);
+			}
+		}
+		if (page_count % interval) {
+			log_msg("Allocated %ldMB\n", pg2mb(page_count));
+		}
+		if (handler_call_count < NOTIFICATIONS) {
+			// Cannot allocate enough memory for test (e.g. on 32 bit)
+			test_skip("Cannot allocate enough memory for test");
+			dispatch_async(vm_queue, ^{cleanup();});
+			return;
+		}
+		dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
+				vm_queue, ^{
+			test_long_greater_than_or_equal("VM Pressure fired",
+					handler_call_count, NOTIFICATIONS);
+			test_long_less_than("VM Pressure stopped firing",
+					handler_call_count, 4);
+			cleanup();
+		});
+	});
+	dispatch_main();
+	return 0;
+}
+#else //DISPATCH_SOURCE_TYPE_VM
+int
+main(void)
+{
+	dispatch_test_start("Dispatch VM Pressure test"
+			" - No DISPATCH_SOURCE_TYPE_VM");
+	test_stop();
+	return 0;
+}
+#endif //DISPATCH_SOURCE_TYPE_VM
diff --git a/tests/dispatch_vnode.c b/tests/dispatch_vnode.c
new file mode 100644
index 0000000..45cae72
--- /dev/null
+++ b/tests/dispatch_vnode.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010-2011 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 <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dispatch/dispatch.h>
+
+#include <bsdtests.h>
+#include "dispatch_test.h"
+
+#define ITERATIONS 1000
+long iterations, notifications;
+
+int
+main(void)
+{
+	dispatch_test_start("Dispatch VNODE RENAME");
+
+	char path1[] = "/tmp/dispatchtest_vnode.XXXXXX";
+	char path2[] = "/tmp/dispatchtest_vnode.XXXXXX";
+	int fd1 = mkstemp(path1);
+	if (fd1 == -1) {
+		test_errno("mkstemp", errno, 0);
+		test_stop();
+	}
+	close(fd1);
+	if (!mktemp(path2)) {
+		test_errno("mktemp", errno, 0);
+		test_stop();
+	}
+	char *currentName = path1;
+	char *renameDest = path2;
+	dispatch_semaphore_t renamedSemaphore = dispatch_semaphore_create(0);
+	dispatch_group_t g = dispatch_group_create();
+
+	while (iterations++ < ITERATIONS) {
+		int fd = open(currentName, O_EVTONLY);
+		if (fd == -1) {
+			test_errno("open", errno, 0);
+			test_stop();
+		}
+
+		dispatch_source_t monitorSource = dispatch_source_create(
+				DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_RENAME,
+				dispatch_get_global_queue(0, 0));
+		dispatch_source_set_event_handler(monitorSource, ^{
+			dispatch_semaphore_signal(renamedSemaphore);
+		});
+		dispatch_source_set_cancel_handler(monitorSource, ^{
+			close(fd);
+		});
+#if DISPATCH_API_VERSION >= 20100818 // <rdar://problem/7731284>
+		dispatch_group_enter(g);
+		dispatch_source_set_registration_handler(monitorSource, ^{
+			dispatch_group_leave(g);
+		});
+#endif
+		dispatch_resume(monitorSource);
+		dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+		if(rename(currentName, renameDest)) {
+			test_errno("rename", errno, 0);
+			test_stop();
+		}
+		char *tmp = currentName;
+		currentName = renameDest;
+		renameDest = tmp;
+
+		if(!dispatch_semaphore_wait(renamedSemaphore,
+				dispatch_time(DISPATCH_TIME_NOW, 10 * 1000 * NSEC_PER_USEC))) {
+			fprintf(stderr, ".");
+			notifications++;
+			dispatch_source_cancel(monitorSource);
+		} else {
+			fprintf(stderr, "!");
+			dispatch_source_cancel(monitorSource);
+			dispatch_semaphore_signal(renamedSemaphore);
+		}
+		if (!(iterations % 80)) {
+			fprintf(stderr, "\n");
+		}
+		dispatch_release(monitorSource);
+	}
+	fprintf(stderr, "\n");
+	unlink(currentName);
+	dispatch_release(g);
+	dispatch_release(renamedSemaphore);
+	test_long("VNODE RENAME notifications", notifications, ITERATIONS);
+	test_stop();
+	return 0;
+}
diff --git a/tests/func.c b/tests/func.c
new file mode 100644
index 0000000..b986522
--- /dev/null
+++ b/tests/func.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2008-2011 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@
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void
+func(void)
+{
+}
+#ifdef __BLOCKS__
+void (^block)(void) = ^{ };
+#endif
+#ifdef __cplusplus
+};
+#endif
diff --git a/tests/leaks-wrapper.sh b/tests/leaks-wrapper.sh
new file mode 100755
index 0000000..05f9d69
--- /dev/null
+++ b/tests/leaks-wrapper.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+/usr/bin/leaks "$@" 2>&1 | tee "${TMPDIR}$*.leakslog" | grep -q " 0 leaks for 0 total leaked bytes"
+
+if [ $? -eq 0 ]; then
+    rm "${TMPDIR}$*.leakslog"
+    exit 0
+else
+    exit $?
+fi
diff --git a/tests/linux_port.h b/tests/linux_port.h
new file mode 100644
index 0000000..f2c82f1
--- /dev/null
+++ b/tests/linux_port.h
@@ -0,0 +1,54 @@
+#include <limits.h>
+#include <sys/param.h>
+
+static inline int32_t
+OSAtomicIncrement32(volatile int32_t *var)
+{
+  return __c11_atomic_fetch_add((_Atomic(int)*)var, 1, __ATOMIC_RELAXED)+1;
+}
+
+static inline int32_t
+OSAtomicIncrement32Barrier(volatile int32_t *var)
+{
+    return __c11_atomic_fetch_add((_Atomic(int)*)var, 1, __ATOMIC_SEQ_CST)+1;
+}
+
+static inline int32_t
+OSAtomicAdd32(int32_t val, volatile int32_t *var)
+{
+    return __c11_atomic_fetch_add((_Atomic(int)*)var, val, __ATOMIC_RELAXED)+val;
+}
+
+// Simulation of mach_absolute_time related infrastructure
+// For now, use gettimeofday.
+// Consider using clockgettime(CLOCK_MONOTONIC) instead.
+
+#include <sys/time.h>
+
+struct mach_timebase_info {
+  uint32_t numer;
+  uint32_t denom;
+};
+
+typedef struct mach_timebase_info *mach_timebase_info_t;
+typedef struct mach_timebase_info mach_timebase_info_data_t;
+
+typedef int kern_return_t;
+
+static inline
+uint64_t
+mach_absolute_time()
+{
+	struct timeval tv;
+	gettimeofday(&tv,NULL);
+	return (1000ull)*((unsigned long long)tv.tv_sec*(1000000ull) + (unsigned long long)tv.tv_usec);
+}
+
+static inline
+int
+mach_timebase_info(mach_timebase_info_t tbi)
+{
+	tbi->numer = 1;
+	tbi->denom = 1;
+	return 0;
+}