+
+ co_await std::move(f);
+ std::cout << "done\n";
+ });
+}
diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt
index 202e2805..a66222dc 100644
--- a/demos/CMakeLists.txt
+++ b/demos/CMakeLists.txt
@@ -54,6 +54,11 @@ endmacro ()
seastar_add_demo (block_discard
SOURCES block_discard_demo.cc)
+if (Seastar_EXPERIMENTAL_COROUTINES_TS)
+ seastar_add_demo (coroutines
+ SOURCES coroutines_demo.cc)
+endif ()
+
seastar_add_demo (echo
SOURCES echo_demo.cc)
--
2.20.1
--
You received this message because you are subscribed to the Google Groups "seastar-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to seastar-dev...@googlegroups.com.
To post to this group, send email to seast...@googlegroups.com.
Visit this group at https://groups.google.com/group/seastar-dev.
To view this discussion on the web visit https://groups.google.com/d/msgid/seastar-dev/20190124220007.21378-19-pdziepak%40scylladb.com.
For more options, visit https://groups.google.com/d/optout.
Hopefully no longer leaks of closing a socket w/out forgetting to wrap on a .finally() block.Excited to try it.
On 24/01/2019 23.59, Paweł Dziepak wrote:
> gnu::used seems to be a better choice than gnu::externally_visible to
> guarantee that the function will actually exist since it is unaffected by
> 'inline' and supported by clang.
Does it perform externally_visible's function (prevent -flto from
complaining)?
Did clang complain about gnu::externally_visible? It shouldn't, really.
On 25/01/2019 00.00, Paweł Dziepak wrote:
> [[gnu::no_sanitize_undefined]] is not supported by clang.
So why is it complaining?!
On 25/01/2019 00.00, Paweł Dziepak wrote:
> Unsurprisingly, clang has issues with gcc-specific pargmas.
> ---
> include/seastar/core/temporary_buffer.hh | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/include/seastar/core/temporary_buffer.hh b/include/seastar/core/temporary_buffer.hh
> index 5ff4d680..48180def 100644
> --- a/include/seastar/core/temporary_buffer.hh
> +++ b/include/seastar/core/temporary_buffer.hh
> @@ -82,14 +82,18 @@ class temporary_buffer {
> temporary_buffer(const temporary_buffer&) = delete;
>
> // At least at -O1, the inline decisions are such that the following code hits https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88897.
> +#ifndef __clang__
Since the following is gcc specific, should we not check for gcc instead?
On Sun, 27 Jan 2019 at 11:12, Avi Kivity <a...@scylladb.com> wrote:
On 24/01/2019 23.59, Paweł Dziepak wrote:
> gnu::used seems to be a better choice than gnu::externally_visible to
> guarantee that the function will actually exist since it is unaffected by
> 'inline' and supported by clang.
Does it perform externally_visible's function (prevent -flto from
complaining)?
Yes, it ensures that the symbol is exists even if LTO would think that it's not used: https://godbolt.org/z/EnFKV-It actually does externally_visible job better than externally_visible since it works with inline functions as well. I am not sure why would one use [[gnu::externally_visible]] instead of [[gnu::used]].
Did clang complain about gnu::externally_visible? It shouldn't, really.
That's indeed what the standard suggests (unknown implementation-defined attributes are ignored), but I agree with clang. Some attributes change the behaviour of the program ([[gnu::packed]], [[gnu::externally_visible]]) and debugging issues caused by the compiler silently ignoring them doesn't sound like fun. FWIW GCC also warns that an unknown attribute was ignored.
I can think of situations where we do want compiler-specific
attributes (starting when we support multiple compiler for real),
but we can defer the discussion until then. Unfortunately the
standard solutions look like SEASTAR_ATTR_GNU_EXTERNALLY_VISIBLE
which is quite painful to look at.
On Sun, 27 Jan 2019 at 11:14, Avi Kivity <a...@scylladb.com> wrote:
On 25/01/2019 00.00, Paweł Dziepak wrote:
> Unsurprisingly, clang has issues with gcc-specific pargmas.
> ---
> include/seastar/core/temporary_buffer.hh | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/include/seastar/core/temporary_buffer.hh b/include/seastar/core/temporary_buffer.hh
> index 5ff4d680..48180def 100644
> --- a/include/seastar/core/temporary_buffer.hh
> +++ b/include/seastar/core/temporary_buffer.hh
> @@ -82,14 +82,18 @@ class temporary_buffer {
> temporary_buffer(const temporary_buffer&) = delete;
>
> // At least at -O1, the inline decisions are such that the following code hits https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88897.
> +#ifndef __clang__
Since the following is gcc specific, should we not check for gcc instead?
Because clang lies and defines __GNUC__.
Well, we can't complain about someone trying really hard to be
compatible and missing some edge cases.
I guess the proper check should be __GNUC__ defined and __clang__ not defined, so that if we ever try to compile this with MSVC it also won't see GCC pragmas. Even better option would be to have compiler extensions sprinkled all over the code and instead have one header that takes care of all the ugly compiler-detection stuff and the rest of the code can just use appropriate definitions and macros. Seems slightly out of scope of this series though.
Yes.
I was commenting on the general principle, not on this case.
Edit: I see you also do that in abandoned(). Why is that not sufficient?
We should consider logging a warning, or perhaps capturing the current
stack trace into the broken_promise.
> ::seastar::schedule(std::make_unique<continuation<Func, T...>>(std::move(func), std::move(*state())));
> } else {
> assert(_promise);
> @@ -899,6 +921,19 @@ class future {
> }
> };
> void do_wait() noexcept {
> + if (__builtin_expect(!_promise, false)) {
> + // Encourage the compiler to move this away from the hot paths. __builtin_expect is not enough
> + // to do that. Cold lambdas work (at least for GCC8+).
> + [&] () __attribute__((cold)) {
> + try {
> + // Constructing broken_promise may throw (std::logic_error ctor is not noexcept).
> + _local_state.set_exception(std::make_exception_ptr(broken_promise{}));
> + } catch (...) {
> + _local_state.set_exception(std::current_exception());
> + }
> + }();
> + return;
Again extract, and maybe move to promise::abandoned().
On 25/01/2019 00.00, Paweł Dziepak wrote:
> This patch adds all necessary glue to make coroutines work with seastar
> futures and promises. They integrate seamlessly and any function that
> returns a future may become a coroutine.
>
> seastar/core/coroutines.hh also defines some classes that should be in
> experimental/coroutine (unless that file exists, in which case it is
> included instead) so that this can work with libstdc++ which doesn't
> provide that header.
This paragraph is outdated.
Ok. Your patch still handles this case, but later on when the
task is attached.
With futures and promises model it is possible that a promise is
destroyed before ever having a value set.
+ abandoned();
+ }
::seastar::schedule(std::make_unique<continuation<Func, T...>>(std::move(func), std::move(*state())));
} else {
assert(_promise);
@@ -801,6 +814,18 @@ class future {
}
}
+ // Used when there is to attempt to attach a continuation or a thread to a future
+ // that was abandoned by its promise.
+ [[gnu::cold]] [[gnu::noinline]]
+ void abandoned() noexcept {
+ try {
+ // Constructing broken_promise may throw (std::logic_error ctor is not noexcept).
+ _local_state.set_exception(std::make_exception_ptr(broken_promise{}));
+ } catch (...) {
+ _local_state.set_exception(std::current_exception());
+ }
+ }
+
template<typename... U>
friend class shared_future;
public:
@@ -899,6 +924,10 @@ class future {
}
};
void do_wait() noexcept {
+ if (__builtin_expect(!_promise, false)) {
--
You received this message because you are subscribed to the Google Groups "seastar-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to seastar-dev...@googlegroups.com.
To post to this group, send email to seast...@googlegroups.com.
Visit this group at https://groups.google.com/group/seastar-dev.
To view this discussion on the web visit https://groups.google.com/d/msgid/seastar-dev/20190129202023.14187-1-pdziepak%40scylladb.com.
On Tue, Jan 29, 2019 at 10:20 PM Paweł Dziepak <pdzi...@scylladb.com> wrote:
With futures and promises model it is possible that a promise is
destroyed before ever having a value set.
One of the key features of the promise/future pair is that they have independentlifetimes: One can destroy a promise before the future. This should have been trueeven if the promise is destroyed before being set. So it's good you fixed it.
I think a separate question is what should happen if a promise is destroyed beforebeing set, meaning that the future can *never* be resolved. Is it bad that a future willnever be resolved, or in this case can never be resolved?
It can easily happen:
promise<> pr;
auto f = pr.get_future();
some_function_that_throws();
// pass pr somewhere, call f.then();
Could somebody wantto do this deliberately (e.g., to get a future which can never resolve)?
No.
or is it much morelikely to be a bug?
It can happen due a code path not taking place due to an
exceptional return.
Do you see the new exception as a debugging aid to help a programmercatch cases where a promise object is lost or is this a feature users would directly use?
It prevents a fiber from hanging forever waiting for a future
that will never come.
So that users have to handle two exception hierarchies?
+ _local_state.set_exception(std::make_exception_ptr(broken_promise{}));
+ } catch (...) {
By the way, thinking of this - doesn't creating the exception and std::current_exception()require memory allocation? What happens if *that* throws?
You get a bad_alloc.
+ _local_state.set_exception(std::current_exception());
+ }
+ }
+
template<typename... U>
friend class shared_future;
public:
@@ -899,6 +924,10 @@ class future {
}
};
void do_wait() noexcept {
+ if (__builtin_expect(!_promise, false)) {
Unrelated to this patch, but the syntax of __builtin_expect is utterly unreadable and confusing (and caused us bugs in the past).Should we perhaps consider "likely"/"unlikely" macros?
No macros.
To view this discussion on the web visit https://groups.google.com/d/msgid/seastar-dev/CANEVyjsX_ZGhHxsmp_G%2BBtvWrBiJ9%2B%3D1LueoqiB0p%2B8LPZq9xA%40mail.gmail.com.
On Tue, Jan 29, 2019 at 10:20 PM Paweł Dziepak <pdzi...@scylladb.com> wrote:With futures and promises model it is possible that a promise is
destroyed before ever having a value set.One of the key features of the promise/future pair is that they have independentlifetimes: One can destroy a promise before the future. This should have been trueeven if the promise is destroyed before being set. So it's good you fixed it.I think a separate question is what should happen if a promise is destroyed beforebeing set, meaning that the future can *never* be resolved. Is it bad that a future willnever be resolved, or in this case can never be resolved? Could somebody wantto do this deliberately (e.g., to get a future which can never resolve)? or is it much morelikely to be a bug? Do you see the new exception as a debugging aid to help a programmercatch cases where a promise object is lost or is this a feature users would directly use?
+ abandoned();
+ }
::seastar::schedule(std::make_unique<continuation<Func, T...>>(std::move(func), std::move(*state())));
} else {
assert(_promise);
@@ -801,6 +814,18 @@ class future {
}
}
+ // Used when there is to attempt to attach a continuation or a thread to a future
+ // that was abandoned by its promise.
+ [[gnu::cold]] [[gnu::noinline]]
+ void abandoned() noexcept {
+ try {
+ // Constructing broken_promise may throw (std::logic_error ctor is not noexcept).What a mess :-( So should we perhaps *not* use std::logic_error and have our own, noexcept,error hierarchy?
+ _local_state.set_exception(std::make_exception_ptr(broken_promise{}));
+ } catch (...) {By the way, thinking of this - doesn't creating the exception and std::current_exception()require memory allocation? What happens if *that* throws?
+ _local_state.set_exception(std::current_exception());
+ }
+ }
+
template<typename... U>
friend class shared_future;
public:
@@ -899,6 +924,10 @@ class future {
}
};
void do_wait() noexcept {
+ if (__builtin_expect(!_promise, false)) {Unrelated to this patch, but the syntax of __builtin_expect is utterly unreadable and confusing (and caused us bugs in the past).Should we perhaps consider "likely"/"unlikely" macros?
I think a separate question is what should happen if a promise is destroyed beforebeing set, meaning that the future can *never* be resolved. Is it bad that a future willnever be resolved, or in this case can never be resolved? Could somebody wantto do this deliberately (e.g., to get a future which can never resolve)? or is it much morelikely to be a bug? Do you see the new exception as a debugging aid to help a programmercatch cases where a promise object is lost or is this a feature users would directly use?Deliberately causing an exception to be thrown in the "expected" path is always a bug.
The alternative (which I considered) to broken_promise exception would be an assertion failure, but since seastar is often used by servers, and abandoned future is not exactly a catastrophic failure (not nearly as server as memory corruption) I went for the way that gives the application a chance to recover. Again, if a broken promise is thrown this means there is a bug in the program, but one can imagine scenarios where botched up exception safety has lead to future being abandoned and an abort would be a harsh punishment.
template <typename Func>
void schedule(Func&& func) {
- if (state()->available()) {
+ if (state()->available() || !_promise) {
+ if (__builtin_expect(!state()->available() && !_promise, false)) {Nitpick: if this is what you check here, why not have a "else if(!_promise)" below (as else for if(state()->available()) instead if sticking it in the same if?I am not sure if I understand what you mean, but this condition is fall-through.
On Wed, Jan 30, 2019 at 1:06 PM Paweł Dziepak <pdzi...@scylladb.com> wrote:I think a separate question is what should happen if a promise is destroyed beforebeing set, meaning that the future can *never* be resolved. Is it bad that a future willnever be resolved, or in this case can never be resolved? Could somebody wantto do this deliberately (e.g., to get a future which can never resolve)? or is it much morelikely to be a bug? Do you see the new exception as a debugging aid to help a programmercatch cases where a promise object is lost or is this a feature users would directly use?Deliberately causing an exception to be thrown in the "expected" path is always a bug.Of course. What I meant was whether somebody might want to deliberately do something likefuture<> never(){promise p;return p.get_future();}and use it in some context that requires a future as a parameter but we never want it to be resolved.If we wanted to support this, you'd still need to fix the code as you did, just NOT throw an exception (or assert, or anything).But you're probably right that it's much more likely that somebody accidentally destroyed p instead of doing it deliberately as in this silly use case, so I think your idea is worthwhile as a debugging aid (and of course it's better than the current possibility of crashing).Also, if somebody really wants to implement never() he can still do this through a promise allocated on the heap (or other mechanisms).