Files
snapd/.mailmap
Oliver Calder 4d01b69eb8 prompting: add epoll package (#12963)
* mailmap: map new commits from zygmunt.krynicki@canonical.com to me@zygoon.pl

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* Initial commit

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* Correct references to old name

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* osutil/epoll: fixed epoll test import

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* osutil/epoll: make Close() set epoll fd to -1

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: renamed `FromSys()` epoll event parameter name to `ev`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: added unit tests, but `Register()` always fails, as does ioctl syscall to prepare fd to register

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: removed unused `modeSet` type from epoll_test.go

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: replaced `syscall` with vendored `x/sys/unix`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: simplified `Readiness` type to match `EPOLL{IN,OUT}` flags

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: fix unit tests using socketpair

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: fixed typo in test

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: tie events list to instance with entry for each registered fd, and add unit tests

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: add `WaitTimeout(msec)` with configurable timeout

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: remove comment about using internal/poll instead of epoll

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: improve error message when epoll create syscall fails

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: use time.Duration instead of int in `WaitTimeout()`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: make epoll package thread safe

Replace the instance-specific event buffer with a mutex-guarded
registered FD count, allowing an event buffer with a number of slots
equal to the current number of registered FDs to be allocated in
`Wait()`, and thus allowing events from all FDs to be handled by a
single `Wait()` call.

Previously, the instance-specific event buffer was shared by separate
calls to `Wait()`, with the address of the start of the buffer passed
into the EPOLL_WAIT syscall, so multiple concurrent calls to `Wait()`
could cause race conditions where the contents of the buffer was
overwritten by multiple threads at once. Now, since the event buffer is
allocated within the `Wait()` function, this race condition is avoided.

Whenever a new FD is registered, the registeredFdCount variable is
incremented, and whenever an FD is deregistered, that variable is
decremented, in both cases guarded by the mutex for the epoll instance.

So what happens if there are n FDs registered, a call to `Wait()`
begins, and then while waiting, another FD is registered with the epoll
instance? Could this result in a buffer with too few entries for the now
(n+1) registered FDs? No, because beyond race conditions where the
kernel receives two write syscalls simultaneously and these end up in
the same epoll response (extremely unlikely), the only way that multiple
events are returned by the same call to `Wait()` is if there were
previous write events which had been caught by epoll but hadn't yet been
handled with an EPOLL_WAIT syscall. In this case, `Wait()` would
immediately return all those previous events, before the new FD is able
to be registered and written to.

The way around this would be if `Wait()` began, allocated the buffer
with size n, and then the thread were interrupted, and the new FD
registered and written to before the EPOLL_WAIT syscall occurred. In
this case, if all the initial n FDs had pending activity, then the
`Wait()` call would return an event buffer of size n, presumably with
the events for the original n FDs, and a subsequent call to `Wait()`
would return the event on the newly-registered FD. No event is lost in
any case.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: simplified duration in `Wait()`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: `s/waitMillisecondsThenWriteToFile/waitMillisecondsThenWriteToFd`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: simplified timeout duration definitions in tests

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: gracefully handle `EINT` errors from `EPOLL_WAIT` syscall

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: clarified handling of EINTR from EPOLL_WAIT syscall

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: replaced mutex with atomic Int32 calls wrapped in helper functions

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: added handling for waiting with no registered FDs

It may be the case that one wishes to wait for epoll events without
first registering any file descriptors to which to listen.  Perhaps
those file descriptors will be registered later by another thread, and
we want to capture any activity on them as soon as that occurs.  In any
case, we do not wish to deny the ability to call `Wait()` if there are
no registered FDs.

However, the `EpollWait` syscall requires a nonzero-length buffer to be
passed in (technically a nonzero length value, along with a pointer to
the buffer). Thus, in order to allow future registered FDs to be handled
by an existing wait call which was initiated when no FDs were
registered, it is necessary to ensure that a buffer of at least length 1
is passed into the `EpollWait` syscall.

Unit tests were added to check for correct waiting behavior when no FDs
are registered, when waiting is initiated before FD is registered, and
when the final FD is deregistered after wait has been initiated.

The `TestWaitThenRegister` function was rewritten to be more salient. In
particular, it now tests behavior when no FDs are registered at the time
`Wait()` is called, and then a new FD is registered and activity occurs
on it.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: added tests for {,de}registering bad file descriptors

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: improved the arbitrary nonexistent FD used by {,de}register tests

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: cleaned up increment/decrement order on error, and unneeded `runtime.KeepAlive()`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: added early return if epoll_wait returned 0 events

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: clean up opened sockets, and ensure Assert not called before reading from channels

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: use proper checker methods when applicable

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: Add comment about minimum buffer size for epoll_wait

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: added unit test for EINTR handling

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: reduced test sleep and timeout durations to make unit tests faster

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: defined `defaultDuration` for use in timing-sensitive unit tests

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* epoll: replaced `Errno` magic numbers with defined values

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

---------

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Co-authored-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
2023-07-25 10:00:57 +02:00

4 lines
262 B
Plaintext

Sergio Cazzolato <sergiocazzolato@gmail.com> sergio-j-cazzolato <sergio.cazzolato@canonical.com>
John R. Lenton <jlenton@gmail.com> John Lenton <chipaca@users.noreply.github.com>
Zygmunt Krynicki <me@zygoon.pl> Zygmunt Krynicki <zygmunt.krynicki@canonical.com>