     public var currentValue: Value? {
         /// Get the current value for the calling thread.
         get {
-            guard let raw = pthread_getspecific(self.key) else {
-                return nil
-            }
-            return (Unmanaged<BoxedType>.fromOpaque(raw).takeUnretainedValue().value.1 as! Value)
+          guard let raw = Key.get(for: self.key) else { return nil }
+          // parenthesize the return value to silence the cast warning
+          return (Unmanaged<BoxedType>
+                   .fromOpaque(raw)
+                   .takeUnretainedValue()
+                   .value.1 as! Value)
         }
 
         /// Set the current value for the calling threads. The `currentValue` for all other threads remains unchanged.
         set {
-            if let raw = pthread_getspecific(self.key) {
+            if let raw = Key.get(for: self.key) {
                 Unmanaged<BoxedType>.fromOpaque(raw).release()
             }
-            let pthreadErr = pthread_setspecific(self.key, newValue.map { v -> UnsafeMutableRawPointer in
-                return Unmanaged.passRetained(Box((self, v))).toOpaque()
-            })
-            precondition(pthreadErr == 0, "pthread_setspecific failed, error \(pthreadErr)")
+            Key.set(value: newValue.map { Unmanaged.passRetained(Box((self, $0))).toOpaque() },
+                    for: self.key)
         }
     }
 }
 
 extension NIOThread: Equatable {
     static func ==(lhs: NIOThread, rhs: NIOThread) -> Bool {
-        return pthread_equal(lhs.pthread, rhs.pthread) != 0
-    }
-}
+#if os(Windows)
+        return CompareObjectHandles(lhs.handle, rhs.handle)
+#else
+        return pthread_equal(lhs.handle, rhs.handle) != 0
+#endif
+    }
+}

//===----------------------------------------------------------------------===//

import CNIOLinux

private typealias ThreadBoxValue = (body: (NIOThread) -> Void, name: String?)
private typealias ThreadBox = Box<ThreadBoxValue>


#if os(Linux)
private let sys_pthread_getname_np = CNIOLinux_pthread_getname_np
private let sys_pthread_setname_np = CNIOLinux_pthread_setname_np
#else
private let sys_pthread_getname_np = pthread_getname_np
// Emulate the same method signature as pthread_setname_np on Linux.
private func sys_pthread_setname_np(_ p: pthread_t, _ pointer: UnsafePointer<Int8>) -> Int32 {

    /// - parameters:
    ///     - body: The closure that will accept the `pthread_t`.
    /// - returns: The value returned by `body`.
#if !os(Windows)
    internal func withUnsafePthread<T>(_ body: (pthread_t) throws -> T) rethrows -> T {
        return try body(self.handle)
    }
#endif

    /// Get current name of the `NIOThread` or `nil` if not set.
    var currentName: String? {
#if os(Windows)
        var pszBuffer: PWSTR?
        GetThreadDescription(self.handle, &pszBuffer)
        guard let buffer = pszBuffer else { return nil }
        let string: String = String(decodingCString: buffer, as: UTF16.self)
        LocalFree(buffer)
        return string
#else
        // 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.handle, ptr.baseAddress!, ptr.count) == 0 else {
                return nil
            }

            let buffer: UnsafeRawBufferPointer =
                UnsafeRawBufferPointer(UnsafeBufferPointer<CChar>(rebasing: ptr.prefix { $0 != 0 }))
            return String(decoding: buffer, as: Unicode.UTF8.self)
        }
#endif
    }

    func join() {
#if os(Windows)
        let dwResult: DWORD = WaitForSingleObject(self.handle, INFINITE)
        assert(dwResult == WAIT_OBJECT_0, "WaitForSingleObject: \(GetLastError())")
#else
        let err = pthread_join(self.handle, nil)
        assert(err == 0, "pthread_join failed with \(err)")
#endif
    }

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