Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions Sources/UnixSignals/UnixSignal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(Android)
import Android
#elseif canImport(ucrt)
import ucrt
#endif
import Dispatch

Expand All @@ -29,18 +31,21 @@ import Dispatch
public struct UnixSignal: Hashable, Sendable, CustomStringConvertible {
internal enum Wrapped {
case sigabrt
case sighup
case sigill
case sigint
case sigsegv
case sigterm
#if !os(Windows)
case sighup
case sigquit
case sigusr1
case sigusr2
case sigalrm
case sigquit
case sigwinch
case sigcont
case sigpipe
#endif
}

private let wrapped: Wrapped
Expand All @@ -58,18 +63,19 @@ public struct UnixSignal: Hashable, Sendable, CustomStringConvertible {

/// Usually generated by the abort() function. Useful for cleanup prior to termination.
public static let sigabrt = Self(.sigabrt)
/// Hang up detected on controlling terminal or death of controlling process. # ignore-unacceptable-language
public static let sighup = Self(.sighup)
/// Issued if the user attempts to execute an illegal, malformed, or privileged instruction.
public static let sigill = Self(.sigill)
/// Issued if the user sends an interrupt signal.
public static let sigint = Self(.sigint)
/// Issued if the user sends a quit signal.
public static let sigquit = Self(.sigquit)
/// Issued if the user makes an invalid memory reference, such as dereferencing a null or invalid pointer.
public static let sigsegv = Self(.sigsegv)
/// Software termination signal.
public static let sigterm = Self(.sigterm)
#if !os(Windows)
/// Hang up detected on controlling terminal or death of controlling process. # ignore-unacceptable-language
public static let sighup = Self(.sighup)
/// Issued if the user sends a quit signal.
public static let sigquit = Self(.sigquit)
public static let sigusr1 = Self(.sigusr1)
public static let sigusr2 = Self(.sigusr2)
public static let sigalrm = Self(.sigalrm)
Expand All @@ -78,6 +84,7 @@ public struct UnixSignal: Hashable, Sendable, CustomStringConvertible {
public static let sigcont = Self(.sigcont)
/// Signal when a write is performed on a closed fd
public static let sigpipe = Self(.sigpipe)
#endif
}

extension UnixSignal.Wrapped: Hashable {}
Expand All @@ -88,18 +95,19 @@ extension UnixSignal.Wrapped: CustomStringConvertible {
switch self {
case .sigabrt:
return "SIGABRT"
case .sighup:
return "SIGHUP"
case .sigill:
return "SIGILL"
case .sigint:
return "SIGINT"
case .sigquit:
return "SIGQUIT"
case .sigsegv:
return "SIGSEGV"
case .sigterm:
return "SIGTERM"
#if !os(Windows)
case .sighup:
return "SIGHUP"
case .sigquit:
return "SIGQUIT"
case .sigusr1:
return "SIGUSR1"
case .sigusr2:
Expand All @@ -112,6 +120,7 @@ extension UnixSignal.Wrapped: CustomStringConvertible {
return "SIGCONT"
case .sigpipe:
return "SIGPIPE"
#endif
}
}
}
Expand All @@ -121,18 +130,19 @@ extension UnixSignal.Wrapped {
switch self {
case .sigabrt:
return SIGABRT
case .sighup:
return SIGHUP
case .sigill:
return SIGILL
case .sigint:
return SIGINT
case .sigquit:
return SIGQUIT
case .sigsegv:
return SIGSEGV
case .sigterm:
return SIGTERM
#if !os(Windows)
case .sighup:
return SIGHUP
case .sigquit:
return SIGQUIT
case .sigusr1:
return SIGUSR1
case .sigusr2:
Expand All @@ -145,6 +155,7 @@ extension UnixSignal.Wrapped {
return SIGCONT
case .sigpipe:
return SIGPIPE
#endif
}
}
}
3 changes: 3 additions & 0 deletions Sources/UnixSignals/UnixSignalsSequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import Musl
#elseif canImport(Android)
@preconcurrency import Dispatch
import Android
#elseif canImport(ucrt)
@preconcurrency import ucrt
@preconcurrency import Dispatch
#endif
import ConcurrencyHelpers

Expand Down
8 changes: 8 additions & 0 deletions Tests/ServiceLifecycleTests/ServiceGroupAddServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import ServiceLifecycle
import UnixSignals
import XCTest

#if canImport(ucrt)
import ucrt
#endif

private struct ExampleError: Error, Hashable {}

@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
Expand Down Expand Up @@ -121,6 +125,7 @@ final class ServiceGroupAddServiceTests: XCTestCase {
await XCTAsyncAssertEqual(await mockService2.hasRun, false)
}

#if !os(Windows)
func testRun_whenAddedServiceExitsEarly_andIgnore() async throws {
let service1 = MockService(description: "Service1")
let service2 = MockService(description: "Service2")
Expand Down Expand Up @@ -153,6 +158,7 @@ final class ServiceGroupAddServiceTests: XCTestCase {
try await XCTAsyncAssertNoThrow(await group.next())
}
}
#endif

func testRun_whenAddedServiceExitsEarly_andShutdownGracefully() async throws {
let service1 = MockService(description: "Service1")
Expand Down Expand Up @@ -207,6 +213,7 @@ final class ServiceGroupAddServiceTests: XCTestCase {
}
}

#if !os(Windows)
func testRun_whenAddedServiceThrows() async throws {
let service1 = MockService(description: "Service1")
let service2 = MockService(description: "Service2")
Expand Down Expand Up @@ -369,6 +376,7 @@ final class ServiceGroupAddServiceTests: XCTestCase {
await service2.resumeRunContinuation(with: .success(()))
}
}
#endif

// MARK: - Helpers

Expand Down
6 changes: 5 additions & 1 deletion Tests/ServiceLifecycleTests/ServiceGroupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ final class ServiceGroupTests: XCTestCase {
}
}

#if !os(Windows)
func test_whenRun_ShutdownGracefully() async throws {
let mockService = MockService(description: "Service1")
let serviceGroup = self.makeServiceGroup(
Expand Down Expand Up @@ -694,7 +695,7 @@ final class ServiceGroupTests: XCTestCase {
}
}
}

func testGracefulShutdownOrdering_whenServiceThrows_andServiceGracefullyShutsdown() async throws {
let service1 = MockService(description: "Service1")
let service2 = MockService(description: "Service2")
Expand Down Expand Up @@ -955,6 +956,7 @@ final class ServiceGroupTests: XCTestCase {
await service1.resumeRunContinuation(with: .success(()))
}
}
#endif

func testTriggerGracefulShutdown() async throws {
let service1 = MockService(description: "Service1")
Expand Down Expand Up @@ -1014,6 +1016,7 @@ final class ServiceGroupTests: XCTestCase {
}
}

#if !os(Windows)
func testGracefulShutdownEscalation() async throws {
let mockService = MockService(description: "Service1")
let serviceGroup = self.makeServiceGroup(
Expand Down Expand Up @@ -1130,6 +1133,7 @@ final class ServiceGroupTests: XCTestCase {
try await XCTAsyncAssertNoThrow(await group.next())
}
}
#endif

func testTriggerGracefulShutdown_serviceThrows_inOrder_gracefullyShutdownGroup() async throws {
let service1 = MockService(description: "Service1")
Expand Down
10 changes: 8 additions & 2 deletions Tests/UnixSignalsTests/UnixSignalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import Glibc
import Musl
#elseif canImport(Android)
import Android
#elseif canImport(ucrt)
import ucrt
#endif

final class UnixSignalTests: XCTestCase {
#if !os(Windows)
func testSingleSignal() async throws {
let signal = UnixSignal.sigalrm
let signals = await UnixSignalsSequence(trapping: signal)
Expand Down Expand Up @@ -89,6 +92,7 @@ final class UnixSignalTests: XCTestCase {
XCTAssertEqual(second, .cancelled)
}
}
#endif

func testEmptySequence() async throws {
let signals = await UnixSignalsSequence(trapping: [])
Expand All @@ -97,6 +101,7 @@ final class UnixSignalTests: XCTestCase {
}
}

#if !os(Windows)
func testCorrectSignalIsGiven() async throws {
let signals = await UnixSignalsSequence(trapping: .sigterm, .sigusr1, .sigusr2, .sighup, .sigint, .sigalrm)
var signalIterator = signals.makeAsyncIterator()
Expand All @@ -110,7 +115,7 @@ final class UnixSignalTests: XCTestCase {
XCTAssertEqual(trapped, signal)
}
}

func testSignalRawValue() {
func assert(_ signal: UnixSignal, rawValue: Int32) {
XCTAssertEqual(signal.rawValue, rawValue)
Expand All @@ -124,7 +129,7 @@ final class UnixSignalTests: XCTestCase {
assert(.sigusr2, rawValue: SIGUSR2)
assert(.sigterm, rawValue: SIGTERM)
}

func testSignalCustomStringConvertible() {
func assert(_ signal: UnixSignal, description: String) {
XCTAssertEqual(String(describing: signal), description)
Expand All @@ -139,6 +144,7 @@ final class UnixSignalTests: XCTestCase {
assert(.sigterm, description: "SIGTERM")
assert(.sigwinch, description: "SIGWINCH")
}
#endif

func testCancelledTask() async throws {
let task = Task {
Expand Down
Loading