Remove `read` and `write` classes and just use `source` and `sink` for
everything.
Rename `Flow.read_into src buf` to just `Flow.read src buf`, which makes
more sense.
Now that `readv` is implemented, we can read directly into the user's
buffer. Testing this by reading from /dev/null into a 64K buffer was
about 5 times faster than the old way (which has a copy and is limited
by the chunk size).
Nothing in here actually depends on Unix. This is just a collection of
utility modules that may be useful for building Eio backends. There is
no need for a separate opam package.
Cancellation contexts are now only about making things stop promptly,
not about reporting errors. That's now handled entirely by the switches.
This fixes a problem where an error raised while cancelling an operation
would be lost.
`Switch.turn_off` is now called `Switch.fail`.
`fork_on_accept` runs an accept function in a new switch. If it
succeeds, it passes the result to a handler function in a new fibre,
which adopts the switch.
This allows moving the complicated accept logic out of the individual
backends. It also allows adding the simpler `Net.accept` function for
the case where only a single connection needs to be accepted.
The behaviour of `Fork.sub ~sw ~on_error` has changed slightly:
`on_error` now runs in the context of the parent `sw`,
and is now skipped if and only if `sw` is cancelled.
Also, the `on_release` argument has been removed, since its only use can
now be done using `fork_on_accept`.
This commit adds the option of setting SO_REUSEPORT socket option in
linux_uring backend.
For libuv/luv backend, it seems it is not easy to set it as yet. This
is related to another outstanding issue related to SO_REUSEADDR
option in libuv backend. Perhaps once luv releases luv-unix, we can
revisit this issue again. For now in-order to ensure the repo builds
I have followed a similar approach as SO_REUSEADDR, i.e. dummy
function `luv_reuse_port` analogous to `luv_resuse_addr`.
SO_REUSEPORT can be used to build scalable, high performance network
servers in linux version 3.9 and over. This is so because reuseport
is used to enable socket sharding on multiple threads or child
processes. Listening sockets with SO_REUSEPORT enabled are further
load balanced by the kernel; so we get a performant load balancer
for free.
References:
https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ
Signed-off-by: Bikal Lem <gbikal+git@gmail.com>
Some arguments in favour of this:
- This is the most flexible arrangement (you can add yields gets the
other combinations).
- The order seems a bit more natural (the README examples look better).
- Might be better for the cache in some cases (domainslib works this way).
- Means that `Fibre.both f g` starts `f` and `g` in similar contexts.
Previously, `f` started before any queued items, while `g` started
after, which was a bit inconsistent.
This also adds some documentation about scheduling order to the ocamldoc
(note that the previous documentation for `fork` was wrong) and adds a
`rationale.md` file explaining the choice.
Previously, each cancellation context kept a list of functions to call
when cancelled. When a cancellable operation starts, a function is
registered which can be used to cancel it. When the operation finishes
(or is cancelled) the function is removed again.
With multiple domains, an operation may succeed in one domain just as it
is being cancelled in another. Since removing a node from a
doubly-linked list cannot be done atomically, this would require a
mutex.
Instead, a cancellation context now keeps a list of fibres. When a fibre
is forked, it gets added to the list, and when it finishes it is
removed. A fibre can also move to a new context (e.g. on `Cancel.sub`).
This list is only accessed from the fibre's own domain.
Each fibre holds a single (atomic, optional) cancellation function.
This is set when a cancellable operation starts. When the operation is
cancelled or finishes, this is cleared (using `Atomic.exchange`) and
the continuation is enqueued to be run.
This also fixes a cancellation bug in `Eio_luv.File`, where we cleared
the cancellation callback after starting an operation, not after it
ended!
If the scheduler crashes, it tries to shut down the uring, which is
likely to fail. In that case, `Fun.protect` throws away the original
exception, which isn't helpful.
Instead of requiring every cancellable operation to pass a `~sw`
argument, give each fibre a default switch and use that. It's too easy
to forget to make something cancellable and clutters up the code.
Allows sources to offer faster alternatives. This is useful for e.g.
faraday and tls, which allocate their own buffers. The Linux FD sink
now uses `writev` to send the data directly where possible.
- Set up a box so that wrapping works correctly.
- Print a `+` at the start of each trace line to show it is trace output.
- Format location tag with the rest of the output (fixes wrapping).
- Add tests for traceln.