Repository: apple/swift-nio
File: Sources/NIOPosix/NIOThreadPool.swift (Swift)

Code before:
                return
            }
            do {
                try promise.succeed(body())
            } catch {
                promise.fail(error)
            }
        }
        return promise.futureResult
    }
}

@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOThreadPool {
    /// Runs the submitted closure if the thread pool is still active, otherwise throw an error.
    /// The closure will be run on the thread pool so can do blocking work.
    ///
    /// - parameters:
    ///     - body: The closure which performs some blocking work to be done on the thread pool.
    /// - returns: result of the passed closure.
    @preconcurrency
    public func runIfActive<T>(_ body: @escaping @Sendable () throws -> T) async throws -> T {
        try await self._runIfActive(body)
    }
    
    private func _runIfActive<T>(_ body: @escaping () throws -> T) async throws -> T {
        try await withCheckedThrowingContinuation { (cont: CheckedContinuation<T, Error>) in
            self.submit { shouldRun in
                guard case shouldRun = NIOThreadPool.WorkItemState.active else {
                    cont.resume(throwing: NIOThreadPoolError.ThreadPoolInactive())
                    return
                }
                do {
                    try cont.resume(returning: body())
                } catch {
                    cont.resume(throwing: error)
                }
            }
        }
    }
}

extension NIOThreadPool {
    @preconcurrency
    public func shutdownGracefully(_ callback: @escaping @Sendable (Error?) -> Void) {
        self.shutdownGracefully(queue: .global(), callback)
    }

    /// Shuts down the thread pool gracefully.
    @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
    @inlinable

Review comment (suggestion):
I don't think we need this inner function now, and so we can avoid dropping the `@Sendable` annotation here.

Code after:
                return
            }
            do {
                try promise.succeed(body())
            } catch {
                promise.fail(error)
            }
        }
        return promise.futureResult
    }

    /// Runs the submitted closure if the thread pool is still active, otherwise throw an error.
    /// The closure will be run on the thread pool so can do blocking work.
    ///
    /// - parameters:
    ///     - body: The closure which performs some blocking work to be done on the thread pool.
    /// - returns: result of the passed closure.
    @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
    public func runIfActive<T: Sendable>(_ body: @escaping @Sendable () throws -> T) async throws -> T {
        try await withCheckedThrowingContinuation { (cont: CheckedContinuation<T, Error>) in
            self.submit { shouldRun in
                guard case shouldRun = NIOThreadPool.WorkItemState.active else {
                    cont.resume(throwing: NIOThreadPoolError.ThreadPoolInactive())
                    return
                }
                do {
                    try cont.resume(returning: body())
                } catch {
                    cont.resume(throwing: error)
                }
            }
        }
    }
}

extension NIOThreadPool {
    @preconcurrency
    public func shutdownGracefully(_ callback: @escaping @Sendable (Error?) -> Void) {
        self.shutdownGracefully(queue: .global(), callback)
    }

    /// Shuts down the thread pool gracefully.
    @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
    @inlinable
    public func shutdownGracefully() async throws {
        return try await withCheckedThrowingContinuation { cont in
            self.shutdownGracefully { error in
                if let error = error {
                    cont.resume(throwing: error)
                } else {
                    cont.resume()