swift-nio/Sources/NIOPosix/ThreadWindows.swift

98 lines
3.4 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if os(Windows)
import WinSDK
typealias ThreadOpsSystem = ThreadOpsWindows
enum ThreadOpsWindows: ThreadOps {
typealias ThreadHandle = HANDLE
typealias ThreadSpecificKey = DWORD
typealias ThreadSpecificKeyDestructor = @convention(c) (UnsafeMutableRawPointer?) -> Void
static func threadName(_ thread: ThreadOpsSystem.ThreadHandle) -> String? {
var pszBuffer: PWSTR?
GetThreadDescription(thread, &pszBuffer)
guard let buffer = pszBuffer else { return nil }
let string: String = String(decodingCString: buffer, as: UTF16.self)
LocalFree(buffer)
return string
}
static func run(handle: inout ThreadOpsSystem.ThreadHandle?, args: Box<NIOThread.ThreadBoxValue>, detachThread: Bool) {
let argv0 = Unmanaged.passRetained(args).toOpaque()
// FIXME(compnerd) this should use the `stdcall` calling convention
let routine: @convention(c) (UnsafeMutableRawPointer?) -> CUnsignedInt = {
let boxed = Unmanaged<NIOThread.ThreadBox>.fromOpaque($0!).takeRetainedValue()
let (body, name) = (boxed.value.body, boxed.value.name)
let hThread: ThreadOpsSystem.ThreadHandle = 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)
}
}
static func isCurrentThread(_ thread: ThreadOpsSystem.ThreadHandle) -> Bool {
return CompareObjectHandles(thread, GetCurrentThread())
}
static var currentThread: ThreadOpsSystem.ThreadHandle {
return GetCurrentThread()
}
static func joinThread(_ thread: ThreadOpsSystem.ThreadHandle) {
let dwResult: DWORD = WaitForSingleObject(thread, INFINITE)
assert(dwResult == WAIT_OBJECT_0, "WaitForSingleObject: \(GetLastError())")
}
static func allocateThreadSpecificValue(destructor: @escaping ThreadSpecificKeyDestructor) -> ThreadSpecificKey {
return FlsAlloc(destructor)
}
static func deallocateThreadSpecificValue(_ key: ThreadSpecificKey) {
let dwResult: Bool = FlsFree(key)
precondition(dwResult, "FlsFree: \(GetLastError())")
}
static func getThreadSpecificValue(_ key: ThreadSpecificKey) -> UnsafeMutableRawPointer? {
return FlsGetValue(key)
}
static func setThreadSpecificValue(key: ThreadSpecificKey, value: UnsafeMutableRawPointer?) {
FlsSetValue(key, value)
}
static func compareThreads(_ lhs: ThreadOpsSystem.ThreadHandle, _ rhs: ThreadOpsSystem.ThreadHandle) -> Bool {
return CompareObjectHandles(lhs, rhs)
}
}
#endif