From b968f8069506f7b160a20ef5ceda3dd62d6e8a5b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 15:18:56 +0200 Subject: [PATCH 1/4] future: report abandoned failed futures Report an abandoned future containing an exception, corresponding to an uncaught exception in an ordinary program. --- core/future.hh | 26 ++++++++++++++++++++++++-- core/reactor.cc | 10 ++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/future.hh b/core/future.hh index 9018081bf3..49fa813abf 100644 --- a/core/future.hh +++ b/core/future.hh @@ -70,6 +70,8 @@ make_task(Func&& func) { return std::unique_ptr(new lambda_task(std::move(func))); } +void report_failed_future(std::exception_ptr ex); + // // A future/promise pair maintain one logical value (a future_state). // To minimize allocations, the value is stored in exactly one of three @@ -169,10 +171,17 @@ struct future_state { _state = state::exception; new (&_u.ex) std::exception_ptr(ex); } + std::exception_ptr get_exception() noexcept { + assert(_state == state::exception); + // Move ex out so future::~future() knows we've handled it + return std::move(_u.ex); + } std::tuple get() { assert(_state != state::future); if (_state == state::exception) { - std::rethrow_exception(_u.ex); + _state = state::invalid; + // Move ex out so future::~future() knows we've handled it + std::rethrow_exception(std::move(_u.ex)); } return std::move(_u.value); } @@ -212,6 +221,8 @@ struct future_state<> { if (x._u.st < state::exception_min) { _u.st = x._u.st; } else { + // Move ex out so future::~future() knows we've handled it + // Moving it will reset us to invalid state new (&_u.ex) std::exception_ptr(std::move(x._u.ex)); } } @@ -249,10 +260,18 @@ struct future_state<> { std::tuple<> get() { assert(_u.st != state::future); if (_u.st >= state::exception_min) { - std::rethrow_exception(_u.ex); + // Move ex out so future::~future() knows we've handled it + // Moving it will reset us to invalid state + std::rethrow_exception(std::move(_u.ex)); } return {}; } + std::exception_ptr get_exception() noexcept { + assert(_u.st >= state::exception_min); + // Move ex out so future::~future() knows we've handled it + // Moving it will reset us to invalid state + return std::move(_u.ex); + } void forward_to(promise<>& pr) noexcept; }; @@ -469,6 +488,9 @@ public: if (_promise) { _promise->_future = nullptr; } + if (failed()) { + report_failed_future(state()->get_exception()); + } } std::tuple get() { return state()->get(); diff --git a/core/reactor.cc b/core/reactor.cc index 1d1aeb9d51..9273b2ed2d 100644 --- a/core/reactor.cc +++ b/core/reactor.cc @@ -1198,6 +1198,16 @@ void schedule(std::unique_ptr t) { engine().add_task(std::move(t)); } +void report_failed_future(std::exception_ptr exp) { + try { + std::rethrow_exception(std::move(exp)); + } catch (std::exception& ex) { + std::cerr << "WARNING: exceptional future ignored: " << ex.what() << "\n"; + } catch (...) { + std::cerr << "WARNING: exceptional future ignored\n"; + } +} + bool operator==(const ::sockaddr_in a, const ::sockaddr_in b) { return (a.sin_addr.s_addr == b.sin_addr.s_addr) && (a.sin_port == b.sin_port); } From facb2ffdc6f35476d8416b7d941438e1e6237a1f Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 16 Mar 2015 07:53:54 +0200 Subject: [PATCH 2/4] build: allow disabling debug info generation Closes #37. --- configure.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.py b/configure.py index f447dc725e..8906bc21df 100755 --- a/configure.py +++ b/configure.py @@ -138,6 +138,8 @@ arg_parser.add_argument('--with-osv', action = 'store', dest = 'with_osv', defau help = 'Shortcut for compile for OSv') arg_parser.add_argument('--dpdk-target', action = 'store', dest = 'dpdk_target', default = '', help = 'Path to DPDK SDK target location (e.g. /x86_64-native-linuxapp-gcc)') +arg_parser.add_argument('--debuginfo', action = 'store', dest = 'debuginfo', type = int, default = 1, + help = 'Enable(1)/disable(0)compiler debug information generation') add_tristate(arg_parser, name = 'hwloc', dest = 'hwloc', help = 'hwloc support') add_tristate(arg_parser, name = 'xen', dest = 'xen', help = 'Xen support') args = arg_parser.parse_args() @@ -264,7 +266,7 @@ warnings = [w warnings = ' '.join(warnings) -dbgflag = debug_flag(args.cxx) +dbgflag = debug_flag(args.cxx) if args.debuginfo else '' def have_hwloc(): return try_compile(compiler = args.cxx, source = '#include \n#include ') From c0d7e4e748a47dfd33e28ef19cb091894bda0aed Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Mon, 16 Mar 2015 09:56:19 +0200 Subject: [PATCH 3/4] core: implement future<> sleep() Seastar applications obviously cannot use the Posix sleep() function, or the entire thread will block. This patch implements future<> sleep(duration) where as expected, the future becomes ready when the given duration passes. For example, one can do: sleep(1s).then([] { std::cout << "Done.\n"; }); This can be useful as an example of futures and continuations in the Seastar tutorial, and people might find other uses for it. This sleep() is implemented in terms of timer<>. sleep() is easier to use and more aligned with the rest of Seastar (it uses then() for the continuation instead of a set_callback() method). The downside of sleep() compared to a timer is that it cannot be canceled once started. In this version, sleep() is implemented without shared_ptr, making the implementation a tiny bit more efficient. There is still a heap allocation (this is unavoidable because std::function requires a copyable type) but no reference counting. Unfortunately, this requires us to use bare "new" and "delete". Signed-off-by: Nadav Har'El --- core/sleep.hh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 core/sleep.hh diff --git a/core/sleep.hh b/core/sleep.hh new file mode 100644 index 0000000000..24b3f54c34 --- /dev/null +++ b/core/sleep.hh @@ -0,0 +1,44 @@ +/* + * This file is open source software, licensed to you under the terms + * of the Apache License, Version 2.0 (the "License"). See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. You may not use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Copyright (C) 2015 Cloudius Systems, Ltd. + */ + +#pragma once + +#include +#include + +#include "core/shared_ptr.hh" +#include "core/reactor.hh" +#include "core/future.hh" + +template +future<> sleep(std::chrono::duration dur) { + struct sleeper { + promise<> done; + timer tmr; + sleeper(std::chrono::duration dur) + : tmr([this] { done.set_value(); delete this; }) + { + tmr.arm(dur); + } + }; + return (new sleeper(dur))->done.get_future(); +} From a7d6e22bafe23979da3fabc75683f62700ffe6f9 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Tue, 17 Mar 2015 08:31:24 +0100 Subject: [PATCH 4/4] sstring: fix bounds checks in find() 'end' iterator was set past the end if pos != 0. --- core/sstring.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sstring.hh b/core/sstring.hh index ae6b336a77..5d688e2d52 100644 --- a/core/sstring.hh +++ b/core/sstring.hh @@ -178,7 +178,7 @@ public: size_t find(char_type t, size_t pos = 0) const noexcept { const char_type* it = str() + pos; - const char_type* end = it + size(); + const char_type* end = str() + size(); while (it < end) { if (*it == t) { return it - str(); @@ -190,7 +190,7 @@ public: size_t find(const basic_sstring& s, size_t pos = 0) const noexcept { const char_type* it = str() + pos; - const char_type* end = it + size(); + const char_type* end = str() + size(); const char_type* c_str = s.str(); const char_type* c_str_end = s.str() + s.size();