 }
 #endif
 
+fileprivate extension NIOThread.NIOThreadHandle {
+  static var invalid: NIOThread.NIOThreadHandle {
+#if os(Windows)
+      return INVALID_HANDLE_VALUE
+#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
+      return nil
+#else
+      return pthread_t()
+#endif
+  }
+}
+
 /// A Thread that executes some runnable block.
 ///
 /// All methods exposed are thread-safe.
 final class NIOThread {
+#if os(Windows)
+    internal typealias NIOThreadHandle = HANDLE
+#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
+    internal typealias NIOThreadHandle = pthread_t?
+#else
+    internal typealias NIOThreadHandle = pthread_t
+#endif
+
+    private typealias ThreadBoxValue = (body: (NIOThread) -> Void, name: String?)
+    private typealias ThreadBox = Box<ThreadBoxValue>
+
     private let desiredName: String?
 
-    /// The pthread_t used by this instance.
-    private let pthread: pthread_t
+    /// The thread handle used by this instance.
+    private let handle: NIOThreadHandle
 
     /// Create a new instance
     ///
     /// - arguments:
-    ///     - pthread: The `pthread_t` that is wrapped and used by the `NIOThread`.
-    private init(pthread: pthread_t, desiredName: String?) {
-        self.pthread = pthread
+    ///     - handle: The `NIOThreadHandle` that is wrapped and used by the `NIOThread`.
+    private init(handle: NIOThreadHandle, desiredName: String?) {
+        self.handle = handle
         self.desiredName = desiredName
     }
 

    /// - parameters:
    ///     - body: The closure that will accept the `pthread_t`.
    /// - returns: The value returned by `body`.
    func withUnsafePthread<T>(_ body: (pthread_t) throws -> T) rethrows -> T {
        return try body(self.pthread)
    }

    /// Get current name of the `NIOThread` or `nil` if not set.
    var currentName: String? {
        get {
            // 64 bytes should be good enough as on Linux the limit is usually 16 and it's very unlikely a user will ever set something longer anyway.
            var chars: [CChar] = Array(repeating: 0, count: 64)
            return chars.withUnsafeMutableBufferPointer { ptr in
                guard sys_pthread_getname_np(self.pthread, ptr.baseAddress!, ptr.count) == 0 else {
                    return nil
                }

                return String(decoding: UnsafeRawBufferPointer(UnsafeBufferPointer<CChar>(rebasing: ptr.prefix { char in
                                  char != 0
                              })),
                              as: Unicode.UTF8.self)
            }
        }
    }

    func join() {
        let err = pthread_join(self.pthread, nil)
        assert(err == 0, "pthread_join failed with \(err)")
    }

    /// Spawns and runs some task in a `NIOThread`.

    ///     - name: The name of the `NIOThread` or `nil` if no specific name should be set.
    ///     - body: The function to execute within the spawned `NIOThread`.
    ///     - detach: Whether to detach the thread. If the thread is not detached it must be `join`ed.
    static func spawnAndRun(name: String? = nil, detachThread: Bool = true,
                            body: @escaping (NIOThread) -> Void) {
        var handle: NIOThreadHandle = .invalid

        // Store everything we want to pass into the c function in a Box so we
        // can hand-over the reference.
        let tuple: ThreadBoxValue = (body: body, name: name)
        let box = ThreadBox(tuple)

        let argv0 = Unmanaged.passRetained(box).toOpaque()

#if os(Windows)
        // FIXME(compnerd) this should use the `stdcall` calling convention
        let routine: @convention(c) (UnsafeMutableRawPointer?) -> CUnsignedInt = {
            let boxed = Unmanaged<ThreadBox>.fromOpaque($0!).takeRetainedValue()
            let (body, name) = (boxed.value.body, boxed.value.name)
            let hThread: NIOThreadHandle = GetCurrentThread()

            if let name = name {
                _ = name.withCString(encodedAs: UTF16.self) {
                    SetThreadDescription(hThread, $0)
                }
            }

            body(NIOThread(handle: hThread, desiredName: name))

            return 0
        }
        let hThread: HANDLE =
            HANDLE(bitPattern: _beginthreadex(nil, 0, routine, argv0, 0, nil))!

        if detachThread {
            CloseHandle(hThread)
        }
#else
        let res = pthread_create(&handle, nil, {
            // Cast to UnsafeMutableRawPointer? and force unwrap to make the
            // same code work on macOS and Linux.
            let boxed = Unmanaged<ThreadBox>
                          .fromOpaque(($0 as UnsafeMutableRawPointer?)!)
                          .takeRetainedValue()
            let (body, name) = (boxed.value.body, boxed.value.name)
            let hThread: NIOThreadHandle = pthread_self()

            if let name = name {
                // this is non-critical so we ignore the result here, we've seen
                // EPERM in containers.
                _ = sys_pthread_setname_np(hThread, name)
            }

            body(NIOThread(handle: hThread, desiredName: name))

            return nil
        }, argv0)
        precondition(res == 0, "Unable to create thread: \(res)")

        if detachThread {
            let detachError = pthread_detach(handle)
            precondition(detachError == 0, "pthread_detach failed with error \(detachError)")
        }
#endif
    }

    /// Returns `true` if the calling thread is the same as this one.
    var isCurrent: Bool {
#if os(Windows)
        return CompareObjectHandles(self.handle, GetCurrentThread())
#else
        return pthread_equal(self.handle, pthread_self()) != 0
#endif
    }

    /// Returns the current running `NIOThread`.
    static var current: NIOThread {
#if os(Windows)
        let hThread: NIOThreadHandle = GetCurrentThread()
#else
        let hThread: NIOThreadHandle = pthread_self()
#endif
        return NIOThread(handle: hThread, desiredName: nil)
    }
}

