From 7bc7951192b4d799d746405427359ea2a451500a Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 13 Mar 2015 16:20:17 +0100 Subject: [PATCH 01/16] core: Use perfect forwarding in invoke_on()/submit_to() Makes invoking non-copyable lambdas possible: distributed t; non_copyable_type x; t.invoke_on(0, [x = std::move(x)] (auto& t) {}); As a side effect this could save some copyable lambdas from being needlesly copied. --- core/distributed.hh | 2 +- core/reactor.hh | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/distributed.hh b/core/distributed.hh index dd5ecfac54..f9e5002292 100644 --- a/core/distributed.hh +++ b/core/distributed.hh @@ -152,7 +152,7 @@ public: futurize_t> invoke_on(unsigned id, Func&& func) { auto inst = _instances[id]; - return smp::submit_to(id, [inst, func] { + return smp::submit_to(id, [inst, func = std::forward(func)] () mutable { return func(*inst); }); } diff --git a/core/reactor.hh b/core/reactor.hh index e9c56921b3..07a6b355fa 100644 --- a/core/reactor.hh +++ b/core/reactor.hh @@ -477,9 +477,9 @@ class smp_message_queue { public: smp_message_queue(); template - std::result_of_t submit(Func func) { + std::result_of_t submit(Func&& func) { using future = std::result_of_t; - auto wi = new async_work_item(std::move(func)); + auto wi = new async_work_item(std::forward(func)); auto fut = wi->get_future(); submit_item(wi); return fut; @@ -881,25 +881,25 @@ public: static bool main_thread() { return std::this_thread::get_id() == _tmain; } template - static std::result_of_t submit_to(unsigned t, Func func, + static std::result_of_t submit_to(unsigned t, Func&& func, std::enable_if_t::value, void*> = nullptr) { if (t == engine().cpu_id()) { return func(); } else { - return _qs[t][engine().cpu_id()].submit(std::move(func)); + return _qs[t][engine().cpu_id()].submit(std::forward(func)); } } template - static future> submit_to(unsigned t, Func func, + static future> submit_to(unsigned t, Func&& func, std::enable_if_t::value && !returns_void::value, void*> = nullptr) { - return submit_to(t, [func = std::move(func)] () mutable { + return submit_to(t, [func = std::forward(func)] () mutable { return make_ready_future>(func()); }); } template - static future<> submit_to(unsigned t, Func func, + static future<> submit_to(unsigned t, Func&& func, std::enable_if_t::value && returns_void::value, void*> = nullptr) { - return submit_to(t, [func = std::move(func)] () mutable { + return submit_to(t, [func = std::forward(func)] () mutable { func(); return make_ready_future<>(); }); From 74e34ed6a4f284c03dd498af5261f7d11e96896e Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 13 Mar 2015 20:37:09 +0100 Subject: [PATCH 02/16] core: Use futurize<> to simplify smp::submit_to() --- core/reactor.hh | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/core/reactor.hh b/core/reactor.hh index 07a6b355fa..fbb5143871 100644 --- a/core/reactor.hh +++ b/core/reactor.hh @@ -433,17 +433,19 @@ class smp_message_queue { virtual future<> process() = 0; virtual void complete() = 0; }; - template + template struct async_work_item : work_item { Func _func; - using value_type = typename Future::value_type; + using futurator = futurize>; + using future_type = typename futurator::type; + using value_type = typename future_type::value_type; std::experimental::optional _result; std::exception_ptr _ex; // if !_result - typename Future::promise_type _promise; // used on local side + typename futurator::promise_type _promise; // used on local side async_work_item(Func&& func) : _func(std::move(func)) {} virtual future<> process() override { try { - return this->_func().then_wrapped([this] (auto&& f) { + return futurator::apply(this->_func).then_wrapped([this] (auto&& f) { try { _result = f.get(); } catch (...) { @@ -463,7 +465,7 @@ class smp_message_queue { _promise.set_exception(std::move(_ex)); } } - Future get_future() { return _promise.get_future(); } + future_type get_future() { return _promise.get_future(); } }; union tx_side { tx_side() {} @@ -477,9 +479,8 @@ class smp_message_queue { public: smp_message_queue(); template - std::result_of_t submit(Func&& func) { - using future = std::result_of_t; - auto wi = new async_work_item(std::forward(func)); + futurize_t> submit(Func&& func) { + auto wi = new async_work_item(std::forward(func)); auto fut = wi->get_future(); submit_item(wi); return fut; @@ -881,29 +882,13 @@ public: static bool main_thread() { return std::this_thread::get_id() == _tmain; } template - static std::result_of_t submit_to(unsigned t, Func&& func, - std::enable_if_t::value, void*> = nullptr) { + static futurize_t> submit_to(unsigned t, Func&& func) { if (t == engine().cpu_id()) { - return func(); + return futurize>::apply(std::forward(func)); } else { return _qs[t][engine().cpu_id()].submit(std::forward(func)); } } - template - static future> submit_to(unsigned t, Func&& func, - std::enable_if_t::value && !returns_void::value, void*> = nullptr) { - return submit_to(t, [func = std::forward(func)] () mutable { - return make_ready_future>(func()); - }); - } - template - static future<> submit_to(unsigned t, Func&& func, - std::enable_if_t::value && returns_void::value, void*> = nullptr) { - return submit_to(t, [func = std::forward(func)] () mutable { - func(); - return make_ready_future<>(); - }); - } static bool poll_queues() { size_t got = 0; for (unsigned i = 0; i < count; i++) { From ecb72e995ad7534c19ed2a3de9b7385b609b6887 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 15 Mar 2015 12:18:44 +0200 Subject: [PATCH 03/16] core: drop superfluous qualifier from or_terminate --- core/future.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/future.hh b/core/future.hh index 9018081bf3..b5598b0a8e 100644 --- a/core/future.hh +++ b/core/future.hh @@ -593,7 +593,7 @@ public: return f; } - future<> or_terminate() && noexcept { + future<> or_terminate() noexcept { return then_wrapped([] (auto&& f) { try { f.get(); From c138e31a2a4652e6362490764a1e86a906e05e09 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 15 Mar 2015 12:41:26 +0200 Subject: [PATCH 04/16] core: check future_avail_count in then_wrapped --- core/future.hh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/future.hh b/core/future.hh index b5598b0a8e..0a751b97d2 100644 --- a/core/future.hh +++ b/core/future.hh @@ -521,7 +521,7 @@ public: then_wrapped(Func&& func) noexcept { using futurator = futurize)>>; using P = typename futurator::promise_type; - if (state()->available()) { + if (state()->available() && (++future_avail_count % 256)) { try { return futurator::apply(std::forward(func), std::move(*this)); } catch (...) { @@ -532,7 +532,7 @@ public: } P pr; auto next_fut = pr.get_future(); - _promise->schedule([func = std::forward(func), pr = std::move(pr)] (auto& state) mutable { + schedule([func = std::forward(func), pr = std::move(pr)] (auto& state) mutable { try { futurator::apply(std::forward(func), future(std::move(state))) .forward_to(std::move(pr)); @@ -540,8 +540,6 @@ public: pr.set_exception(std::current_exception()); } }); - _promise->_future = nullptr; - _promise = nullptr; return next_fut; } From ad63b70d53daffc16494f55d84ee5e26c834f0c1 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 15 Mar 2015 14:11:51 +0200 Subject: [PATCH 05/16] core: remove unused structure future_task --- core/future.hh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/future.hh b/core/future.hh index 0a751b97d2..16cf4944a9 100644 --- a/core/future.hh +++ b/core/future.hh @@ -256,15 +256,6 @@ struct future_state<> { void forward_to(promise<>& pr) noexcept; }; -template -struct future_task final : task, future_state { - Func _func; - future_task(Func&& func) : _func(std::move(func)) {} - virtual void run() noexcept { - func(*this); - } -}; - template class promise { future* _future = nullptr; From 186e25717e873e8df7b1d56c57d709226935a96d Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 15 Mar 2015 14:12:54 +0200 Subject: [PATCH 06/16] core: consolidate then() and then_wrapped() code --- core/future.hh | 86 +++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/core/future.hh b/core/future.hh index 16cf4944a9..fee3101931 100644 --- a/core/future.hh +++ b/core/future.hh @@ -315,7 +315,7 @@ private: struct task_with_state final : task { task_with_state(Func&& func) : _func(std::move(func)) {} virtual void run() noexcept override { - _func(_state); + _func(std::move(_state)); } future_state _state; Func _func; @@ -422,7 +422,7 @@ private: struct task_with_ready_state final : task { task_with_ready_state(Func&& func, future_state&& state) : _state(std::move(state)), _func(std::move(func)) {} virtual void run() noexcept override { - _func(_state); + _func(std::move(_state)); } future_state _state; Func _func; @@ -435,6 +435,32 @@ private: _promise = nullptr; } } + + template + futurize_t then(Func&& func, Param&& param) noexcept { + using futurator = futurize; + using P = typename futurator::promise_type; + if (state()->available() && (++future_avail_count % 256)) { + try { + return futurator::apply(std::forward(func), param(std::move(*state()))); + } catch (...) { + P p; + p.set_exception(std::current_exception()); + return p.get_future(); + } + } + P pr; + auto fut = pr.get_future(); + schedule([pr = std::move(pr), func = std::forward(func), param = std::forward(param)] (auto&& state) mutable { + try { + futurator::apply(std::forward(func), param(std::move(state))).forward_to(std::move(pr)); + } catch (...) { + pr.set_exception(std::current_exception()); + } + }); + return fut; + } + public: using value_type = std::tuple; using promise_type = promise; @@ -475,26 +501,13 @@ public: template futurize_t> then(Func&& func) noexcept { - using futurator = futurize>; - if (state()->available() && (++future_avail_count % 256)) { - try { - return futurator::apply(std::forward(func), std::move(state()->get())); - } catch (...) { - typename futurator::promise_type p; - p.set_exception(std::current_exception()); - return p.get_future(); - } - } - typename futurator::promise_type pr; - auto fut = pr.get_future(); - schedule([pr = std::move(pr), func = std::forward(func)] (auto& state) mutable { - try { - futurator::apply(std::forward(func), state.get()).forward_to(std::move(pr)); - } catch (...) { - pr.set_exception(std::current_exception()); - } - }); - return fut; + return then>(std::forward(func), [] (future_state&& state) { return state.get(); }); + } + + template + futurize_t)>> + then_wrapped(Func&& func) noexcept { + return then)>>(std::forward(func), [] (future_state&& state) { return future(std::move(state)); }); } void forward_to(promise&& pr) noexcept { @@ -507,33 +520,6 @@ public: } } - template - futurize_t)>> - then_wrapped(Func&& func) noexcept { - using futurator = futurize)>>; - using P = typename futurator::promise_type; - if (state()->available() && (++future_avail_count % 256)) { - try { - return futurator::apply(std::forward(func), std::move(*this)); - } catch (...) { - P pr; - pr.set_exception(std::current_exception()); - return pr.get_future(); - } - } - P pr; - auto next_fut = pr.get_future(); - schedule([func = std::forward(func), pr = std::move(pr)] (auto& state) mutable { - try { - futurator::apply(std::forward(func), future(std::move(state))) - .forward_to(std::move(pr)); - } catch (...) { - pr.set_exception(std::current_exception()); - } - }); - return next_fut; - } - /** * Finally continuation for statements that require waiting for the result. I.e. you need to "finally" call * a function that returns a possibly unavailable future. @@ -568,7 +554,7 @@ public: state()->forward_to(pr); return f; } - _promise->schedule([pr = std::move(pr), func = std::forward(func)] (auto& state) mutable { + _promise->schedule([pr = std::move(pr), func = std::forward(func)] (auto&& state) mutable { try { func(); } catch (...) { From c3ba8678e4cfc348ef1d2bb532949731a9e55f39 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 15 Mar 2015 14:44:58 +0200 Subject: [PATCH 07/16] core: consolidate finally() implemetations --- core/future.hh | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/core/future.hh b/core/future.hh index fee3101931..9e5a5baf3a 100644 --- a/core/future.hh +++ b/core/future.hh @@ -527,9 +527,10 @@ public: * is ignored. I.e. the original return value (the future upon which you are making this call) will be preserved. */ template - future finally(Func&& func, std::enable_if_t>::value, void*> = nullptr) noexcept { - return then_wrapped([func = std::forward(func)](future result) { - return func().then_wrapped([result = std::move(result)](auto f_res) mutable { + future finally(Func&& func) noexcept { + return then_wrapped([func = std::forward(func)](future result) mutable { + using futurator = futurize>; + return futurator::apply(std::forward(func)).then_wrapped([result = std::move(result)](auto f_res) mutable { try { f_res.get(); // force excepion if one return std::move(result); @@ -540,34 +541,6 @@ public: }); } - template - future finally(Func&& func, std::enable_if_t>::value, void*> = nullptr) noexcept { - promise pr; - auto f = pr.get_future(); - if (state()->available()) { - try { - func(); - } catch (...) { - pr.set_exception(std::current_exception()); - return f; - } - state()->forward_to(pr); - return f; - } - _promise->schedule([pr = std::move(pr), func = std::forward(func)] (auto&& state) mutable { - try { - func(); - } catch (...) { - pr.set_exception(std::current_exception()); - return; - } - state.forward_to(pr); - }); - _promise->_future = nullptr; - _promise = nullptr; - return f; - } - future<> or_terminate() noexcept { return then_wrapped([] (auto&& f) { try { From 0537a8ffe563a2625c25e79235083d59c784c73e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 14:48:31 +0200 Subject: [PATCH 08/16] linecount: don't try to create the file. It's read-only. --- tests/linecount.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/linecount.cc b/tests/linecount.cc index 898e0ffddc..11189548bf 100644 --- a/tests/linecount.cc +++ b/tests/linecount.cc @@ -54,7 +54,7 @@ int main(int ac, char** av) { }); app.run(ac, av, [&app] { auto fname = app.configuration()["file"].as(); - engine().open_file_dma(fname, open_flags::ro | open_flags::create).then([] (file f) { + engine().open_file_dma(fname, open_flags::ro).then([] (file f) { auto r = make_shared(std::move(f)); r->is.consume(*r).then([r] { print("%d lines\n", r->count); From d3acb5acc29d8e91edccfdde5dda48d45ac6cd9b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 14:48:52 +0200 Subject: [PATCH 09/16] linecount: better error handling --- tests/linecount.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/linecount.cc b/tests/linecount.cc index 11189548bf..e420d221cb 100644 --- a/tests/linecount.cc +++ b/tests/linecount.cc @@ -58,8 +58,18 @@ int main(int ac, char** av) { auto r = make_shared(std::move(f)); r->is.consume(*r).then([r] { print("%d lines\n", r->count); - engine().exit(0); }); + }).then_wrapped([] (future<> f) { + try { + f.get(); + engine().exit(0); + } catch (std::exception& ex) { + std::cout << ex.what() << "\n"; + engine().exit(1); + } catch (...) { + std::cout << "unknown exception\n"; + engine().exit(0); + } }); }); } From 1f8e0dbbab82ea5a4d5688634e35ae502877563a Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Wed, 11 Mar 2015 13:52:30 +0200 Subject: [PATCH 10/16] unaligned: new header file for unaligned access This patch adds a new header file, "core/unaligned.hh", which defines a new operation, unaligned_cast(p). This works exctly like reinterpret_cast(p) except it is safe to use even when the address of p is not a multiple of alignof(T). A long comment in the header file explains why this unaligned_cast<> is necessary on some esoteric architectures and to quiet gcc's -fsanitize=alignment. The header file also defines a new template for holding an unaligned version of type - unaligned. unaligned is almost identical to our existing net::packed<>, so the next patch will implement net::packed in terms of unaligned<>. The unaligned_cast<> and unaligned<> templates are of course generally useful outside the network code, which is why I wanted them out of the networking header files and namespace. Signed-off-by: Nadav Har'El --- core/unaligned.hh | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 core/unaligned.hh diff --git a/core/unaligned.hh b/core/unaligned.hh new file mode 100644 index 0000000000..7a21820299 --- /dev/null +++ b/core/unaligned.hh @@ -0,0 +1,66 @@ +/* + * 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 + +// The following unaligned_cast(p) is a portable replacement for +// reinterpret_cast(p) which should be used every time address p +// is not guaranteed to be properly aligned to alignof(T). +// +// On architectures like x86 and ARM, where unaligned access is allowed, +// unaligned_cast will behave the same as reinterpret_cast and will generate +// the same code. +// +// Certain architectures (e.g., MIPS) make it extremely slow or outright +// forbidden to use ordinary machine instructions on a primitive type at an +// unaligned addresses - e.g., access a uint32_t at an address which is not +// a multiple of 4. Gcc's "undefined behavior sanitizer" (enabled in our debug +// build) also catches such unaligned accesses and reports them as errors, +// even when running on x86. +// +// Therefore, reinterpret_cast on an address which is not guaranteed +// to be a multiple of 4 may generate extremely slow code or runtime errors, +// and must be avoided. The compiler needs to be told about the unaligned +// access, so it can generate reasonably-efficient code for the access +// (in MIPS, this means generating two instructions "lwl" and "lwr", instead +// of the one instruction "lw" which faults on unaligned/ access). The way to +// tell the compiler this is with __attribute__((packed)). This will also +// cause the sanitizer not to generate runtime alignment checks for this +// access. + +template +struct unaligned { + T raw; + unaligned() = default; + unaligned(T x) : raw(x) {} + unaligned& operator=(const T& x) { raw = x; return *this; } + operator T() const { return raw; } +} __attribute__((packed)); + +template +inline auto unaligned_cast(F* p) { + return reinterpret_cast>*>(p); +} + +template +inline auto unaligned_cast(const F* p) { + return reinterpret_cast>*>(p); +} From d1601b46f26af6d42c89a3ed6ce5940a865758b4 Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Wed, 11 Mar 2015 13:52:31 +0200 Subject: [PATCH 11/16] net: implement net::packed<> in terms of unaligned<> The previous patch moved most of the functionality of net::packed<> into a new template unaligned<> (in core/unaligned.hh). So in this patch we implement net::packed<> in terms of unaligned<>. The former is basically the same as the latter, with the addition of the "adjust_endianness" feature that the networking code expects. Signed-off-by: Nadav Har'El --- net/byteorder.hh | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/net/byteorder.hh b/net/byteorder.hh index c4e83f1f63..a3f8c40406 100644 --- a/net/byteorder.hh +++ b/net/byteorder.hh @@ -26,6 +26,8 @@ #include #include +#include "core/unaligned.hh" + inline uint64_t ntohq(uint64_t v) { return __builtin_bswap64(v); } @@ -56,25 +58,12 @@ inline int32_t hton(int32_t x) { return htonl(x); } inline int64_t ntoh(int64_t x) { return ntohq(x); } inline int64_t hton(int64_t x) { return htonq(x); } - -// Wrapper around a primitive type to provide an unaligned version. -// This is because gcc (correctly) doesn't allow binding an unaligned -// scalar variable to a reference, and (unfortunately) doesn't allow -// specifying unaligned references. -// -// So, packed& is our way of passing a reference (or pointer) -// to a uint32_t around, without losing the knowledge about its alignment -// or lack thereof. +// Define net::packed<> using unaligned<> from unaligned.hh. template -struct packed { - T raw; - packed() = default; - packed(T x) : raw(x) {} - packed& operator=(const T& x) { raw = x; return *this; } - operator T() const { return raw; } - +struct packed : public unaligned { + using unaligned::unaligned; // inherit constructors template - void adjust_endianness(Adjuster a) { a(raw); } + void adjust_endianness(Adjuster a) { a(this->raw); } } __attribute__((packed)); template From 3578d3d01626cf113935b169debf2084bed72052 Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Sun, 15 Mar 2015 13:40:40 +0200 Subject: [PATCH 12/16] build: make it easy to compile a Seastar-based project This patch makes compiling a file "hello.cc" using seastar as simple as: g++ `pkg-config --cflags --libs build/release/seastar.pc` hello.cc Our current build system makes it very hard for users to build a project *using* Seastar - basically requiring them to integrate their project into the Seastar tree and its Makefile into our "ninja" framework. This patch simplifies things considerably by doing two things: First it builds an archive of all Seastar objects - build/$mode/libseastar.a. But this in itself is not enough - the user wouldn't know how to use it (currently, -Wl,--whole-archive is needed, unfortunately, because of reliance of C++ static constructors), and will also need a long list of other libraries, as wall as various definitions and include paths during compilation. The solution is to use pkg-config, which has become the de-facto standard method on Linux for makefiles to figure out how to compile with a certain library. With this patch, someone can do this for example, to compile tests/fileiotests.cc: g++ `pkg-config --cflags --libs build/release/seastar.pc` tests/fileiotest.cc Note how we have a different ".pc" file for each mode, with the appropriate compile and link flags. A more eleborate example with separate compile and link stages will use "pkg-config --cflags" on the compilation stage, and "--libs" on the linking stage. Eventually, we should have a "ninja install", which will install libseastar.a and seastar.pc to their system-wide default location, and then the above command line will become as simple as: g++ `pkg-config --cflags --libs seastar` tests/fileiotest.cc Signed-off-by: Nadav Har'El --- configure.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/configure.py b/configure.py index 7966407702..bf768d7440 100755 --- a/configure.py +++ b/configure.py @@ -116,7 +116,7 @@ apps = [ 'apps/memcached/memcached', ] -all_artifacts = apps + tests +all_artifacts = apps + tests + ['libseastar.a', 'seastar.pc'] arg_parser = argparse.ArgumentParser('Configure seastar') arg_parser.add_argument('--static', dest = 'static', action = 'store_const', default = '', @@ -203,6 +203,7 @@ memcache_base = [ ] + libnet + core deps = { + 'libseastar.a' : core + libnet, 'apps/seastar/seastar': ['apps/seastar/main.cc'] + core, 'tests/test-reactor': ['tests/test-reactor.cc'] + core, 'apps/httpd/httpd': ['http/common.cc', 'http/routes.cc', 'json/json_elements.cc', 'json/formatter.cc', 'http/matcher.cc', 'http/mime_types.cc', 'http/httpd.cc', 'http/reply.cc', 'http/request_parser.rl', 'apps/httpd/main.cc'] + libnet + core, @@ -331,17 +332,37 @@ with open(buildfile, 'w') as f: command = $cxx $cxxflags_{mode} $ldflags -o $out $in $libs $libs_{mode} description = LINK $out pool = link_pool + rule ar.{mode} + command = rm -f $out; ar cr $out $in; ranlib $out + description = AR $out ''').format(mode = mode, **modeval)) f.write('build {mode}: phony {artifacts}\n'.format(mode = mode, artifacts = str.join(' ', ('$builddir/' + mode + '/' + x for x in build_artifacts)))) compiles = {} ragels = {} for binary in build_artifacts: + if binary.endswith('.pc'): + # Create the pkg-config file now, no nead to wait until build + with open('build/' + mode + '/' + binary, 'w') as pc: + vars = modeval.copy() + vars.update(globals()) + pc.write(textwrap.dedent('''\ + Name: Seastar + URL: http://seastar-project.org/ + Description: Advanced C++ framework for high-performance server applications on modern hardware. + Version: 1.0 + Libs: -L{srcdir}/{builddir} -Wl,--whole-archive -lseastar -Wl,--no-whole-archive {dbgflag} -Wl,--no-as-needed {static} {pie} -fvisibility=hidden -pthread {user_ldflags} {libs} {sanitize_libs} + Cflags: -std=gnu++1y {dbgflag} {fpie} -Wall -Werror -fvisibility=hidden -pthread -I{srcdir} -I{srcdir}/{builddir}/gen {user_cflags} {warnings} {defines} {sanitize} {opt} + ''').format(builddir = 'build/' + mode, srcdir = os.getcwd(), **vars)) + continue srcs = deps[binary] objs = ['$builddir/' + mode + '/' + src.replace('.cc', '.o') for src in srcs if src.endswith('.cc')] - f.write('build $builddir/{}/{}: link.{} {}\n'.format(mode, binary, mode, str.join(' ', objs))) + if binary.endswith('.a'): + f.write('build $builddir/{}/{}: ar.{} {}\n'.format(mode, binary, mode, str.join(' ', objs))) + else: + f.write('build $builddir/{}/{}: link.{} {}\n'.format(mode, binary, mode, str.join(' ', objs))) for src in srcs: if src.endswith('.cc'): obj = '$builddir/' + mode + '/' + src.replace('.cc', '.o') From f8c69904cdef4ae62e94ffab4edd932043bd957d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 16:16:41 +0200 Subject: [PATCH 13/16] build: fix seastar.pc generation Need to ensure the directory is there first. --- configure.py | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.py b/configure.py index bf768d7440..104e4c1202 100755 --- a/configure.py +++ b/configure.py @@ -343,6 +343,7 @@ with open(buildfile, 'w') as f: for binary in build_artifacts: if binary.endswith('.pc'): # Create the pkg-config file now, no nead to wait until build + os.makedirs('build/' + mode) with open('build/' + mode + '/' + binary, 'w') as pc: vars = modeval.copy() vars.update(globals()) From 25c37c92f5fdb15230bda0d0f43c49479a03f977 Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Sun, 15 Mar 2015 16:05:07 +0200 Subject: [PATCH 14/16] core: fix engine_exit() engine_exit() without a parameter is meant to do engine().exit(0). We do this, but forget to return from this function, so after calling engine().exit(0), it continued on and crashed. Signed-off-by: Nadav Har'El --- core/reactor.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/core/reactor.cc b/core/reactor.cc index 1d1aeb9d51..7842647993 100644 --- a/core/reactor.cc +++ b/core/reactor.cc @@ -1563,6 +1563,7 @@ reactor_backend_osv::enable_timer(clock_type::time_point when) { void engine_exit(std::exception_ptr eptr) { if (!eptr) { engine().exit(0); + return; } #ifndef __GNUC__ std::cerr << "Exiting on unhandled exception.\n"; From 24bc1b412651dfa760eb855e323b038083b587ea Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 18:13:29 +0200 Subject: [PATCH 15/16] build: improve seastar.pc generation Generate at build time, so it gets rebuilt even if build/ is wiped out. --- configure.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/configure.py b/configure.py index 104e4c1202..f447dc725e 100755 --- a/configure.py +++ b/configure.py @@ -204,6 +204,7 @@ memcache_base = [ deps = { 'libseastar.a' : core + libnet, + 'seastar.pc': [], 'apps/seastar/seastar': ['apps/seastar/main.cc'] + core, 'tests/test-reactor': ['tests/test-reactor.cc'] + core, 'apps/httpd/httpd': ['http/common.cc', 'http/routes.cc', 'json/json_elements.cc', 'json/formatter.cc', 'http/matcher.cc', 'http/mime_types.cc', 'http/httpd.cc', 'http/reply.cc', 'http/request_parser.rl', 'apps/httpd/main.cc'] + libnet + core, @@ -314,6 +315,9 @@ with open(buildfile, 'w') as f: rule ragel command = ragel -G2 -o $out $in description = RAGEL $out + rule gen + command = echo -e $text > $out + description = GEN $out ''').format(**globals())) for mode in build_modes: modeval = modes[mode] @@ -341,26 +345,23 @@ with open(buildfile, 'w') as f: compiles = {} ragels = {} for binary in build_artifacts: + srcs = deps[binary] + objs = ['$builddir/' + mode + '/' + src.replace('.cc', '.o') + for src in srcs + if src.endswith('.cc')] if binary.endswith('.pc'): - # Create the pkg-config file now, no nead to wait until build - os.makedirs('build/' + mode) - with open('build/' + mode + '/' + binary, 'w') as pc: - vars = modeval.copy() - vars.update(globals()) - pc.write(textwrap.dedent('''\ + vars = modeval.copy() + vars.update(globals()) + pc = textwrap.dedent('''\ Name: Seastar URL: http://seastar-project.org/ Description: Advanced C++ framework for high-performance server applications on modern hardware. Version: 1.0 Libs: -L{srcdir}/{builddir} -Wl,--whole-archive -lseastar -Wl,--no-whole-archive {dbgflag} -Wl,--no-as-needed {static} {pie} -fvisibility=hidden -pthread {user_ldflags} {libs} {sanitize_libs} Cflags: -std=gnu++1y {dbgflag} {fpie} -Wall -Werror -fvisibility=hidden -pthread -I{srcdir} -I{srcdir}/{builddir}/gen {user_cflags} {warnings} {defines} {sanitize} {opt} - ''').format(builddir = 'build/' + mode, srcdir = os.getcwd(), **vars)) - continue - srcs = deps[binary] - objs = ['$builddir/' + mode + '/' + src.replace('.cc', '.o') - for src in srcs - if src.endswith('.cc')] - if binary.endswith('.a'): + ''').format(builddir = 'build/' + mode, srcdir = os.getcwd(), **vars) + f.write('build $builddir/{}/{}: gen\n text = {}\n'.format(mode, binary, repr(pc))) + elif binary.endswith('.a'): f.write('build $builddir/{}/{}: ar.{} {}\n'.format(mode, binary, mode, str.join(' ', objs))) else: f.write('build $builddir/{}/{}: link.{} {}\n'.format(mode, binary, mode, str.join(' ', objs))) From d2c0e485f8d9b24bc8577329a865eb53dee091f6 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 15 Mar 2015 20:18:17 +0200 Subject: [PATCH 16/16] posix: fix posix::recv return Shuts up warning in gcc 5, and is aligned with the other methods. --- core/posix.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/posix.hh b/core/posix.hh index 7044ca7dde..788b3835aa 100644 --- a/core/posix.hh +++ b/core/posix.hh @@ -189,7 +189,7 @@ public: return {}; } throw_system_error_on(r == -1); - return { r }; + return { ssize_t(r) }; } boost::optional recvmsg(msghdr* mh, int flags) { auto r = ::recvmsg(_fd, mh, flags);