This patches shows what change is needed for http to run with multiple
event loops. This is not very useful still because actual work is not
yet distributed.
This patch adds an ability to specify how much threads seastart should
spawn. Each thread run its own instance of event loop. Separate
communication channel is created between each pair of threads.
Currently thread_pool implements cross-thread communication channel
internally. Separate communication logic into its own class to
reuse it for smp communication in later patches.
Simplify it for the many possible states of the unsent queue:
- empty: return an empty packet
- one small packet: dequeue and return
- one large packet at head: split and return
- many packets, starting with a small one: merge first, split last
Move reference counting into the deleter core, instead of relegating it
to a shared_deleter (which has to be allocated) and an external reference
counted (also allocated). This dramatically reduces dynamic allocations.
Instead of using internal_deleter, which is unwieldy, store the
header data inside packet::impl which we're allocating anyway.
This adds some complication when we need to reallocate impl (if
the number of fragments overflows), but usually saves two allocations:
one for the internal_deleter and one for the data itself.
deleter::share() is causing massive amounts of allocation. First,
since usually a packet's deleter is not a shared_deleter, we need to
allocate that shared_deleter. Second, we need an external reference
count which requires yet another allocation.
Making reference counting part of the deleter class would solve both of
these problems, but we cannot easily do that, since users hold
std::unique_ptr<deleter> which is clearly not sharable.
We could do a massive s/unique_ptr/shared_ptr/ here, but that would have
the side effect of making sharing "too easy" - you simply copy the pointer.
We'd like to keep it explicit.
So to make the change easier, rename the existing unique_ptr<deleter> as
plain "deleter", whereas the old "deleter" becomes deleter::impl:
old name new name
-------- --------
deleter deleter::impl
unique_ptr<deleter> deleter
with exactly the same semantics. A later patch can then add explicit sharing.
This fixes SIGSEGV which happens when a promise gets resolved and
dies before the callback is registerred via then(). The latter assumes
that _promise must not be nullptr if the state is not resolved
yet. The dying promise should move the resolved state into the
future's local state.
The future/promise pair is for single-shot use only, which makes it
less useful for repetitive processing.
Add a stream/subscription abstraction, where a stream can produce data
which is repetitively consumed by the subscription. End-or-stream (or
error condition) is provided by a future.
Inspired by Dart's Stream class.
As the whole point of future/promise is to decouple the producer from the
consumer, available() is not generally useful. However it can still be
useful in special cases when we want to know who got there first.
One of them is deciding when to drop packets -- if the consumer is not
ready, and no queue space is available, we should just drop the packet
instead of waiting for the consumer.
Virtio net options:
--event-index arg (=on) Enable event_index feature (on / off)
By default, --event-index is enable. To disable, e.g.:
$ ./httpd --network-stack native --event-index off