<!--
{
  "availability" : [

  ],
  "documentType" : "symbol",
  "framework" : "Event",
  "identifier" : "/documentation/Event/EventLoop",
  "metadataVersion" : "0.1.0",
  "role" : "Class",
  "symbol" : {
    "kind" : "Class",
    "modules" : [
      "Event"
    ],
    "preciseIdentifier" : "s:5Event0A4LoopC"
  },
  "title" : "EventLoop"
}
-->

# EventLoop

A libevent-backed event loop owning an `event_base` for async I/O dispatch.

```
final class EventLoop
```

## Overview

`EventLoop` wraps libevent’s [`event_base`](https://libevent.org/doc/structevent__base.html) — the per-loop data
structure that watches file descriptors for readiness using the platform’s most
efficient I/O multiplexer (kqueue on Apple platforms, epoll on Linux, with POSIX
`poll(2)` as a fallback). [`Socket`](/documentation/Event/Socket) and [`ServerSocket`](/documentation/Event/ServerSocket) use an `EventLoop` to
schedule read- and write-ready callbacks and drive them to completion.

### Shared vs. owned loops

Most callers use the [`shared`](/documentation/Event/EventLoop/shared) singleton. Create a dedicated loop only when you
need isolation — for example, in tests that must not contend with application
traffic, or when you want distinct fd-watch sets per subsystem. The singleton is
fine for the common “one loop per process” pattern; it’s not a locking construct
and does not synchronize concurrent use from multiple tasks.

### Lifecycle

The typical flow is:

1. Acquire a loop (``doc://Event/documentation/Event/EventLoop/shared`` or ``doc://Event/documentation/Event/EventLoop/init()``).
1. Register I/O via ``doc://Event/documentation/Event/Socket`` / ``doc://Event/documentation/Event/ServerSocket`` methods — each method drives the
   loop internally via ``doc://Event/documentation/Event/EventLoop/runOnce()``.
1. Call ``doc://Event/documentation/Event/EventLoop/run()`` when you want a long-lived event-dispatch loop in a dedicated
   task, or rely on per-operation ``doc://Event/documentation/Event/EventLoop/runOnce()`` for one-shot use.
1. ``doc://Event/documentation/Event/EventLoop/stop()`` signals ``doc://Event/documentation/Event/EventLoop/run()`` to exit at its next dispatch boundary.

### Backend selection

The runtime backend is exposed via [`backendMethod`](/documentation/Event/EventLoop/backendMethod). swift-event asserts at test
time that this is `"kqueue"` on Apple platforms and `"epoll"` on Linux — see
[Backend and Platforms](/documentation/Event/BackendAndPlatforms) for the full backend story and the reasons
Windows IOCP, Solaris `devpoll`/`evport`, and OpenSSL bufferevents are excluded.

### Concurrency

Marked `@unchecked Sendable` to permit handoff of ownership across task boundaries.
The underlying `event_base` is **not** thread-safe: swift-event does not invoke
`evthread_use_pthreads()`, so concurrent calls into a single `EventLoop` from
multiple tasks are **undefined behavior at the libevent level**. The invariant is
single-owner-per-scope — hand off, do not share. See [Production Considerations](/documentation/Event/ProductionConsiderations)
“Concurrency Model” for the full honest description.