[libdispatch-changes] [215] trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Aug 8 22:09:03 PDT 2012


Revision: 215
          http://trac.macosforge.org/projects/libdispatch/changeset/215
Author:   dsteffen at apple.com
Date:     2012-08-08 22:09:03 -0700 (Wed, 08 Aug 2012)
Log Message:
-----------
MountainLion macosforge testsuite

Modified Paths:
--------------
    trunk/Makefile.am
    trunk/configure.ac
    trunk/testing/Makefile.am
    trunk/testing/bench.mm
    trunk/testing/bsdtestharness.c
    trunk/testing/bsdtests.c
    trunk/testing/bsdtests.h
    trunk/testing/dispatch_after.c
    trunk/testing/dispatch_api.c
    trunk/testing/dispatch_apply.c
    trunk/testing/dispatch_concur.c
    trunk/testing/dispatch_deadname.c
    trunk/testing/dispatch_drift.c
    trunk/testing/dispatch_group.c
    trunk/testing/dispatch_io.c
    trunk/testing/dispatch_priority.c
    trunk/testing/dispatch_queue_finalizer.c
    trunk/testing/dispatch_suspend_timer.c
    trunk/testing/dispatch_test.c
    trunk/testing/dispatch_test.h
    trunk/testing/dispatch_timer.c
    trunk/testing/dispatch_timer_bit31.c
    trunk/testing/dispatch_timer_set_time.c
    trunk/testing/dispatch_vm.c

Added Paths:
-----------
    trunk/testing/dispatch_transform.c

Modified: trunk/Makefile.am
===================================================================
--- trunk/Makefile.am	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/Makefile.am	2012-08-09 05:09:03 UTC (rev 215)
@@ -9,7 +9,8 @@
 	man						\
 	os						\
 	private					\
-	src
+	src						\
+	testing
 
 EXTRA_DIST=					\
 	LICENSE					\

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/configure.ac	2012-08-09 05:09:03 UTC (rev 215)
@@ -295,5 +295,11 @@
 #
 # Generate Makefiles.
 #
-AC_CONFIG_FILES([Makefile dispatch/Makefile man/Makefile os/Makefile private/Makefile src/Makefile])
+AC_CONFIG_FILES([Makefile dispatch/Makefile man/Makefile os/Makefile private/Makefile src/Makefile testing/Makefile])
+
+#
+# Generate testsuite links
+#
+AC_CONFIG_LINKS([testing/dispatch:${x:+}private testing/bench.cc:testing/bench.mm testing/leaks-wrapper:testing/leaks-wrapper.sh])
+
 AC_OUTPUT

Modified: trunk/testing/Makefile.am
===================================================================
--- trunk/testing/Makefile.am	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/Makefile.am	2012-08-09 05:09:03 UTC (rev 215)
@@ -62,17 +62,16 @@
 	dispatch_vnode				\
 	dispatch_select
 
-dispatch_c99_CFLAGS=-std=c99
+dispatch_c99_CFLAGS=$(AM_CFLAGS) -std=c99
 dispatch_plusplus_SOURCES=dispatch_plusplus.cpp
 dispatch_priority2_SOURCES=dispatch_priority.c
-dispatch_priority2_CFLAGS=-DUSE_SET_TARGET_QUEUE=1
+dispatch_priority2_CPPFLAGS=$(AM_CPPFLAGS) -DUSE_SET_TARGET_QUEUE=1
 
-INCLUDES=-I$(top_builddir) -I$(top_srcdir)
+AM_CPPFLAGS=-I$(top_builddir) -I$(top_srcdir)
 
-CPPFLAGS=
-CFLAGS=-Wall -g $(MARCH_FLAGS) $(CBLOCKS_FLAGS)
-OBJCFLAGS=-Wall -g $(MARCH_FLAGS) $(CBLOCKS_FLAGS)
-CXXFLAGS=-Wall -g $(MARCH_FLAGS) $(CXXBLOCKS_FLAGS)
+AM_CFLAGS=-Wall $(MARCH_FLAGS) $(CBLOCKS_FLAGS)
+AM_OBJCFLAGS=-Wall $(MARCH_FLAGS) $(CBLOCKS_FLAGS) -fobjc-gc
+AM_CXXFLAGS=-Wall $(MARCH_FLAGS) $(CXXBLOCKS_FLAGS)
 
 LDADD=libbsdtests.la ../src/libdispatch.la
 libbsdtests_la_LDFLAGS=-avoid-version
@@ -83,10 +82,12 @@
 if HAVE_COREFOUNDATION
 TESTS+=							\
 	dispatch_cf_main			\
+	dispatch_transform			\
 	dispatch_sync_on_main		\
 	cffd
 
 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
@@ -99,14 +100,13 @@
 	bench
 
 dispatch_sync_gc_SOURCES=dispatch_sync_gc.m
-dispatch_sync_gc_OBJCFLAGS=-fobjc-gc
 dispatch_sync_gc_LDFLAGS=-framework Foundation
 dispatch_apply_gc_SOURCES=dispatch_apply_gc.m
-dispatch_apply_gc_OBJCFLAGS=-fobjc-gc
 dispatch_apply_gc_LDFLAGS=-framework Foundation
 nsoperation_SOURCES=nsoperation.m
 nsoperation_LDFLAGS=-framework Foundation
-bench_SOURCES=bench.cc func.c
+nodist_bench_SOURCES=bench.cc
+bench_SOURCES=func.c
 bench_LDFLAGS=-framework Foundation
 # Workaround missing objcxx support in older autotools
 bench.o: bench.cc

Modified: trunk/testing/bench.mm
===================================================================
--- trunk/testing/bench.mm	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/bench.mm	2012-08-09 05:09:03 UTC (rev 215)
@@ -416,6 +416,13 @@
 
 	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)
@@ -466,9 +473,36 @@
 	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");
@@ -528,6 +562,37 @@
 	}
 	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();

Modified: trunk/testing/bsdtestharness.c
===================================================================
--- trunk/testing/bsdtestharness.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/bsdtestharness.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -18,7 +18,6 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-#include <mach/clock_types.h>
 #include <dispatch/dispatch.h>
 #include <assert.h>
 #include <spawn.h>
@@ -26,7 +25,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <signal.h>
+#include <mach/clock_types.h>
 #include <mach-o/arch.h>
+#include <sys/resource.h>
+#include <sys/time.h>
 
 #include <bsdtests.h>
 
@@ -37,19 +39,31 @@
 {
 	dispatch_source_t tmp_ds;
 	int res;
-	pid_t pid;
+	pid_t pid = 0;
 
 	if (argc < 2) {
 		fprintf(stderr, "usage: %s [...]\n", argv[0]);
 		exit(1);
 	}
 
+	short spawnflags = POSIX_SPAWN_START_SUSPENDED;
+#if TARGET_OS_EMBEDDED
+	spawnflags |= POSIX_SPAWN_SETEXEC;
+#endif
+
 	posix_spawnattr_t attr;
 	res = posix_spawnattr_init(&attr);
 	assert(res == 0);
-	res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
+	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;
+	}
+
 	char *arch = getenv("BSDTEST_ARCH");
 	if (arch) {
 		const NXArchInfo *ai = NXGetArchInfoFromName(arch);
@@ -66,12 +80,21 @@
 	}
 	newargv[i-1] = NULL;
 
-	res = posix_spawnp(&pid, newargv[0], NULL, &attr, newargv, environ);
-	if (res) {
-		errno = res;
-		perror(newargv[0]);
-		exit(EXIT_FAILURE);
+	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);
 
@@ -81,23 +104,40 @@
 	assert(tmp_ds);
 	dispatch_source_set_event_handler(tmp_ds, ^{
 		int status;
-		int res2 = waitpid(pid, &status, 0);
+		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
-	// Give embedded platforms a little more time.
-	uint64_t timeout = 300LL * NSEC_PER_SEC;
+		to = 180LL * NSEC_PER_SEC;
 #else
-	uint64_t timeout = 150LL * NSEC_PER_SEC;
+		to = 90LL * NSEC_PER_SEC;
 #endif
+	}
 
-	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), main_q, ^{
+	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, to), main_q, ^{
 		kill(pid, SIGKILL);
-		fprintf(stderr, "Terminating unresponsive process (%0.1lfs)\n", (double)timeout/NSEC_PER_SEC);
+		fprintf(stderr, "Terminating unresponsive process (%0.1lfs)\n", (double)to / NSEC_PER_SEC);
 	});
 
 	signal(SIGINT, SIG_IGN);
@@ -109,6 +149,9 @@
 	});
 	dispatch_resume(tmp_ds);
 
+	if (spawnflags & POSIX_SPAWN_SETEXEC) {
+		usleep(USEC_PER_SEC/10);
+	}
 	kill(pid, SIGCONT);
 
 	dispatch_main();

Modified: trunk/testing/bsdtests.c
===================================================================
--- trunk/testing/bsdtests.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/bsdtests.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -127,6 +127,18 @@
 	_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)
 {
@@ -211,6 +223,19 @@
 }
 
 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);
@@ -250,6 +275,20 @@
 }
 
 void
+_test_double_equal(const char* file, long line, const char* desc, double val, double expected)
+{
+	_test_print(file, line, desc, (val == expected), "%f", val, "%f", expected);
+}
+
+
+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, long actual, long expected)
 {
 	char* actual_str;
@@ -386,6 +425,10 @@
 		return;
 	}
 
+	unsetenv("DYLD_IMAGE_SUFFIX");
+	unsetenv("DYLD_INSERT_LIBRARIES");
+	unsetenv("DYLD_LIBRARY_PATH");
+
 	unsetenv("MallocStackLogging");
 	unsetenv("MallocStackLoggingNoCompact");
 

Modified: trunk/testing/bsdtests.h
===================================================================
--- trunk/testing/bsdtests.h	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/bsdtests.h	2012-08-09 05:09:03 UTC (rev 215)
@@ -18,10 +18,21 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
+#ifndef __BSD_TEST_H__
+#define __BSD_TEST_H__
+
 #include <errno.h>
 #include <mach/error.h>
 #include <CoreFoundation/CoreFoundation.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
 
 /**
@@ -47,67 +58,81 @@
  * 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(__FILE__, __LINE__, a, b)
+#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(__FILE__, __LINE__, a, b)
+#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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, a, b, c)
+#define test_uint32(a,b,c) _test_uint32(__SOURCE_FILE__, __LINE__, a, b, c)
 void test_uint32_format(long actual, long 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(__FILE__, __LINE__, a, b, c)
+#define test_int32(a,b,c) _test_int32(__SOURCE_FILE__, __LINE__, a, b, c)
 void test_sint32_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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, a, b, c)
+#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(__FILE__, __LINE__, d, v, m)
+#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(__FILE__, __LINE__, d, v, m)
+#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, long actual, long expected);
-#define test_errno(a,b,c) _test_errno(__FILE__, __LINE__, a, b, c)
+#define test_errno(a,b,c) _test_errno(__SOURCE_FILE__, __LINE__, a, b, c)
 void test_errno_format(long actual, long expected, const char *format, ...) __printflike(3,4);
 
 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(__FILE__, __LINE__, a, b, c)
+#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);
 
 void test_cferror(const char* desc, CFErrorRef actual, CFIndex expectedCode);
 void test_cferror_format(CFErrorRef actual, CFIndex expectedCode, const char *format, ...) __printflike(3,4);
 
 void _test_skip(const char* file, long line, const char* desc);
-#define test_skip(m) _test_skip(__FILE__, __LINE__, m)
+#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__ */

Modified: trunk/testing/dispatch_after.c
===================================================================
--- trunk/testing/dispatch_after.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_after.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -50,7 +50,7 @@
 		time_a_min = dispatch_time(0,  5.5*NSEC_PER_SEC);
 		time_a     = dispatch_time(0,   6*NSEC_PER_SEC);
 		time_a_max = dispatch_time(0,  6.5*NSEC_PER_SEC);
-		dispatch_after(time_a, dispatch_get_current_queue(), ^{
+		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, now_a - time_a_min);
 			test_long_less_than("must finish faster than  6.5s", 0, time_a_max - now_a);
@@ -58,7 +58,7 @@
 			time_b_min = dispatch_time(0,  1.5*NSEC_PER_SEC);
 			time_b     = dispatch_time(0,    2*NSEC_PER_SEC);
 			time_b_max = dispatch_time(0,  2.5*NSEC_PER_SEC);
-			dispatch_after(time_b, dispatch_get_current_queue(), ^{
+			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, now_b - time_b_min);
 				test_long_less_than("must finish faster than  2.5s", 0, time_b_max - now_b);
@@ -66,12 +66,12 @@
 				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,  .5*NSEC_PER_SEC);
-				dispatch_after(time_c, dispatch_get_current_queue(), ^{
+				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, now_c - time_c_min);
 					test_long_less_than("must finish faster than .5s", 0, time_c_max - now_c);
 
-					dispatch_async_f(dispatch_get_current_queue(), NULL, done);
+					dispatch_async_f(dispatch_get_main_queue(), NULL, done);
 				});
 			});
 		});

Modified: trunk/testing/dispatch_api.c
===================================================================
--- trunk/testing/dispatch_api.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_api.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -33,8 +33,9 @@
 int
 main(void)
 {
+	dispatch_queue_t q;
 	dispatch_test_start("Dispatch (Public) API");
-	dispatch_queue_t q = dispatch_get_main_queue();
+	q = dispatch_get_main_queue();
 	test_ptr_notnull("dispatch_get_main_queue", q);
 
 	dispatch_async_f(dispatch_get_main_queue(), NULL, work);

Modified: trunk/testing/dispatch_apply.c
===================================================================
--- trunk/testing/dispatch_apply.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_apply.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -24,10 +24,88 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <libkern/OSAtomic.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
 
 #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.
+ */
+#if TARGET_OS_EMBEDDED
+// iPhone 4
+#define ITERS_PER_SECOND 50000000UL
+#else
+// On a 2.7 4-core i5 iMac12,2, one thread of this loop runs at ROUGHLY:
+#define ITERS_PER_SECOND 1000000000UL
+#endif
+
+/* 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;
+void busythread(void *ignored)
+{
+	(void)ignored;
+	uint64_t i = 0, j = 0;
+
+	OSAtomicIncrement32(&busy_threads_started);
+
+	for(i = 0; i < 2*ITERS_PER_SECOND; i++)
+	{
+		if(i == 500000) { j -= busythread_useless; }
+		j += i;
+	}
+
+	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
+ */
+void test_apply_contended(dispatch_queue_t dq)
+{
+	uint32_t activecpu;
+	size_t s = sizeof(activecpu);
+	sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0);
+	int tIndex, n_threads = 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;
+
+	unsigned int before = busy_threads_started;
+	dispatch_apply(final, dq, ^(size_t i __attribute__((unused))) {
+		OSAtomicIncrement32(&count);
+	});
+	unsigned int 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);
+
+	dispatch_group_wait(grp, DISPATCH_TIME_FOREVER);
+	dispatch_release(grp);
+
+}
+
 int
 main(void)
 {
@@ -54,6 +132,8 @@
 	});
 	test_long("nested count", count, final * final * final);
 
+	test_apply_contended(queue);
+
 	test_stop();
 
 	return 0;

Modified: trunk/testing/dispatch_concur.c
===================================================================
--- trunk/testing/dispatch_concur.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_concur.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -147,7 +147,7 @@
 	size_t c = __sync_add_and_fetch(&concur, 1), *m = ((size_t *)ctxt) + i;
 	if (c > *m) *m = c;
 
-	usleep(10000);
+	usleep(100000);
 	__sync_sub_and_fetch(&concur, 1);
 }
 

Modified: trunk/testing/dispatch_deadname.c
===================================================================
--- trunk/testing/dispatch_deadname.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_deadname.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -32,18 +32,17 @@
 #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); _kr; })
+		_kr, mach_error_string(_kr), #x); (void)kr; })
 void
-test_mach_debug_port(mach_port_t name, const char *str)
+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\n",
-				name, kr, mach_error_string(kr), str);
+		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) {
@@ -58,8 +57,7 @@
 		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|
-			MACH_PORT_TYPE_SEND_ONCE)) {
+	if (type & (MACH_PORT_TYPE_RECEIVE|MACH_PORT_TYPE_SEND)) {
 		test_mach_assume_zero(mach_port_dnrequest_info(mach_task_self(), name,
 				&dnrsiz, &dnreqs));
 		}
@@ -71,24 +69,28 @@
 		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) nsreq(%s) pdreq(%s) srights(%s) sorights(%03u) "
-				"qlim(%03u) msgcount(%03u) mkscount(%03u) seqno(%03u) }: %s\n",
-				name, nr, ns, nso, nd, dnreqs, 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);
+				"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) }: %s\n", name, nr, ns, nso, nd, dnreqs, str);
+				"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\n", name, type,
-				str);
+		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__)
+#define test_mach_debug_port(x) test_mach_debug_port(x, __func__, __LINE__)
 #else
-#define test_mach_debug_port(x)
+#define test_mach_debug_port(x) (void)(x)
 #endif
 
 static dispatch_group_t g;
@@ -112,6 +114,11 @@
 		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);
 		});
@@ -431,6 +438,7 @@
 	dispatch_source_cancel(ds);
 	dispatch_release(ds);
 	test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, 0);
+	dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
 }
 
 int

Modified: trunk/testing/dispatch_drift.c
===================================================================
--- trunk/testing/dispatch_drift.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_drift.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -28,19 +28,16 @@
 #include <bsdtests.h>
 #include "dispatch_test.h"
 
-#if TARGET_OS_EMBEDDED
-#define ACCEPTABLE_DRIFT 0.002
-#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;
-	// 10 times a second
-	uint64_t interval = 1000000000 / 10;
+	__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;
@@ -67,15 +64,17 @@
 		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) {
-			if (drift < 0) {
-				drift = -drift;
+			drift_sum /= count - 1;
+			if (drift_sum < 0) {
+				drift_sum = -drift_sum;
 			}
 			double acceptable_drift = ACCEPTABLE_DRIFT;
-			test_double_less_than("drift", drift, acceptable_drift);
+			test_double_less_than("drift", drift_sum, acceptable_drift);
 			test_stop();
 		}
 		last_jitter = jitter;

Modified: trunk/testing/dispatch_group.c
===================================================================
--- trunk/testing/dispatch_group.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_group.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -33,6 +33,14 @@
 #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*);
+
 dispatch_group_t
 create_group(size_t count, int delay)
 {
@@ -57,13 +65,10 @@
 	return group;
 }
 
-int
-main(void)
+static void
+test_group(void *ctxt __attribute__((unused)))
 {
 	long res;
-
-	dispatch_test_start("Dispatch Group");
-
 	dispatch_group_t group;
 
 	group = create_group(100, 0);
@@ -95,15 +100,95 @@
 	test_ptr_notnull("dispatch_group_async", group);
 
 	dispatch_group_notify(group, dispatch_get_main_queue(), ^{
-		dispatch_queue_t m = dispatch_get_main_queue();
-		dispatch_queue_t c = dispatch_get_current_queue();
-		test_ptr("Notification Received", m, c);
-		test_stop();
+		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
+			eh = 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 = 0; i < LOOP_COUNT; i++) {
+		if (!((i+1) % (LOOP_COUNT/10))) {
+			fprintf(stderr, "#%ld\n", i+1);
+		}
+		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, 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;

Modified: trunk/testing/dispatch_io.c
===================================================================
--- trunk/testing/dispatch_io.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_io.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -65,7 +65,7 @@
 #endif
 
 static void
-test_io_close(int with_timer)
+test_io_close(int with_timer, bool from_path)
 {
 	#define chunks 4
 	#define READSIZE (512*1024)
@@ -80,8 +80,8 @@
 		test_errno("open", errno, 0);
 		test_stop();
 	}
-	if (fcntl(fd, F_NOCACHE, 1)) {
-		test_errno("fcntl F_NOCACHE", errno, 0);
+	if (fcntl(fd, F_GLOBAL_NOCACHE, 1) == -1) {
+		test_errno("fcntl F_GLOBAL_NOCACHE", errno, 0);
 		test_stop();
 	}
 	struct stat sb;
@@ -94,12 +94,21 @@
 	dispatch_source_t t = NULL;
 	dispatch_group_t g = dispatch_group_create();
 	dispatch_group_enter(g);
-	dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd,
-			dispatch_get_global_queue(0, 0), ^(int error) {
+	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);
@@ -147,7 +156,8 @@
 			}
 		});
 	}
-	dispatch_io_close(io, /* NO STOP */ 0);
+	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);
@@ -332,8 +342,8 @@
 		test_stop();
 	}
 	// disable caching also for extra fd opened by dispatch_io_create_with_path
-	if (fcntl(fd, F_GLOBAL_NOCACHE, 1)) {
-		test_errno("fcntl F_GLOBAL_NOCACHE failed", errno, 0);
+	if (fcntl(fd, F_GLOBAL_NOCACHE, 1) == -1) {
+		test_errno("fcntl F_GLOBAL_NOCACHE", errno, 0);
 		test_stop();
 	}
 	switch (option) {
@@ -476,7 +486,7 @@
 static void
 test_read_many_files(void)
 {
-	char *paths[] = {"/usr/include", NULL};
+	char *paths[] = {"/usr/lib", NULL};
 	dispatch_group_t g = dispatch_group_create();
 	dispatch_semaphore_t s = dispatch_semaphore_create(maxopenfiles);
 	uint64_t start;
@@ -664,9 +674,15 @@
 	dispatch_test_start("Dispatch IO");
 	dispatch_async(dispatch_get_main_queue(), ^{
 #if DISPATCHTEST_IO
-		test_io_close(0 /* without timer */ );
-		test_io_close(1 /* with channel interval */);
-		test_io_close(2 /* with external timer */);
+		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();

Modified: trunk/testing/dispatch_priority.c
===================================================================
--- trunk/testing/dispatch_priority.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_priority.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -34,32 +34,40 @@
 static volatile int done;
 
 #ifdef DISPATCH_QUEUE_PRIORITY_BACKGROUND // <rdar://problem/7439794>
-
-#define PRIORITIES 4
-char *labels[PRIORITIES] = { "BACKGROUND", "LOW", "DEFAULT", "HIGH" };
-int priorities[PRIORITIES] = { DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_PRIORITY_LOW, DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_HIGH };
-
+#define USE_BACKGROUND_PRIORITY 1
 #else
+#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
+#endif
 
-#define PRIORITIES 3
-char *labels[PRIORITIES] = { "LOW", "DEFAULT", "HIGH" };
-int priorities[PRIORITIES] = { DISPATCH_QUEUE_PRIORITY_LOW, DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_HIGH };
+#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 2000000
+#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];
 
-#define ITERATIONS (long)(PRIORITIES * n_blocks() * 0.50)
 static volatile long iterations;
+static long total;
+static size_t prio0, priorities = PRIORITIES;
 
 int
 n_blocks(void)
@@ -78,11 +86,12 @@
 void
 histogram(void)
 {
-	long total = 0;
-	size_t x,y;
-	for (y = 0; y < PRIORITIES; ++y) {
+	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);
-		total += counts[y].count;
+		completed += counts[y].count;
 
 		double fraction = (double)counts[y].count / (double)n_blocks();
 		double value = fraction * (double)80;
@@ -92,9 +101,19 @@
 		printf("\n");
 	}
 
-	test_long("blocks completed", total, ITERATIONS);
-	test_long_less_than("high priority precedence", counts[0].count,
-			counts[PRIORITIES-1].count);
+	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
@@ -115,8 +134,10 @@
 			__sync_add_and_fetch(&done, 1);
 			usleep(100000);
 			histogram();
-			test_stop();
-			exit(0);
+			dispatch_time_t delay = DISPATCH_TIME_NOW;
+			dispatch_after(delay, dispatch_get_main_queue(), ^{
+				test_stop();
+			});
 		}
 	}
 }
@@ -136,43 +157,46 @@
 main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
 {
 	dispatch_queue_t q[PRIORITIES];
-	int i;
+	size_t i;
 
-	iterations = ITERATIONS;
+#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)");
-	for(i = 0; i < PRIORITIES; i++) {
-#if DISPATCH_API_VERSION < 20100518 // <rdar://problem/7790099>
-		q[i] = dispatch_queue_create(labels[i], NULL);
 #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);
-#endif
 		test_ptr_notnull("q[i]", q[i]);
 		assert(q[i]);
 		dispatch_suspend(q[i]);
-		dispatch_set_target_queue(q[i], dispatch_get_global_queue(priorities[i], 0));
-#if DISPATCH_API_VERSION < 20100518 // <rdar://problem/7790099>
-		dispatch_queue_set_width(q[i], LONG_MAX);
+		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
 	}
-#else
-	dispatch_test_start("Dispatch Priority");
-	for(i = 0; i < PRIORITIES; i++) {
-		q[i] = dispatch_get_global_queue(priorities[i], 0);
-	}
-#endif
 
-	for(i = 0; i < PRIORITIES; i++) {
+	for (i = prio0; i < prio0 + priorities; i++) {
 		submit_work(q[i], &counts[i].count);
 	}
 
-#if USE_SET_TARGET_QUEUE
-	for(i = 0; i < PRIORITIES; i++) {
+	for (i = prio0; i < prio0 + priorities; i++) {
 		dispatch_resume(q[i]);
 		dispatch_release(q[i]);
 	}
-#endif
 
 	dispatch_main();
 

Modified: trunk/testing/dispatch_queue_finalizer.c
===================================================================
--- trunk/testing/dispatch_queue_finalizer.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_queue_finalizer.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -69,6 +69,7 @@
 	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

Modified: trunk/testing/dispatch_suspend_timer.c
===================================================================
--- trunk/testing/dispatch_suspend_timer.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_suspend_timer.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -45,7 +45,7 @@
 	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());
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
 
 	__block int i = 0, i_prime = 0;
 	__block int j = 0;

Modified: trunk/testing/dispatch_test.c
===================================================================
--- trunk/testing/dispatch_test.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_test.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -19,15 +19,20 @@
  */
 
 #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>
 #include <sys/event.h>
 #include <assert.h>
 
+#include <dispatch/dispatch.h>
+
 void test_start(const char* desc);
 
 void
@@ -56,3 +61,10 @@
 	close(kq);
 	return r > 0;
 }
+
+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);
+}

Modified: trunk/testing/dispatch_test.h
===================================================================
--- trunk/testing/dispatch_test.h	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_test.h	2012-08-09 05:09:03 UTC (rev 215)
@@ -20,6 +20,7 @@
 
 #include <sys/cdefs.h>
 #include <stdbool.h>
+#include <dispatch/dispatch.h>
 
 #define test_group_wait(g) do { \
 	if (dispatch_group_wait(g, dispatch_time(DISPATCH_TIME_NOW, \
@@ -34,4 +35,7 @@
 
 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)
+
 __END_DECLS

Modified: trunk/testing/dispatch_timer.c
===================================================================
--- trunk/testing/dispatch_timer.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_timer.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -46,7 +46,7 @@
 	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());
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
 
 	uint64_t j;
 
@@ -73,16 +73,13 @@
 	__block int i = 0;
 
 	dispatch_source_t s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_q);
-	dispatch_debug(s, "fresh timer:");
 	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_debug(s, "pre release timer:");
 		dispatch_release(s);
-		dispatch_debug(s, "post release timer:");
 	});
 
 	dispatch_source_set_event_handler(s, ^{

Modified: trunk/testing/dispatch_timer_bit31.c
===================================================================
--- trunk/testing/dispatch_timer_bit31.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_timer_bit31.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -34,7 +34,7 @@
 	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());
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
 
 	struct timeval start_time;
 

Modified: trunk/testing/dispatch_timer_set_time.c
===================================================================
--- trunk/testing/dispatch_timer_set_time.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_timer_set_time.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -35,7 +35,7 @@
 	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());
+	//test_ptr("dispatch_get_main_queue", main_q, dispatch_get_current_queue());
 
 	__block int i = 0;
 	struct timeval start_time;

Added: trunk/testing/dispatch_transform.c
===================================================================
--- trunk/testing/dispatch_transform.c	                        (rev 0)
+++ trunk/testing/dispatch_transform.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -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
+

Modified: trunk/testing/dispatch_vm.c
===================================================================
--- trunk/testing/dispatch_vm.c	2012-08-09 05:08:56 UTC (rev 214)
+++ trunk/testing/dispatch_vm.c	2012-08-09 05:09:03 UTC (rev 215)
@@ -29,6 +29,7 @@
 #include <time.h>
 
 #include <dispatch/dispatch.h>
+#include <dispatch/private.h>
 
 #include <bsdtests.h>
 #include "dispatch_test.h"
@@ -36,7 +37,7 @@
 #if defined(DISPATCH_SOURCE_TYPE_VM) && defined(NOTE_VM_PRESSURE)
 
 #if TARGET_OS_EMBEDDED
-#define ALLOC_SIZE ((size_t)(1024*1024*5ul))	// 5MB
+#define ALLOC_SIZE ((size_t)(1024*1024*1ul))	// 1MB
 #define NOTIFICATIONS 1
 #else
 #define ALLOC_SIZE ((size_t)(1024*1024*20ul))	// 20MB
@@ -60,7 +61,7 @@
 
 #define log_msg(msg, ...) \
 do { \
-	fprintf(stderr, "[%2ds] " msg, (int)(time(NULL) - initial), ## __VA_ARGS__);\
+	fprintf(stderr, "[%2ds] " msg, (int)(time(NULL) - initial), ##__VA_ARGS__);\
 } while (0)
 
 static bool
@@ -102,7 +103,7 @@
 int
 main(void)
 {
-	dispatch_test_start("Dispatch VM Pressure test"); // <rdar://problem/7000945>
+	dispatch_test_start("Dispatch VM Pressure test"); // rdar://problem/7000945
 	if (!dispatch_test_check_evfilt_vm()) {
 		test_skip("EVFILT_VM not supported");
 		test_stop();
@@ -142,7 +143,8 @@
 	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) {
+		while (handler_call_count < NOTIFICATIONS &&
+				page_count < max_page_count) {
 			void *p = valloc(ALLOC_SIZE);
 			if (!p) {
 				break;
@@ -163,9 +165,12 @@
 			dispatch_async(vm_queue, ^{cleanup();});
 			return;
 		}
-		dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), vm_queue, ^{
-			test_long_less_than("VM Pressure fired", NOTIFICATIONS - 1, handler_call_count);
-			test_long_less_than("VM Pressure stopped firing", handler_call_count, 4);
+		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();
 		});
 	});
@@ -176,7 +181,8 @@
 int
 main(void)
 {
-	dispatch_test_start("Dispatch VM Pressure test - No DISPATCH_SOURCE_TYPE_VM");
+	dispatch_test_start("Dispatch VM Pressure test"
+			" - No DISPATCH_SOURCE_TYPE_VM");
 	test_stop();
 	return 0;
 }
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/libdispatch-changes/attachments/20120808/59c32e7d/attachment-0001.html>


More information about the libdispatch-changes mailing list