<!--
{
  "availability" : [

  ],
  "documentType" : "symbol",
  "framework" : "Event",
  "identifier" : "/documentation/Event/EventLoop/signalStream(_:)",
  "metadataVersion" : "0.1.0",
  "role" : "Instance Method",
  "symbol" : {
    "kind" : "Instance Method",
    "modules" : [
      "Event"
    ],
    "preciseIdentifier" : "s:5Event0A4LoopC12signalStreamyScSys5Int32VGAFd_tF"
  },
  "title" : "signalStream(_:)"
}
-->

# signalStream(_:)

Yields the signal number each time one of `signals` fires on this loop.

```
func signalStream(_ signals: Int32...) -> AsyncStream<Int32>
```

## Parameters

`signals`

One or more signal numbers to observe (e.g.
`SIGTERM`, `SIGINT`, `SIGHUP`, `SIGUSR1`).

## Return Value

An `AsyncStream<Int32>` yielding the signal number each time
any of the requested signals fires.

## Discussion

Backed by libevent’s `evsignal_*` machinery. libevent installs its own
signal-safe handler internally (the C-side handler only notes the
signal and lets the loop dispatch the callback in normal context), so
the closure body runs in regular Swift Concurrency context — none of
the async-signal-safety restrictions of raw `signal(2)` handlers
apply. This mirrors the safety story of Apple’s
[`DispatchSource.makeSignalSource(_:queue:)`](https://developer.apple.com/documentation/dispatch/dispatchsource/1781941-makesignalsource), which also defers
callbacks off the signal handler.

The stream is unbuffered by default (matches `AsyncStream`’s no-arg
constructor): values are delivered to the iterator if it is currently
awaiting, or buffered until it does. Stream termination —
`for await … break`, the iterating task being cancelled, or the
returned stream being dropped — calls `event_del(3)` on each
registered signal event, restoring the prior signal disposition.

> Important: libevent permits at most one `event_base` to claim a given
> signal at a time. If two ``doc://Event/documentation/Event/EventLoop`` instances in the same process
> call `signalStream` for the same signal number, the second
> registration’s behavior is undefined. In practice you should
> register process-global signals on a single event loop —
> ``doc://Event/documentation/Event/EventLoop/shared`` is the typical choice.

> Tip: When unit-testing code that consumes a signal stream, fire
> signals with `kill(getpid(), SIGUSR1)` rather than `raise(SIGUSR1)`.
> `raise()` is thread-directed (equivalent to
> `pthread_kill(pthread_self(), …)`) and only delivers to the calling
> thread; if the loop is being driven on a different thread — the
> typical test pattern — libevent’s handler never sees the signal and
> the test hangs. `kill(getpid(), …)` is process-directed so any
> unblocked thread, including the loop’s driver, can receive it.
> Production users whose signals come from external processes
> (`kill -TERM <pid>`, `Ctrl-C` from a shell) never hit this — those
> are already process-directed.

Composes cleanly with
[`swift-service-lifecycle`](https://github.com/swift-server/swift-service-lifecycle):
a service’s `run()` body can iterate this stream and call
`gracefulShutdown()` on the first value, breaking out of the loop to
trigger automatic teardown.