# Signal Handling

Use `SignalEOS` to gracefully shut down a pipeline on SIGINT (Ctrl+C) or
SIGTERM instead of crashing.

## Basic Usage

Inherit `SignalEOS` in your source element and check `self.signaled_eos()`:

```{.python notest}
from dataclasses import dataclass
from sgn import SourceElement, SourcePad, Frame
from sgn.sources import SignalEOS


@dataclass
class StreamingSource(SourceElement, SignalEOS):
    """A source that runs until interrupted."""
    def new(self, pad: SourcePad) -> Frame:
        if self.signaled_eos():
            return Frame(EOS=True)
        data = produce_data()  # Your data generation logic
        return Frame(data=data)
```

Wrap the pipeline execution with the `SignalEOS` context manager:

```{.python notest}
from sgn import Pipeline
from sgn.sources import SignalEOS

p = Pipeline()
# ... build pipeline ...

with SignalEOS():
    p.run()
```

When a signal is received, `signaled_eos()` returns `True`. The source produces
an EOS frame, which propagates through the pipeline, and all sinks mark EOS
normally. The pipeline shuts down cleanly.

## How It Works

1. On `__enter__`, `SignalEOS` replaces handlers for SIGINT and SIGTERM with a
   custom handler that records the signal.
2. On `__exit__`, the original signal handlers are restored.
3. `signaled_eos()` returns `True` if any handled signal has been received.

## Built-in Support

`NullSource` already inherits `SignalEOS`, so it works out of the box:

```{.python notest}
from sgn import Pipeline, NullSource, NullSink
from sgn.sources import SignalEOS

src = NullSource(name="src", source_pad_names=["H1"], wait=1.0)
snk = NullSink(name="snk", sink_pad_names=["H1"])

p = Pipeline()
p.connect(src, snk)

with SignalEOS():
    p.run()
# Press Ctrl+C to stop
```

## Combined with HTTPControl

`HTTPControl` inherits from `SignalEOS`, so using `HTTPControl` as a context
manager also provides signal handling:

```{.python notest}
from sgn.control import HTTPControl

with HTTPControl():
    p.run()
# Both HTTP control and signal handling are active
```
