A future that does not carry any data (future<>) and its sibling (promise<>)
are heavily used in the code. We can optimize them by overlaying the
future's payload, which in this case can only be an std::exception_ptr,
with the future state, as a pointer and an enum have disjoint values.
This of course depends on std::exception_ptr being implemented as a pointer,
but as it happens, it is.
With this, sizeof(future<>) is reduced from 24 bytes to 16 bytes.
Use when you don't want to care about the result and just want to
return a future<>.
The current implementation may not be the most optimal way to do it
but it can be improved later if there's need.
Unlike future::then(), which unwraps the value, then_wrapped() keeps it
wrapped in a future<>, so if it is exceptional, it can still be accessed.
This is similar to the proposed std::future::then(), so we should later
rename it to match (and rename the existing future::then() to future::next().
It did not handle properly the case when the target promise's future gets dead
without installing a callback or the future was never installed. The
mishanlding of the former case was causing httpd to abort on SMP.
We can avoid extra allocation and chaining by linking the current
future's promise with the target promise's future, as if the target
promise was moved into the current future's promise.
Test case (added in the next patch):
promise<> p1;
promise<> p2;
auto f = p1.get_future().then([f = std::move(p2.get_future())] () mutable {
return std::move(f); // this future will fail
}).then([] {
// never reached, that's ok
});
p1.set_value();
p2.set_exception(std::runtime_error("boom"));
// f should get resolved eventually with error, but was not
The callback passed to it will be executed when future gets resolved,
successfully or not. The returned future will mimic the state of the
target future.
This will allow the user to have one handler for both success and
failure. This simplifies client code a bit when both paths need to
work on the same object. Having to split the function into two
callbacks, one of which is passed to then() and the other to rescue()
on a resulting promise, would make it necessary to wrap the object in
a shared_ptr, which is suboptimal.
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.
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.
Instead of keeping the future state in heap storage, referenced from
the promise/future/task, keep the state in the promise or future and only
allocate it on the heap as a last resort (for a stack).
Improves httpd throughtput by ~20%.