Merge pull request #330 from dgrove-oss/increase-test-timeout

Increase test timeout value by 4x

https://bugs.swift.org/browse/SR-6792
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43bc70d..19ea9e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -83,6 +83,7 @@
 option(ENABLE_TESTING "build libdispatch tests" ON)
 
 if(CMAKE_SYSTEM_NAME STREQUAL Linux OR
+   CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR
    CMAKE_SYSTEM_NAME STREQUAL Android)
   set(USE_GOLD_LINKER_DEFAULT ON)
 else()
@@ -95,6 +96,7 @@
 
 if(CMAKE_SYSTEM_NAME STREQUAL Linux OR
    CMAKE_SYSTEM_NAME STREQUAL Android OR
+   CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR
    CMAKE_SYSTEM_NAME STREQUAL Windows)
   set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT ON)
 else()
@@ -120,6 +122,7 @@
 
 if(CMAKE_SYSTEM_NAME STREQUAL Linux OR
    CMAKE_SYSTEM_NAME STREQUAL Android OR
+   CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR
    CMAKE_SYSTEM_NAME STREQUAL Windows)
   add_library(BlocksRuntime
               STATIC
@@ -264,6 +267,10 @@
   set(ENABLE_DTRACE_DEFAULT OFF)
 endif()
 
+if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+  add_definitions(-D_WITH_DPRINTF)
+endif()
+
 if(ENABLE_DTRACE STREQUAL "")
   find_program(dtrace_EXECUTABLE dtrace)
   if(dtrace_EXECUTABLE)
diff --git a/cmake/config.h.in b/cmake/config.h.in
index c858589..12a2530 100644
--- a/cmake/config.h.in
+++ b/cmake/config.h.in
@@ -139,10 +139,10 @@
 #cmakedefine HAVE_PTHREAD_MACHDEP_H
 
 /* Define to 1 if you have the `pthread_main_np' function. */
-#cmakedefine HAVE_PTHREAD_MAIN_NP
+#cmakedefine01 HAVE_PTHREAD_MAIN_NP
 
 /* Define to 1 if you have the <pthread_np.h> header file. */
-#cmakedefine HAVE_PTHREAD_NP_H
+#cmakedefine01 HAVE_PTHREAD_NP_H
 
 /* Define to 1 if you have the <pthread/qos.h> header file. */
 #cmakedefine HAVE_PTHREAD_QOS_H
diff --git a/dispatch/base.h b/dispatch/base.h
index 4c82b01..0c5f8c9 100644
--- a/dispatch/base.h
+++ b/dispatch/base.h
@@ -112,6 +112,14 @@
 #define DISPATCH_LINUX_UNAVAILABLE()
 #endif
 
+#ifdef __FreeBSD__
+#define DISPATCH_FREEBSD_UNAVAILABLE() \
+		DISPATCH_UNAVAILABLE_MSG( \
+		"This interface is unavailable on FreeBSD systems")
+#else
+#define DISPATCH_FREEBSD_UNAVAILABLE()
+#endif
+
 #ifndef DISPATCH_ALIAS_V2
 #if TARGET_OS_MAC
 #define DISPATCH_ALIAS_V2(sym)	 __asm__("_" #sym "$V2")
diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h
index 2d45b83..a4b5459 100644
--- a/dispatch/dispatch.h
+++ b/dispatch/dispatch.h
@@ -26,8 +26,8 @@
 #include <os/availability.h>
 #include <TargetConditionals.h>
 #include <os/base.h>
-#elif defined(__linux__)
-#include <os/linux_base.h>
+#elif defined(__linux__) || defined(__FreeBSD__)
+#include <os/generic_unix_base.h>
 #endif
 
 #include <sys/types.h>
@@ -40,7 +40,7 @@
 #endif
 #include <fcntl.h>
 
-#if defined(__linux__) && defined(__has_feature)
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__has_feature)
 #if __has_feature(modules)
 #if !defined(__arm__)
 #include <stdio.h> // for off_t (to match Glibc.modulemap)
diff --git a/os/CMakeLists.txt b/os/CMakeLists.txt
index e1e93a4..2c4d32e 100644
--- a/os/CMakeLists.txt
+++ b/os/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 install(FILES
           object.h
-          linux_base.h
+          generic_unix_base.h
         DESTINATION
           "${INSTALL_OS_HEADERS_DIR}")
 
diff --git a/os/Makefile.am b/os/Makefile.am
index d009a37..8be68d7 100644
--- a/os/Makefile.am
+++ b/os/Makefile.am
@@ -10,7 +10,7 @@
 
 os_HEADERS=	\
 	object.h \
-	linux_base.h
+	generic_unix_base.h
 
 noinst_HEADERS=	\
 	object_private.h \
diff --git a/os/linux_base.h b/os/generic_unix_base.h
similarity index 93%
rename from os/linux_base.h
rename to os/generic_unix_base.h
index 58b4971..26c664c 100644
--- a/os/linux_base.h
+++ b/os/generic_unix_base.h
@@ -10,12 +10,17 @@
  *
  */
 
-#ifndef __OS_LINUX_BASE__
-#define __OS_LINUX_BASE__
+#ifndef __OS_GENERIC_UNIX_BASE__
+#define __OS_GENERIC_UNIX_BASE__
 
 #if __has_include(<sys/sysmacros.h>)
 #include <sys/sysmacros.h>
 #endif
+
+#if defined(__FreeBSD__)
+#include <libutil.h>
+#include <fcntl.h>
+#endif
 #include <sys/param.h>
 
 #if __has_include(<sys/cdefs.h>)
@@ -120,4 +125,4 @@
 #endif
 #define OS_NOTHROW
 
-#endif /* __OS_LINUX_BASE__ */
+#endif /* __OS_GENERIC_UNIX_BASE__ */
diff --git a/os/object.h b/os/object.h
index 100721f..3666c33 100644
--- a/os/object.h
+++ b/os/object.h
@@ -26,8 +26,8 @@
 #include <os/availability.h>
 #include <TargetConditionals.h>
 #include <os/base.h>
-#elif defined(__linux__)
-#include <os/linux_base.h>
+#elif defined(__linux__) || defined(__FreeBSD__)
+#include <os/generic_unix_base.h>
 #endif
 
 /*!
diff --git a/os/voucher_activity_private.h b/os/voucher_activity_private.h
index 8ce0ef5..3df9023 100644
--- a/os/voucher_activity_private.h
+++ b/os/voucher_activity_private.h
@@ -26,7 +26,7 @@
 #include <mach/mach_time.h>
 #include <firehose/tracepoint_private.h>
 #endif
-#ifndef __linux__
+#if __APPLE__
 #include <os/base.h>
 #include <os/availability.h>
 #endif
diff --git a/os/voucher_private.h b/os/voucher_private.h
index aecbbc9..3e28091 100644
--- a/os/voucher_private.h
+++ b/os/voucher_private.h
@@ -21,7 +21,7 @@
 #ifndef __OS_VOUCHER_PRIVATE__
 #define __OS_VOUCHER_PRIVATE__
 
-#ifndef __linux__
+#if __APPLE__
 #include <os/base.h>
 #include <os/availability.h>
 #endif
diff --git a/private/private.h b/private/private.h
index 228ce2c..cb4f676 100644
--- a/private/private.h
+++ b/private/private.h
@@ -32,8 +32,8 @@
 #include <os/availability.h>
 #include <TargetConditionals.h>
 #include <os/base.h>
-#elif defined(__linux__)
-#include <os/linux_base.h>
+#elif defined(__linux__) || defined(__FreeBSD__)
+#include <os/generic_unix_base.h>
 #endif
 
 #if TARGET_OS_MAC
@@ -172,7 +172,7 @@
 
 #if TARGET_OS_MAC
 #define DISPATCH_COCOA_COMPAT 1
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__FreeBSD__)
 #define DISPATCH_COCOA_COMPAT 1
 #else
 #define DISPATCH_COCOA_COMPAT 0
@@ -184,7 +184,7 @@
 
 #if TARGET_OS_MAC
 typedef mach_port_t dispatch_runloop_handle_t;
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__FreeBSD__)
 typedef int dispatch_runloop_handle_t;
 #else
 #error "runloop support not implemented on this platform"
diff --git a/private/queue_private.h b/private/queue_private.h
index 06fca91..f71e5e3 100644
--- a/private/queue_private.h
+++ b/private/queue_private.h
@@ -49,6 +49,13 @@
 
 #define DISPATCH_QUEUE_FLAGS_MASK (DISPATCH_QUEUE_OVERCOMMIT)
 
+// On FreeBSD pthread_attr_t is a typedef to a pointer type
+#if defined(__FreeBSD__)
+#  define DISPATCH_QUEUE_NULLABLE_PTHREAD_ATTR_PTR _Nullable
+#else
+#  define DISPATCH_QUEUE_NULLABLE_PTHREAD_ATTR_PTR
+#endif
+
 /*!
  * @function dispatch_queue_attr_make_with_overcommit
  *
@@ -227,7 +234,7 @@
 DISPATCH_NOTHROW
 dispatch_queue_t
 dispatch_pthread_root_queue_create(const char *_Nullable label,
-	unsigned long flags, const pthread_attr_t *_Nullable attr,
+	unsigned long flags, const pthread_attr_t DISPATCH_QUEUE_NULLABLE_PTHREAD_ATTR_PTR *_Nullable attr,
 	dispatch_block_t _Nullable configure);
 
 /*!
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0dd6a3c..c9c55b5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -47,8 +47,8 @@
               shims/atomic_sfb.h
               shims/getprogname.h
               shims/hw_config.h
-              shims/linux_stubs.c
-              shims/linux_stubs.h
+              shims/generic_unix_stubs.c
+              shims/generic_unix_stubs.h
               shims/lock.c
               shims/lock.h
               shims/perfmon.h
@@ -101,6 +101,7 @@
                       -fmodule-map-file=${CMAKE_SOURCE_DIR}/dispatch/module.modulemap
                     SWIFT_FLAGS
                       -I ${CMAKE_SOURCE_DIR}
+                      -I/usr/include
                       ${swift_optimization_flags}
                     DEPENDS
                       ${CMAKE_SOURCE_DIR}/dispatch/module.modulemap)
diff --git a/src/Makefile.am b/src/Makefile.am
index 58dcead..e6d31f5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,8 +59,8 @@
 	shims/atomic_sfb.h		\
 	shims/getprogname.h		\
 	shims/hw_config.h		\
-	shims/linux_stubs.c		\
-	shims/linux_stubs.h		\
+	shims/generic_unix_stubs.c		\
+	shims/generic_unix_stubs.h		\
 	shims/lock.c			\
 	shims/lock.h			\
 	shims/perfmon.h			\
diff --git a/src/block.cpp b/src/block.cpp
index 2a6f007..6936ada 100644
--- a/src/block.cpp
+++ b/src/block.cpp
@@ -109,7 +109,7 @@
 // The compiler hides the name of the function it generates, and changes it if
 // we try to reference it directly, but the linker still sees it.
 extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 		asm("___dispatch_block_create_block_invoke");
 #else
 		asm("____dispatch_block_create_block_invoke");
diff --git a/src/event/event_config.h b/src/event/event_config.h
index 60f776f..02508c0 100644
--- a/src/event/event_config.h
+++ b/src/event/event_config.h
@@ -76,16 +76,14 @@
 #if DISPATCH_EVENT_BACKEND_KEVENT
 #	if defined(EV_SET_QOS)
 #		define DISPATCH_USE_KEVENT_QOS 1
-#		ifndef KEVENT_FLAG_IMMEDIATE
-#		define KEVENT_FLAG_IMMEDIATE 0x001
-#		endif
-#		ifndef KEVENT_FLAG_ERROR_EVENTS
-#		define KEVENT_FLAG_ERROR_EVENTS 0x002
-#		endif
 #	else
 #		define DISPATCH_USE_KEVENT_QOS 0
 #	endif
 
+#	ifndef KEVENT_FLAG_ERROR_EVENTS
+#		define KEVENT_FLAG_ERROR_EVENTS 0x002
+#	endif
+
 #	ifdef NOTE_LEEWAY
 #		define DISPATCH_HAVE_TIMER_COALESCING 1
 #   else
@@ -106,6 +104,14 @@
 #	define NOTE_FUNLOCK 0x00000100
 #	endif
 
+// FreeBSD's kevent does not support those
+#	ifndef NOTE_ABSOLUTE
+#	define NOTE_ABSOLUTE 0
+#	endif
+#	ifndef NOTE_EXITSTATUS
+#	define NOTE_EXITSTATUS 0
+#	endif
+
 #	if HAVE_DECL_NOTE_REAP
 #	if defined(NOTE_REAP) && defined(__APPLE__)
 #	undef NOTE_REAP
@@ -146,9 +152,15 @@
 
 #	define DISPATCH_HAVE_TIMER_QOS 0
 #	define DISPATCH_HAVE_TIMER_COALESCING 0
-#	define KEVENT_FLAG_IMMEDIATE 0x001
 #endif // !DISPATCH_EVENT_BACKEND_KEVENT
 
+// These flags are used by dispatch generic code and
+// translated back by the various backends to similar semantics
+// hence must be defined even on non Darwin platforms
+#ifndef KEVENT_FLAG_IMMEDIATE
+#	define KEVENT_FLAG_IMMEDIATE 0x001
+#endif
+
 #ifdef EV_UDATA_SPECIFIC
 #	define DISPATCH_EV_DIRECT		(EV_UDATA_SPECIFIC|EV_DISPATCH)
 #else
diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c
index 8fe76d5..e7dafc7 100644
--- a/src/event/event_kevent.c
+++ b/src/event/event_kevent.c
@@ -32,6 +32,8 @@
 #define DISPATCH_KEVENT_MUXED_MARKER  1ul
 #define DISPATCH_MACH_AUDIT_TOKEN_PID (5)
 
+#define dispatch_kevent_udata_t  typeof(((dispatch_kevent_t)NULL)->udata)
+
 typedef struct dispatch_muxnote_s {
 	TAILQ_ENTRY(dispatch_muxnote_s) dmn_list;
 	TAILQ_HEAD(, dispatch_unote_linkage_s) dmn_unotes_head;
@@ -59,8 +61,13 @@
 static TAILQ_HEAD(dispatch_muxnote_bucket_s, dispatch_muxnote_s)
 _dispatch_sources[DSL_HASH_SIZE];
 
+#if defined(__APPLE__)
 #define DISPATCH_NOTE_CLOCK_WALL NOTE_MACH_CONTINUOUS_TIME
 #define DISPATCH_NOTE_CLOCK_MACH 0
+#else
+#define DISPATCH_NOTE_CLOCK_WALL 0
+#define DISPATCH_NOTE_CLOCK_MACH 0
+#endif
 
 static const uint32_t _dispatch_timer_index_to_fflags[] = {
 #define DISPATCH_TIMER_FFLAGS_INIT(kind, qos, note) \
@@ -191,17 +198,20 @@
 	_dispatch_debug("%s kevent[%p] %s= { ident = 0x%llx, filter = %s, "
 			"flags = %s (0x%x), fflags = 0x%x, data = 0x%llx, udata = 0x%llx, "
 			"qos = 0x%x, ext[0] = 0x%llx, ext[1] = 0x%llx, ext[2] = 0x%llx, "
-			"ext[3] = 0x%llx }: %s #%u", verb, kev, i_n, kev->ident,
-			_evfiltstr(kev->filter), _evflagstr(kev->flags, flagstr,
-			sizeof(flagstr)), kev->flags, kev->fflags, kev->data, kev->udata,
-			kev->qos, kev->ext[0], kev->ext[1], kev->ext[2], kev->ext[3],
+			"ext[3] = 0x%llx }: %s #%u", verb, kev, i_n,
+			(unsigned long long)kev->ident, _evfiltstr(kev->filter),
+			_evflagstr(kev->flags, flagstr, sizeof(flagstr)), kev->flags, kev->fflags,
+			(unsigned long long)kev->data, (unsigned long long)kev->udata, kev->qos,
+			kev->ext[0], kev->ext[1], kev->ext[2], kev->ext[3],
 			function, line);
 #else
 	_dispatch_debug("%s kevent[%p] %s= { ident = 0x%llx, filter = %s, "
 			"flags = %s (0x%x), fflags = 0x%x, data = 0x%llx, udata = 0x%llx}: "
 			"%s #%u", verb, kev, i_n,
-			kev->ident, _evfiltstr(kev->filter), _evflagstr(kev->flags, flagstr,
-			sizeof(flagstr)), kev->flags, kev->fflags, kev->data, kev->udata,
+			(unsigned long long)kev->ident, _evfiltstr(kev->filter),
+			_evflagstr(kev->flags, flagstr, sizeof(flagstr)), kev->flags,
+			kev->fflags, (unsigned long long)kev->data,
+			(unsigned long long)kev->udata,
 			function, line);
 #endif
 }
@@ -334,10 +344,17 @@
 }
 
 DISPATCH_ALWAYS_INLINE
+static inline bool
+_dispatch_kevent_unote_is_muxed(dispatch_kevent_t ke)
+{
+	return ((uintptr_t)ke->udata) & DISPATCH_KEVENT_MUXED_MARKER;
+}
+
+DISPATCH_ALWAYS_INLINE
 static dispatch_unote_t
 _dispatch_kevent_get_unote(dispatch_kevent_t ke)
 {
-	dispatch_assert((ke->udata & DISPATCH_KEVENT_MUXED_MARKER) == 0);
+	dispatch_assert(_dispatch_kevent_unote_is_muxed(ke) == false);
 	return (dispatch_unote_t){ ._du = (dispatch_unote_class_t)ke->udata };
 }
 
@@ -356,7 +373,7 @@
 		}
 		// for EV_DELETE if the update was deferred we may have reclaimed
 		// the udata already, and it is unsafe to dereference it now.
-	} else if (ke->udata & DISPATCH_KEVENT_MUXED_MARKER) {
+	} else if (_dispatch_kevent_unote_is_muxed(ke)) {
 		ke->flags |= _dispatch_kevent_get_muxnote(ke)->dmn_kev.flags;
 	} else if (ke->udata) {
 		if (!_dispatch_unote_registered(_dispatch_kevent_get_unote(ke))) {
@@ -463,7 +480,7 @@
 	}
 #endif
 
-	if (ke->udata & DISPATCH_KEVENT_MUXED_MARKER) {
+	if (_dispatch_kevent_unote_is_muxed(ke)) {
 		return _dispatch_kevent_merge_muxed(ke);
 	}
 	return _dispatch_kevent_merge(_dispatch_kevent_get_unote(ke), ke);
@@ -480,7 +497,7 @@
 		.ident = 1,
 		.filter = EVFILT_USER,
 		.flags = EV_ADD|EV_CLEAR,
-		.udata = (uintptr_t)DISPATCH_WLH_MANAGER,
+		.udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER,
 	};
 	int kqfd;
 
@@ -542,7 +559,7 @@
 			.filter = EVFILT_USER,
 			.flags = EV_ADD|EV_CLEAR,
 			.qos = _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG,
-			.udata = (uintptr_t)DISPATCH_WLH_MANAGER,
+			.udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER,
 		};
 retry:
 		r = kevent_qos(kqfd, &ke, 1, NULL, 0, NULL, NULL,
@@ -601,7 +618,7 @@
 		for (r = 0; r < n; r++) {
 			ke[r].flags |= EV_RECEIPT;
 		}
-		out_n = n;
+		n_out = n;
 	}
 #endif
 
@@ -614,6 +631,8 @@
 		}
 		r = kevent_qos(kqfd, ke, n, ke_out, n_out, buf, avail, flags);
 #else
+		(void)buf;
+		(void)avail;
 		const struct timespec timeout_immediately = {}, *timeout = NULL;
 		if (flags & KEVENT_FLAG_IMMEDIATE) timeout = &timeout_immediately;
 		r = kevent(kqfd, ke, n, ke_out, n_out, timeout);
@@ -717,19 +736,20 @@
 		.ident  = du->du_ident,
 		.filter = dst->dst_filter,
 		.flags  = flags,
-		.udata  = (uintptr_t)du,
+		.udata  = (dispatch_kevent_udata_t)du,
 		.fflags = du->du_fflags | dst->dst_fflags,
 		.data   = (typeof(dk->data))dst->dst_data,
 #if DISPATCH_USE_KEVENT_QOS
 		.qos    = (typeof(dk->qos))pp,
 #endif
 	};
+	(void)pp; // if DISPATCH_USE_KEVENT_QOS == 0
 }
 
 DISPATCH_ALWAYS_INLINE
 static inline int
 _dispatch_kq_deferred_find_slot(dispatch_deferred_items_t ddi,
-		int16_t filter, uint64_t ident, uint64_t udata)
+		int16_t filter, uint64_t ident, dispatch_kevent_udata_t udata)
 {
 	dispatch_kevent_t events = ddi->ddi_eventlist;
 	int i;
@@ -825,7 +845,7 @@
 
 	if (ddi && wlh == _dispatch_get_wlh()) {
 		int slot = _dispatch_kq_deferred_find_slot(ddi,
-				du->du_filter, du->du_ident, (uintptr_t)du);
+				du->du_filter, du->du_ident, (dispatch_kevent_udata_t)du);
 		if (slot < ddi->ddi_nevents) {
 			// <rdar://problem/26202376> when deleting and an enable is pending,
 			// we must merge EV_ENABLE to do an immediate deletion
@@ -924,6 +944,7 @@
 #define _dispatch_unote_muxnote_find(dmb, du, wlh) \
 		_dispatch_muxnote_find(dmb, wlh, du._du->du_ident, du._du->du_filter)
 
+#if HAVE_MACH
 DISPATCH_ALWAYS_INLINE
 static inline dispatch_muxnote_t
 _dispatch_mach_muxnote_find(mach_port_t name, int16_t filter)
@@ -932,6 +953,7 @@
 	dmb = _dispatch_muxnote_bucket(name, filter);
 	return _dispatch_muxnote_find(dmb, DISPATCH_WLH_ANON, name, filter);
 }
+#endif
 
 DISPATCH_NOINLINE
 static bool
@@ -961,7 +983,8 @@
 #if DISPATCH_USE_KEVENT_QOS
 		dmn->dmn_kev.qos = _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG;
 #endif
-		dmn->dmn_kev.udata = (uintptr_t)dmn | DISPATCH_KEVENT_MUXED_MARKER;
+		dmn->dmn_kev.udata = (dispatch_kevent_udata_t)((uintptr_t)dmn |
+				DISPATCH_KEVENT_MUXED_MARKER);
 		dmn->dmn_wlh = wlh;
 		if (unlikely(du._du->du_type->dst_update_mux)) {
 			installed = du._du->du_type->dst_update_mux(dmn);
@@ -984,11 +1007,13 @@
 		TAILQ_INSERT_TAIL(&dmn->dmn_unotes_head, dul, du_link);
 		dul->du_muxnote = dmn;
 
+#if HAVE_MACH
 		if (du._du->du_filter == DISPATCH_EVFILT_MACH_NOTIFICATION) {
 			bool armed = DISPATCH_MACH_NOTIFICATION_ARMED(&dmn->dmn_kev);
 			os_atomic_store2o(du._dmsr, dmsr_notification_armed, armed,relaxed);
 		}
 		du._du->du_wlh = DISPATCH_WLH_ANON;
+#endif
 	}
 	return installed;
 }
@@ -1038,9 +1063,12 @@
 	dispatch_muxnote_t dmn = dul->du_muxnote;
 	bool update = false, dispose = false;
 
+#if HAVE_MACH
 	if (dmn->dmn_kev.filter == DISPATCH_EVFILT_MACH_NOTIFICATION) {
 		os_atomic_store2o(du._dmsr, dmsr_notification_armed, false, relaxed);
 	}
+#endif
+
 	dispatch_assert(du._du->du_wlh == DISPATCH_WLH_ANON);
 	du._du->du_wlh = NULL;
 	TAILQ_REMOVE(&dmn->dmn_unotes_head, dul, du_link);
@@ -1129,7 +1157,7 @@
 			.ident  = 1,
 			.filter = EVFILT_USER,
 			.fflags = NOTE_TRIGGER,
-			.udata = (uintptr_t)DISPATCH_WLH_MANAGER,
+			.udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER,
 		};
 		return _dispatch_kq_deferred_update(DISPATCH_WLH_ANON, &ke);
 	} else if (wlh && wlh != DISPATCH_WLH_ANON) {
@@ -1262,7 +1290,7 @@
 		.flags = action | EV_ONESHOT,
 		.fflags = _dispatch_timer_index_to_fflags[tidx],
 		.data = (int64_t)target,
-		.udata = (uintptr_t)&_dispatch_timers_heap[tidx],
+		.udata = (dispatch_kevent_udata_t)&_dispatch_timers_heap[tidx],
 #if DISPATCH_HAVE_TIMER_COALESCING
 		.ext[1] = leeway,
 #endif
@@ -1270,6 +1298,7 @@
 		.qos = _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG,
 #endif
 	};
+	(void)leeway; // if DISPATCH_HAVE_TIMER_COALESCING == 0
 
 	_dispatch_kq_deferred_update(DISPATCH_WLH_ANON, &ke);
 }
@@ -1927,11 +1956,13 @@
 		return;
 	}
 
+#if HAVE_MACH
 	DISPATCH_MACH_NOTIFICATION_ARMED(&dmn->dmn_kev) = true;
 	TAILQ_FOREACH(dul, &dmn->dmn_unotes_head, du_link) {
 		du = _dispatch_unote_linkage_get_unote(dul);
 		os_atomic_store2o(du._dmsr, dmsr_notification_armed, true, relaxed);
 	}
+#endif
 }
 
 static dispatch_unote_t
diff --git a/src/event/workqueue.c b/src/event/workqueue.c
index 73362a5..19a2476 100644
--- a/src/event/workqueue.c
+++ b/src/event/workqueue.c
@@ -66,7 +66,9 @@
 	int num_registered_tids;
 } dispatch_workq_monitor_s, *dispatch_workq_monitor_t;
 
+#if HAVE_DISPATCH_WORKQ_MONITORING
 static dispatch_workq_monitor_s _dispatch_workq_monitors[DISPATCH_QOS_MAX];
+#endif
 
 #pragma mark Implementation of the monitoring subsystem.
 
@@ -91,6 +93,9 @@
 	int worker_id = mon->num_registered_tids++;
 	mon->registered_tids[worker_id] = tid;
 	_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
+#else
+	(void)root_q;
+	(void)cls;
 #endif // HAVE_DISPATCH_WORKQ_MONITORING
 }
 
@@ -113,6 +118,9 @@
 		}
 	}
 	_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
+#else
+	(void)root_q;
+	(void)cls;
 #endif // HAVE_DISPATCH_WORKQ_MONITORING
 }
 
diff --git a/src/init.c b/src/init.c
index 6672fac..26612c0 100644
--- a/src/init.c
+++ b/src/init.c
@@ -737,7 +737,7 @@
 
 #if DISPATCH_DEBUG
 	offset += dsnprintf(&buf[offset], bufsiz - offset, "%llu\t",
-			_dispatch_absolute_time() - dispatch_log_basetime);
+			(unsigned long long)_dispatch_absolute_time() - dispatch_log_basetime);
 #endif
 	r = vsnprintf(&buf[offset], bufsiz - offset, msg, ap);
 	if (r < 0) return;
@@ -834,7 +834,7 @@
 	int r;
 #if DISPATCH_DEBUG && !DISPATCH_USE_OS_DEBUG_LOG
 	offset += dsnprintf(&buf[offset], bufsiz - offset, "%llu\t\t%p\t",
-			_dispatch_absolute_time() - dispatch_log_basetime,
+			(unsigned long long)_dispatch_absolute_time() - dispatch_log_basetime,
 			(void *)_dispatch_thread_self());
 #endif
 	if (dou._do) {
diff --git a/src/io.c b/src/io.c
index 155b6cf..80aa780 100644
--- a/src/io.c
+++ b/src/io.c
@@ -20,6 +20,11 @@
 
 #include "internal.h"
 
+#if defined(__FreeBSD__)
+#include <fcntl.h>
+#define F_RDADVISE F_RDAHEAD
+#endif
+
 #ifndef DISPATCH_IO_DEBUG
 #define DISPATCH_IO_DEBUG DISPATCH_DEBUG
 #endif
@@ -419,7 +424,7 @@
 		struct stat st;
 		_dispatch_io_syscall_switch_noerr(err,
 			(path_data->oflag & O_NOFOLLOW) == O_NOFOLLOW
-#ifndef __linux__
+#if __APPLE__
 					|| (path_data->oflag & O_SYMLINK) == O_SYMLINK
 #endif
 					? lstat(path_data->path, &st) : stat(path_data->path, &st),
@@ -627,7 +632,8 @@
 {
 	_dispatch_retain(channel);
 	dispatch_async(channel->queue, ^{
-		_dispatch_channel_debug("set interval: %llu", channel, interval);
+		_dispatch_channel_debug("set interval: %llu", channel,
+		  (unsigned long long)interval);
 		channel->params.interval = interval < INT64_MAX ? interval : INT64_MAX;
 		channel->params.interval_flags = flags;
 		_dispatch_release(channel);
@@ -1372,7 +1378,7 @@
 						break;
 				);
 			}
-			dev_t dev = major(st.st_dev);
+			dev_t dev = (dev_t)major(st.st_dev);
 			// We have to get the disk on the global dev queue. The
 			// barrier queue cannot continue until that is complete
 			dispatch_suspend(fd_entry->barrier_queue);
@@ -1459,7 +1465,7 @@
 			path_data->channel->queue);
 	_dispatch_fd_entry_debug("create: path %s", fd_entry, path_data->path);
 	if (S_ISREG(mode)) {
-		_dispatch_disk_init(fd_entry, major(dev));
+		_dispatch_disk_init(fd_entry, (dev_t)major(dev));
 	} else {
 			_dispatch_stream_init(fd_entry,
 					_dispatch_get_root_queue(DISPATCH_QOS_DEFAULT, false));
@@ -2138,7 +2144,7 @@
 {
 	_dispatch_op_debug("advise", op);
 	if (_dispatch_io_get_error(op, NULL, true)) return;
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 	// linux does not support fcntl (F_RDAVISE)
 	// define necessary datastructure and use readahead
 	struct radvisory {
@@ -2165,7 +2171,7 @@
 	}
 	advise.ra_offset = op->advise_offset;
 	op->advise_offset += advise.ra_count;
-#ifdef __linux__
+#if defined(__linux__)
 	_dispatch_io_syscall_switch(err,
 			readahead(op->fd_entry->fd, advise.ra_offset, (size_t)advise.ra_count),
 		case EINVAL: break; // fd does refer to a non-supported filetype
diff --git a/src/queue.c b/src/queue.c
index 33e5009..7725d0d 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -912,7 +912,14 @@
 static inline pid_t
 gettid(void)
 {
-	return (pid_t) syscall(SYS_gettid);
+	return (pid_t)syscall(SYS_gettid);
+}
+#elif defined(__FreeBSD__)
+DISPATCH_ALWAYS_INLINE
+static inline pid_t
+gettid(void)
+{
+	return (pid_t)pthread_getthreadid_np();
 }
 #else
 #error "SYS_gettid unavailable on this system"
@@ -4668,11 +4675,13 @@
 static void
 _dispatch_return_to_kernel(void)
 {
+#if DISPATCH_USE_KEVENT_WORKQUEUE
 	if (unlikely(_dispatch_get_wlh() == DISPATCH_WLH_ANON)) {
 		_dispatch_clear_return_to_kernel();
 	} else {
 		_dispatch_event_loop_drain(KEVENT_FLAG_IMMEDIATE);
 	}
+#endif
 }
 
 void
diff --git a/src/shims.h b/src/shims.h
index fad36bc..af3bef0 100644
--- a/src/shims.h
+++ b/src/shims.h
@@ -28,8 +28,8 @@
 #define __DISPATCH_OS_SHIMS__
 
 #include <pthread.h>
-#ifdef __linux__
-#include "shims/linux_stubs.h"
+#if defined(__linux__) || defined(__FreeBSD__)
+#include "shims/generic_unix_stubs.h"
 #endif
 
 #ifdef __ANDROID__
diff --git a/src/shims/atomic.h b/src/shims/atomic.h
index 64af8b2..5c9ce5a 100644
--- a/src/shims/atomic.h
+++ b/src/shims/atomic.h
@@ -31,6 +31,10 @@
 #error libdispatch requires C11 with <stdatomic.h>
 #endif
 
+// FreeBSD only defines _Bool in C mode. In C++ mode _Bool is not being defined.
+#if defined(__cplusplus) && defined(__FreeBSD__)
+#define _Bool bool
+#endif
 #include <stdatomic.h>
 
 #define memory_order_ordered    memory_order_seq_cst
diff --git a/src/shims/linux_stubs.c b/src/shims/generic_unix_stubs.c
similarity index 92%
rename from src/shims/linux_stubs.c
rename to src/shims/generic_unix_stubs.c
index 4923eb0..e1eb93e 100644
--- a/src/shims/linux_stubs.c
+++ b/src/shims/generic_unix_stubs.c
@@ -17,11 +17,11 @@
  */
 
 #include <stdint.h>
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__FreeBSD__)
 #include <sys/syscall.h>
 #else
 #include <syscall.h>
-#endif /* __ANDROID__ */
+#endif /* __ANDROID__ || __FreeBSD__ */
 
 #if __has_include(<config/config_ac.h>)
 #include <config/config_ac.h>
@@ -30,7 +30,7 @@
 #endif
 
 #include "pthread.h"
-#include "os/linux_base.h"
+#include "os/generic_unix_base.h"
 #include "internal.h"
 
 
diff --git a/src/shims/linux_stubs.h b/src/shims/generic_unix_stubs.h
similarity index 100%
rename from src/shims/linux_stubs.h
rename to src/shims/generic_unix_stubs.h
diff --git a/src/transform.c b/src/transform.c
index 91fed5b..44a1271 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -26,6 +26,13 @@
 #include <endian.h>
 #define OSLittleEndian __LITTLE_ENDIAN
 #define OSBigEndian __BIG_ENDIAN
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#define OSLittleEndian _LITTLE_ENDIAN
+#define OSBigEndian _BIG_ENDIAN
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__)
 #define OSSwapLittleToHostInt16 le16toh
 #define OSSwapBigToHostInt16 be16toh
 #define OSSwapHostToLittleInt16 htole16
diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c
index eab84b3..7aad1c0 100644
--- a/tests/bsdtestharness.c
+++ b/tests/bsdtestharness.c
@@ -31,7 +31,7 @@
 #endif
 #include <sys/resource.h>
 #include <sys/time.h>
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 #include <sys/wait.h>
 #endif
 
diff --git a/tests/bsdtests.c b/tests/bsdtests.c
index 09ab000..2c07a5d 100644
--- a/tests/bsdtests.c
+++ b/tests/bsdtests.c
@@ -18,7 +18,7 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 // for asprintf
 #define _GNU_SOURCE 1
 #endif
@@ -452,7 +452,7 @@
 	usleep(100000);	// give 'gdb --waitfor=' a chance to find this proc
 }
 
-#if __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 static char** get_environment(void)
 {
 	extern char **environ; 
diff --git a/tests/bsdtests.h b/tests/bsdtests.h
index 8bf733f..f296194 100644
--- a/tests/bsdtests.h
+++ b/tests/bsdtests.h
@@ -41,6 +41,7 @@
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+#include <unistd.h>
 #include <string.h>
 #include <stdint.h>
 
@@ -152,7 +153,7 @@
 #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__
+#if defined(__APPLE__)
 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);
diff --git a/tests/dispatch_io_net.c b/tests/dispatch_io_net.c
index 4d02751..fd680ae 100644
--- a/tests/dispatch_io_net.c
+++ b/tests/dispatch_io_net.c
@@ -47,7 +47,7 @@
 #endif
 #endif
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 #define _NSGetExecutablePath(ef,bs) (*(bs)=(size_t)snprintf(ef,*(bs),"%s",argv[0]),0)
 #endif
 
diff --git a/tests/dispatch_test.c b/tests/dispatch_test.c
index a8f40d2..ea58194 100644
--- a/tests/dispatch_test.c
+++ b/tests/dispatch_test.c
@@ -56,7 +56,7 @@
 	int kq = kqueue();
 	assert(kq != -1);
 	struct kevent ke = {
-		.ident = fd,
+		.ident = (uintptr_t)fd,
 		.filter = EVFILT_READ,
 		.flags = EV_ADD|EV_ENABLE,
 	};
diff --git a/tests/dispatch_test.h b/tests/dispatch_test.h
index 392b7f9..fdcffd2 100644
--- a/tests/dispatch_test.h
+++ b/tests/dispatch_test.h
@@ -22,8 +22,8 @@
 #include <stdbool.h>
 #include <dispatch/dispatch.h>
 
-#ifdef __linux__
-#include <linux_port.h>
+#if defined(__linux__) || defined(__FreeBSD__)
+#include <generic_unix_port.h>
 #endif
 
 #define test_group_wait(g) do { \
@@ -42,7 +42,7 @@
 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__
+#if __APPLE__
 int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
 		size_t *newpl);
 #endif
diff --git a/tests/linux_port.h b/tests/generic_unix_port.h
similarity index 100%
rename from tests/linux_port.h
rename to tests/generic_unix_port.h