Events were buffered with `bufferingNewest(512)`, so a burst of
changes silently lost all but the newest 512 events whenever the
consumer lagged. The stream now buffers without limit, and
`init(bufferingPolicy:)` lets callers choose a bounded policy.
`deinit` closed the inotify descriptor while its dispatch source was
still active. The kernel drops the epoll registration on close, but
libdispatch keeps its own; an instance created afterwards that reuses
the descriptor number could inherit that stale state and never
receive events. Roughly one test run in three lost a single event
this way.
The reader is now cancelled in `deinit` and the descriptor closed in
its cancel handler, as libdispatch requires.
Properties of actors are implicitly isolated. To be able to read the
events stream from any concurrent context, we need to declare it
nonisolated. And as AsyncStream conforms to Sendable, it is safe to make
both events and the private eventStream nonisolated.
For watching whole trees - a change which is upcoming - the watch
descriptor IDs will have to be managed in multiple lists. The
InotifyWatchManager encapsulates the managment logic within a nice API.
Instead of using hardcoded fixed width integers, use C integer types.
As the actual integer size of C depends on the implementation, even if
it is often 32bit, we use the C integer types to guard against cases,
where that is not the case.
Each inotify instance produces events for paths in its watch list. Each
item in the watch list is identified by its watch descriptor. Different
paths can be watched for different events.