diff --git a/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift b/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift index 6e20a9a98c..7ac08c8ffc 100644 --- a/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift +++ b/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift @@ -70,7 +70,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { private let index = ManagedAtomic(0) private var eventLoops: [SelectableEventLoop] private let shutdownLock: NIOLock = NIOLock() - private let threadNamePrefix: String + private let threadNamePrefix: String? private var runState: RunState = .running private let canBeShutDown: Bool @@ -108,7 +108,8 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { } private static func setupThreadAndEventLoop( - name: String, + name: String?, + threadConfiguration: NIOThreadConfiguration, parentGroup: MultiThreadedEventLoopGroup, selectorFactory: @escaping () throws -> NIOPosix.Selector, initializer: @escaping ThreadInitializer, @@ -119,7 +120,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { // synchronised by `lock` var _loop: SelectableEventLoop! = nil - NIOThread.spawnAndRun(name: name, detachThread: false) { t in + NIOThread.spawnAndRun(name: name, configuration: threadConfiguration, detachThread: false) { t in MultiThreadedEventLoopGroup.runTheLoop( thread: t, parentGroup: parentGroup, @@ -150,6 +151,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { public convenience init(numberOfThreads: Int) { self.init( numberOfThreads: numberOfThreads, + threadConfiguration: .defaultForEventLoopGroups, canBeShutDown: true, metricsDelegate: nil, selectorFactory: NIOPosix.Selector.init @@ -169,6 +171,32 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { public convenience init(numberOfThreads: Int, metricsDelegate: NIOEventLoopMetricsDelegate) { self.init( numberOfThreads: numberOfThreads, + threadConfiguration: .defaultForEventLoopGroups, + canBeShutDown: true, + metricsDelegate: metricsDelegate, + selectorFactory: NIOPosix.Selector.init + ) + } + + /// Creates a `MultiThreadedEventLoopGroup` instance which uses `numberOfThreads`. + /// + /// - note: Don't forget to call `shutdownGracefully` or `syncShutdownGracefully` when you no longer need this + /// `EventLoopGroup`. If you forget to shut the `EventLoopGroup` down you will leak `numberOfThreads` + /// (kernel) threads which are costly resources. This is especially important in unit tests where one + /// `MultiThreadedEventLoopGroup` is started per test case. + /// + /// - Parameters: + /// - numberOfThreads: The number of `Threads` to use. + /// - threadConfiguration: Configuration for the threads to spawn. + /// - metricsDelegate: Delegate for collecting information from this eventloop + public convenience init( + numberOfThreads: Int, + threadConfiguration: NIOThreadConfiguration, + metricsDelegate: NIOEventLoopMetricsDelegate? = nil + ) { + self.init( + numberOfThreads: numberOfThreads, + threadConfiguration: threadConfiguration, canBeShutDown: true, metricsDelegate: metricsDelegate, selectorFactory: NIOPosix.Selector.init @@ -179,13 +207,13 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { /// /// This is only useful for global singletons. public static func _makePerpetualGroup( - threadNamePrefix: String, - numberOfThreads: Int + numberOfThreads: Int, + threadConfiguration: NIOThreadConfiguration ) -> MultiThreadedEventLoopGroup { self.init( numberOfThreads: numberOfThreads, + threadConfiguration: threadConfiguration, canBeShutDown: false, - threadNamePrefix: threadNamePrefix, metricsDelegate: nil, selectorFactory: NIOPosix.Selector.init ) @@ -193,6 +221,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { internal convenience init( numberOfThreads: Int, + threadConfiguration: NIOThreadConfiguration, metricsDelegate: NIOEventLoopMetricsDelegate?, selectorFactory: @escaping () throws -> NIOPosix.Selector ) { @@ -201,6 +230,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { self.init( threadInitializers: initializers, canBeShutDown: true, + threadConfiguration: threadConfiguration, metricsDelegate: metricsDelegate, selectorFactory: selectorFactory ) @@ -208,24 +238,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { internal convenience init( numberOfThreads: Int, - canBeShutDown: Bool, - threadNamePrefix: String, - metricsDelegate: NIOEventLoopMetricsDelegate?, - selectorFactory: @escaping () throws -> NIOPosix.Selector - ) { - precondition(numberOfThreads > 0, "numberOfThreads must be positive") - let initializers: [ThreadInitializer] = Array(repeating: { _ in }, count: numberOfThreads) - self.init( - threadInitializers: initializers, - canBeShutDown: canBeShutDown, - threadNamePrefix: threadNamePrefix, - metricsDelegate: metricsDelegate, - selectorFactory: selectorFactory - ) - } - - internal convenience init( - numberOfThreads: Int, + threadConfiguration: NIOThreadConfiguration, canBeShutDown: Bool, metricsDelegate: NIOEventLoopMetricsDelegate?, selectorFactory: @escaping () throws -> NIOPosix.Selector @@ -235,6 +248,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { self.init( threadInitializers: initializers, canBeShutDown: canBeShutDown, + threadConfiguration: threadConfiguration, metricsDelegate: metricsDelegate, selectorFactory: selectorFactory ) @@ -242,6 +256,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { internal convenience init( threadInitializers: [ThreadInitializer], + threadConfiguration: NIOThreadConfiguration, metricsDelegate: NIOEventLoopMetricsDelegate?, selectorFactory: @escaping () throws -> NIOPosix.Selector = NIOPosix.Selector .init @@ -249,6 +264,7 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { self.init( threadInitializers: threadInitializers, canBeShutDown: true, + threadConfiguration: threadConfiguration, metricsDelegate: metricsDelegate, selectorFactory: selectorFactory ) @@ -261,12 +277,12 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { internal init( threadInitializers: [ThreadInitializer], canBeShutDown: Bool, - threadNamePrefix: String = "NIO-ELT-", + threadConfiguration: NIOThreadConfiguration, metricsDelegate: NIOEventLoopMetricsDelegate?, selectorFactory: @escaping () throws -> NIOPosix.Selector = NIOPosix.Selector .init ) { - self.threadNamePrefix = threadNamePrefix + self.threadNamePrefix = threadConfiguration.threadNamePrefix let myGroupID = nextEventLoopGroupID.loadThenWrappingIncrement(ordering: .relaxed) self.myGroupID = myGroupID var idx = 0 @@ -275,7 +291,8 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup { self.eventLoops = threadInitializers.map { initializer in // Maximum name length on linux is 16 by default. let ev = MultiThreadedEventLoopGroup.setupThreadAndEventLoop( - name: "\(threadNamePrefix)\(myGroupID)-#\(idx)", + name: self.threadNamePrefix.map { "\($0)\(myGroupID)-#\(idx)" }, + threadConfiguration: threadConfiguration, parentGroup: self, selectorFactory: selectorFactory, initializer: initializer, diff --git a/Sources/NIOPosix/NIOThreadPool.swift b/Sources/NIOPosix/NIOThreadPool.swift index c5817601f6..ac1b8a8263 100644 --- a/Sources/NIOPosix/NIOThreadPool.swift +++ b/Sources/NIOPosix/NIOThreadPool.swift @@ -79,6 +79,7 @@ public final class NIOThreadPool { /// It should never be "leaked" outside of the lock block. case modifying } + private let threadConfiguration: NIOThreadConfiguration private let semaphore = DispatchSemaphore(value: 0) private let lock = NIOLock() private var threads: [NIOThread]? = nil // protected by `lock` @@ -194,21 +195,61 @@ public final class NIOThreadPool { /// - parameters: /// - numberOfThreads: The number of threads to use for the thread pool. public convenience init(numberOfThreads: Int) { - self.init(numberOfThreads: numberOfThreads, canBeStopped: true) + self.init( + numberOfThreads: numberOfThreads, + threadConfiguration: .defaultForOffloadThreadPool, + canBeStopped: true + ) + } + + /// Initialize a `NIOThreadPool` thread pool with `numberOfThreads` threads. + /// + /// - parameters: + /// - numberOfThreads: The number of threads to use for the thread pool. + public convenience init(numberOfThreads: Int, threadConfiguration: NIOThreadConfiguration) { + self.init( + numberOfThreads: numberOfThreads, + threadConfiguration: .defaultForOffloadThreadPool, + canBeStopped: true + ) } /// Create a ``NIOThreadPool`` that is already started, cannot be shut down and must not be `deinit`ed. /// /// This is only useful for global singletons. + @available( + *, + deprecated, + renamed: "_makePerpetualStartedPool(numberOfThreads:threadConfiguration:threadNamePrefix:)" + ) public static func _makePerpetualStartedPool(numberOfThreads: Int, threadNamePrefix: String) -> NIOThreadPool { - let pool = self.init(numberOfThreads: numberOfThreads, canBeStopped: false) - pool._start(threadNamePrefix: threadNamePrefix) + var threadConfig = NIOThreadConfiguration.defaultForOffloadThreadPool + threadConfig.threadNamePrefix = threadNamePrefix + let pool = self.init(numberOfThreads: numberOfThreads, threadConfiguration: threadConfig, canBeStopped: false) + pool.start() return pool } - private init(numberOfThreads: Int, canBeStopped: Bool) { + /// Create a ``NIOThreadPool`` that is already started, cannot be shut down and must not be `deinit`ed. + /// + /// This is only useful for global singletons. + public static func _makePerpetualStartedPool( + numberOfThreads: Int, + threadConfiguration: NIOThreadConfiguration + ) -> NIOThreadPool { + let pool = self.init( + numberOfThreads: numberOfThreads, + threadConfiguration: threadConfiguration, + canBeStopped: false + ) + pool.start() + return pool + } + + private init(numberOfThreads: Int, threadConfiguration: NIOThreadConfiguration, canBeStopped: Bool) { self.numberOfThreads = numberOfThreads self.canBeStopped = canBeStopped + self.threadConfiguration = threadConfiguration } private func process(identifier: Int) { @@ -252,10 +293,6 @@ public final class NIOThreadPool { /// Start the `NIOThreadPool` if not already started. public func start() { - self._start(threadNamePrefix: "TP-#") - } - - public func _start(threadNamePrefix: String) { let alreadyRunning: Bool = self.lock.withLock { switch self.state { case .running(_): @@ -286,9 +323,14 @@ public final class NIOThreadPool { self.threads?.reserveCapacity(self.numberOfThreads) } + let threadNamePrefix = self.threadConfiguration.threadNamePrefix for id in 0.. Void, name: String?) + internal typealias ThreadBoxValue = ( + body: (NIOThread) -> Void, name: String?, configuration: NIOThreadConfiguration + ) internal typealias ThreadBox = Box private let desiredName: String? @@ -78,6 +80,14 @@ final class NIOThread { ThreadOpsSystem.joinThread(self.handle) } + static func spawnAndRunBasic( + body: @escaping (NIOThread) -> Void + ) { + var threadConfig = NIOThreadConfiguration.defaultForEventLoopGroups + threadConfig.threadNamePrefix = "UnitTest-" + self.spawnAndRun(name: nil, configuration: threadConfig, detachThread: true, body: body) + } + /// Spawns and runs some task in a `NIOThread`. /// /// - arguments: @@ -85,7 +95,8 @@ final class NIOThread { /// - 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, + name: String?, + configuration: NIOThreadConfiguration, detachThread: Bool = true, body: @escaping (NIOThread) -> Void ) { @@ -93,7 +104,7 @@ final class NIOThread { // 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 tuple: ThreadBoxValue = (body: body, name: name, configuration: configuration) let box = ThreadBox(tuple) ThreadOpsSystem.run(handle: &handle, args: box, detachThread: detachThread) diff --git a/Sources/NIOPosix/ThreadConfiguration.swift b/Sources/NIOPosix/ThreadConfiguration.swift new file mode 100644 index 0000000000..ec1c33f6d4 --- /dev/null +++ b/Sources/NIOPosix/ThreadConfiguration.swift @@ -0,0 +1,142 @@ +#if canImport(Darwin) +import Dispatch +#endif + +public struct NIOThreadConfiguration: Sendable { + public var threadNamePrefix: Optional + + #if canImport(Darwin) + public var osSpecificConfiguration: DarwinThreadConfiguration + #elseif os(Linux) + public var osSpecificConfiguration: LinuxThreadConfiguration + #elseif os(Windows) + public var osSpecificConfiguration: WindowsThreadConfiguration + #elseif os(Android) + public var osSpecificConfiguration: AndroidThreadConfiguration + #elseif os(WASI) + public var osSpecificConfiguration: WASIThreadConfiguration + #elseif os(FreeBSD) + public var osSpecificConfiguration: FreeBSDThreadConfiguration + #endif + + internal static var defaultForEventLoopGroups: Self { + NIOThreadConfiguration( + threadNamePrefix: "NIO-ELT-", + osSpecificConfiguration: .default + ) + } + + internal static var defaultForOffloadThreadPool: Self { + NIOThreadConfiguration( + threadNamePrefix: "TP-", + osSpecificConfiguration: .default + ) + } + + public static var `default`: Self { + NIOThreadConfiguration( + threadNamePrefix: nil, + osSpecificConfiguration: .default + ) + } +} + +#if os(Linux) +extension NIOThreadConfiguration { + public struct LinuxThreadConfiguration: Sendable { + public static var `default`: Self { + .init() + } + } +} +#endif + +#if os(Android) +extension NIOThreadConfiguration { + public struct AndroidThreadConfiguration: Sendable { + public static var `default`: Self { + .init() + } + } +} +#endif + +#if os(Windows) +extension NIOThreadConfiguration { + public struct WindowsThreadConfiguration: Sendable { + public static var `default`: Self { + .init() + } + } +} +#endif + +#if os(WASI) +extension NIOThreadConfiguration { + public struct WASIThreadConfiguration: Sendable { + public static var `default`: Self { + .init() + } + } +} +#endif + +#if os(FreeBSD) +extension NIOThreadConfiguration { + public struct FreeBSDThreadConfiguration: Sendable { + public static var `default`: Self { + .init() + } + } +} +#endif + +#if canImport(Darwin) +extension NIOThreadConfiguration { + public struct DarwinThreadConfiguration: Sendable { + public var qosClass: DarwinQoSClass + + public struct DarwinQoSClass: Sendable { + var backing: Backing + + internal enum Backing: Sendable { + case inheritFromMainThread + + case custom(qos_class_t) + } + + public static var inheritFromMainThread: Self { + .init(backing: .inheritFromMainThread) + } + + public static var userInteractive: Self { + .init(backing: .custom(QOS_CLASS_USER_INTERACTIVE)) + } + + public static var userInitiated: Self { + .init(backing: .custom(QOS_CLASS_USER_INITIATED)) + } + + public static var background: Self { + .init(backing: .custom(QOS_CLASS_BACKGROUND)) + } + + public static var utility: Self { + .init(backing: .custom(QOS_CLASS_UTILITY)) + } + + public static var unspecified: Self { + .init(backing: .custom(QOS_CLASS_UNSPECIFIED)) + } + + public static var `default`: Self { + .init(backing: .custom(QOS_CLASS_DEFAULT)) + } + } + + public static var `default`: Self { + .init(qosClass: .inheritFromMainThread) + } + } +} +#endif diff --git a/Sources/NIOPosix/ThreadPosix.swift b/Sources/NIOPosix/ThreadPosix.swift index f876c42c8a..e0894732c9 100644 --- a/Sources/NIOPosix/ThreadPosix.swift +++ b/Sources/NIOPosix/ThreadPosix.swift @@ -39,22 +39,18 @@ private typealias ThreadDestructor = @convention(c) (UnsafeMutableRawPointer) -> private func sysPthread_create( handle: UnsafeMutablePointer, + attr: UnsafePointer?, destructor: @escaping ThreadDestructor, args: UnsafeMutableRawPointer? ) -> CInt { #if canImport(Darwin) - var attr: pthread_attr_t = .init() - pthread_attr_init(&attr) - pthread_attr_set_qos_class_np(&attr, qos_class_main(), 0) - let thread = pthread_create(handle, &attr, destructor, args) - pthread_attr_destroy(&attr) - return thread + return pthread_create(handle, attr, destructor, args) #else #if canImport(Musl) var handleLinux: OpaquePointer? = nil let result = pthread_create( &handleLinux, - nil, + attr, destructor, args ) @@ -62,7 +58,7 @@ private func sysPthread_create( var handleLinux = pthread_t() let result = pthread_create( &handleLinux, - nil, + attr, destructor, args ) @@ -104,9 +100,25 @@ enum ThreadOpsPosix: ThreadOps { args: Box, detachThread: Bool ) { + var attr: pthread_attr_t = pthread_attr_t() + pthread_attr_init(&attr) + defer { + pthread_attr_destroy(&attr) + } + #if canImport(Darwin) + let qosClass: qos_class_t + switch args.value.configuration.osSpecificConfiguration.qosClass.backing { + case .inheritFromMainThread: + qosClass = qos_class_main() + case .custom(let `class`): + qosClass = `class` + } + pthread_attr_set_qos_class_np(&attr, qosClass, 0) + #endif let argv0 = Unmanaged.passRetained(args).toOpaque() let res = sysPthread_create( handle: &handle, + attr: &attr, destructor: { // Cast to UnsafeMutableRawPointer? and force unwrap to make the // same code work on macOS and Linux. diff --git a/Tests/NIOPosixTests/EventLoopTest.swift b/Tests/NIOPosixTests/EventLoopTest.swift index 4b0abd9530..5606bde148 100644 --- a/Tests/NIOPosixTests/EventLoopTest.swift +++ b/Tests/NIOPosixTests/EventLoopTest.swift @@ -634,7 +634,11 @@ public final class EventLoopTest: XCTestCase { } let threads: [ThreadInitializer] = [body, body] - let group = MultiThreadedEventLoopGroup(threadInitializers: threads, metricsDelegate: nil) + let group = MultiThreadedEventLoopGroup( + threadInitializers: threads, + threadConfiguration: .defaultForEventLoopGroups, + metricsDelegate: nil + ) XCTAssertEqual(2, counter) XCTAssertNoThrow(try group.syncShutdownGracefully()) @@ -1945,6 +1949,37 @@ public final class EventLoopTest: XCTestCase { scheduledTask.cancel() } + + func testThreadPrefixes() throws { + var threadConfig = NIOThreadConfiguration.defaultForEventLoopGroups + threadConfig.threadNamePrefix = "test-" + let group = MultiThreadedEventLoopGroup(numberOfThreads: 3, threadConfiguration: threadConfig) + defer { + XCTAssertNoThrow(try group.syncShutdownGracefully()) + } + + for loop in group.makeIterator() { + let threadName = try loop.submit { return Thread.current.name ?? "NO NAME" }.wait() + XCTAssert(threadName.hasPrefix("test-")) + } + } + + func testThreadQoS() throws { + #if canImport(Darwin) + var threadConfig = NIOThreadConfiguration.defaultForEventLoopGroups + threadConfig.threadNamePrefix = "test-" + threadConfig.osSpecificConfiguration.qosClass = .utility + let group = MultiThreadedEventLoopGroup(numberOfThreads: 3, threadConfiguration: threadConfig) + defer { + XCTAssertNoThrow(try group.syncShutdownGracefully()) + } + + for loop in group.makeIterator() { + let qosClass = try loop.submit { qos_class_self() }.wait() + XCTAssertEqual(QOS_CLASS_UTILITY, qosClass) + } + #endif + } } private class EventLoopWithPreSucceededFuture: EventLoop { diff --git a/Tests/NIOPosixTests/SyscallAbstractionLayer.swift b/Tests/NIOPosixTests/SyscallAbstractionLayer.swift index ab5b075110..0f46c4607f 100644 --- a/Tests/NIOPosixTests/SyscallAbstractionLayer.swift +++ b/Tests/NIOPosixTests/SyscallAbstractionLayer.swift @@ -640,7 +640,11 @@ extension SALTest { } } self.wakeups = .init(description: "wakeups") - self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1, metricsDelegate: nil) { + self.group = MultiThreadedEventLoopGroup( + numberOfThreads: 1, + threadConfiguration: .defaultForOffloadThreadPool, + metricsDelegate: nil + ) { try HookedSelector( userToKernel: self.userToKernelBox, kernelToUser: self.kernelToUserBox, diff --git a/Tests/NIOPosixTests/ThreadTest.swift b/Tests/NIOPosixTests/ThreadTest.swift index 8320f068dd..837a5a7cbe 100644 --- a/Tests/NIOPosixTests/ThreadTest.swift +++ b/Tests/NIOPosixTests/ThreadTest.swift @@ -21,7 +21,7 @@ import XCTest class ThreadTest: XCTestCase { func testCurrentThreadWorks() throws { let s = DispatchSemaphore(value: 0) - NIOThread.spawnAndRun { t in + NIOThread.spawnAndRunBasic { t in XCTAssertTrue(t.isCurrent) s.signal() } @@ -30,8 +30,8 @@ class ThreadTest: XCTestCase { func testCurrentThreadIsNotTrueOnOtherThread() throws { let s = DispatchSemaphore(value: 0) - NIOThread.spawnAndRun { t1 in - NIOThread.spawnAndRun { t2 in + NIOThread.spawnAndRunBasic { t1 in + NIOThread.spawnAndRunBasic { t2 in XCTAssertFalse(t1.isCurrent) XCTAssertTrue(t2.isCurrent) s.signal() @@ -43,7 +43,7 @@ class ThreadTest: XCTestCase { func testThreadSpecificsAreNilWhenNotPresent() throws { class SomeClass {} let s = DispatchSemaphore(value: 0) - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let tsv: ThreadSpecificVariable = ThreadSpecificVariable() XCTAssertNil(tsv.currentValue) s.signal() @@ -54,7 +54,7 @@ class ThreadTest: XCTestCase { func testThreadSpecificsWorks() throws { class SomeClass {} let s = DispatchSemaphore(value: 0) - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let tsv: ThreadSpecificVariable = ThreadSpecificVariable() XCTAssertNil(tsv.currentValue) let expected = SomeClass() @@ -68,12 +68,12 @@ class ThreadTest: XCTestCase { func testThreadSpecificsAreNotAvailableOnADifferentThread() throws { class SomeClass {} let s = DispatchSemaphore(value: 0) - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let tsv = ThreadSpecificVariable() XCTAssertNil(tsv.currentValue) tsv.currentValue = SomeClass() XCTAssertNotNil(tsv.currentValue) - NIOThread.spawnAndRun { t2 in + NIOThread.spawnAndRunBasic { t2 in XCTAssertNil(tsv.currentValue) s.signal() } @@ -91,7 +91,7 @@ class ThreadTest: XCTestCase { } } weak var weakSome: SomeClass? = nil - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let some = SomeClass(sem: s) weakSome = some let tsv = ThreadSpecificVariable() @@ -112,7 +112,7 @@ class ThreadTest: XCTestCase { } } weak var weakSome: SomeClass? = nil - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let some = SomeClass(sem: s) weakSome = some let tsv = ThreadSpecificVariable() @@ -138,7 +138,7 @@ class ThreadTest: XCTestCase { weak var weakSome1: SomeClass? = nil weak var weakSome2: SomeClass? = nil weak var weakSome3: SomeClass? = nil - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let some1 = SomeClass(sem: s1) weakSome1 = some1 let some2 = SomeClass(sem: s2) @@ -172,12 +172,12 @@ class ThreadTest: XCTestCase { } } weak var weakSome: SomeClass? = nil - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in let some = SomeClass(sem: s) weakSome = some let tsv = ThreadSpecificVariable() for _ in 0..<10 { - NIOThread.spawnAndRun { (_: NIOPosix.NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOPosix.NIOThread) in tsv.currentValue = some } } @@ -203,7 +203,7 @@ class ThreadTest: XCTestCase { } weak var weakSome: SomeClass? = nil weak var weakTSV: ThreadSpecificVariable? = nil - NIOThread.spawnAndRun { (_: NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOThread) in { let some = SomeClass(sem: s) weakSome = some @@ -231,7 +231,7 @@ class ThreadTest: XCTestCase { } for _ in 0..() tsv.currentValue = some @@ -273,7 +273,7 @@ class ThreadTest: XCTestCase { weak var weakSome1: SomeClass? = nil weak var weakSome2: SomeClass? = nil weak var weakTSV: ThreadSpecificVariable? = nil - NIOThread.spawnAndRun { (_: NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOThread) in { let some = SomeClass(sem: t1Sem) weakSome1 = some @@ -287,7 +287,7 @@ class ThreadTest: XCTestCase { XCTAssertNotNil(weakTSV) }() } - NIOThread.spawnAndRun { (_: NIOThread) in + NIOThread.spawnAndRunBasic { (_: NIOThread) in { let some = SomeClass(sem: t2Sem) weakSome2 = some