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

Code before:
@inlinable
internal func withAutoReleasePool<T>(_ execute: () throws -> T) rethrows -> T {
#if canImport(Darwin)
    return try autoreleasepool {
        try execute()
    }
#else
    return try execute()
#endif
}

/// Information about an EventLoop tick
public struct EventLoopTickInfo {
    /// The number of tasks which were executed in this tick
    public var numberOfTasks: Int
    /// The time at which the tick began
    public var startTime: NIODeadline

    internal init(numberOfTasks: Int, startTime: NIODeadline) {
        self.numberOfTasks = numberOfTasks
        self.startTime = startTime
    }
}

/// Implement this delegate to receive information about the EventLoop, such as each tick
public protocol EventLoopDelegate {
    /// Called after a tick has run
    /// This function is called after every tick - avoid long-running tasks here
    /// - Parameter info: Information about the tick, such as how many tasks were executed
    func processedTick(info: EventLoopTickInfo)
}

/// `EventLoop` implementation that uses a `Selector` to get notified once there is more I/O or tasks to process.
/// The whole processing of I/O and tasks is done by a `NIOThread` that is tied to the `SelectableEventLoop`. This `NIOThread`
/// is guaranteed to never change!
@usableFromInline
internal final class SelectableEventLoop: EventLoop {

    static let strictModeEnabled: Bool = {
        switch getenv("SWIFTNIO_STRICT").map({ String.init(cString: $0).lowercased() }) {
        case "true", "y", "yes", "on", "1":
            return true
        default:
            return false
        }
    }()

    /// The different state in the lifecycle of an `EventLoop` seen from _outside_ the `EventLoop`.
    private enum ExternalState {
        /// `EventLoop` is open and so can process more work.
        case open

Review comment (suggestion):
- needs a `NIO` prefix to satisfy the public API guarantees NIO has
- I'd call this `NIOEventLoopMetricsDelegate` or something

Code after:
/// Execute the given closure and ensure we release all auto pools if needed.
@inlinable
internal func withAutoReleasePool<T>(_ execute: () throws -> T) rethrows -> T {
#if canImport(Darwin)
    return try autoreleasepool {
        try execute()
    }
#else
    return try execute()
#endif
}

/// Information about an EventLoop tick
public struct NIOEventLoopTickInfo: Sendable, Hashable {
    /// The eventloop which ticked
    public var eventLoopID: ObjectIdentifier
    /// The number of tasks which were executed in this tick
    public var numberOfTasks: Int
    /// The time at which the tick began
    public var startTime: NIODeadline

    internal init(eventLoopID: ObjectIdentifier, numberOfTasks: Int, startTime: NIODeadline) {
        self.eventLoopID = eventLoopID
        self.numberOfTasks = numberOfTasks
        self.startTime = startTime
    }
}

/// Implement this delegate to receive information about the EventLoop, such as each tick
public protocol NIOEventLoopMetricsDelegate: Sendable {
    /// Called after a tick has run
    /// This function is called after every tick - avoid long-running tasks here
    /// - Warning: This function is called after every event loop tick and on the event loop thread. Any non-trivial work in this function will block the event loop and cause latency increases and performance degradation.
    /// - Parameter info: Information about the tick, such as how many tasks were executed
    func processedTick(info: NIOEventLoopTickInfo)
}

/// `EventLoop` implementation that uses a `Selector` to get notified once there is more I/O or tasks to process.
/// The whole processing of I/O and tasks is done by a `NIOThread` that is tied to the `SelectableEventLoop`. This `NIOThread`
/// is guaranteed to never change!
@usableFromInline
internal final class SelectableEventLoop: EventLoop {

    static let strictModeEnabled: Bool = {
        switch getenv("SWIFTNIO_STRICT").map({ String.init(cString: $0).lowercased() }) {
        case "true", "y", "yes", "on", "1":
            return true
        default:
            return false
        }
    }()