/
Neitrinok
/
seastar
Обзор
Документация
Войти
/
Neitrinok
/
seastar
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/testing/test_runner.cc
173 строки
6 KB
Tyler Rockwood
treewide: replace assert with SEASTAR_ASSERT
18 фев 2025, 01:25
18 фев 2025, 01:25
7a91062
Код
Авторство
О чём код?
/* * 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. */ #include <iostream> #include <seastar/core/app-template.hh> #include <seastar/core/reactor.hh> #include <seastar/core/posix.hh> #include <seastar/testing/random.hh> #include <seastar/testing/test_runner.hh> #include <seastar/util/assert.hh> namespace seastar { namespace testing { static test_runner instance; struct stop_execution : public std::exception {}; test_runner::~test_runner() { finalize(); } bool test_runner::start(int ac, char** av) { bool expected = false; if (!_started.compare_exchange_strong(expected, true, std::memory_order_acquire)) { return true; } // Don't interfere with seastar signal handling sigset_t mask; sigfillset(&mask); for (auto sig : { SIGSEGV }) { sigdelset(&mask, sig); } auto r = ::pthread_sigmask(SIG_BLOCK, &mask, NULL); if (r) { std::cerr << "Error blocking signals. Aborting." << std::endl; abort(); } _st_args = std::make_unique<start_thread_args>(ac, av); return true; } int test_runner::start_thread(int ac, char** av) { auto init_outcome = std::make_shared<exchanger<int>>(); namespace bpo = boost::program_options; _thread = std::make_unique<posix_thread>([this, ac, av, init_outcome]() mutable { app_template app; app.add_options() ("random-seed", bpo::value<unsigned>(), "Random number generator seed") ("fail-on-abandoned-failed-futures", bpo::value<bool>()->default_value(true), "Fail the test if there are any abandoned failed futures"); // We guarantee that only one thread is running. // We only read this after that one thread is joined, so this is safe. _exit_code = app.run(ac, av, [this, &app, init_outcome = init_outcome.get()] { init_outcome->give(0); auto init = [&app] { auto conf_seed = app.configuration()["random-seed"]; auto seed = conf_seed.empty() ? std::random_device()(): conf_seed.as<unsigned>(); std::cout << "random-seed=" << seed << std::endl; return smp::invoke_on_all([seed] { auto local_seed = seed + this_shard_id(); local_random_engine.seed(local_seed); }); }; return init().then([this] { return do_until([this] { return _done; }, [this] { // this will block the reactor briefly, but we don't care try { auto func = _task.take(); return func(); } catch (const stop_execution&) { _done = true; return make_ready_future<>(); } }).or_terminate(); }).then([&app] { if (engine().abandoned_failed_futures()) { std::cerr << "*** " << engine().abandoned_failed_futures() << " abandoned failed future(s) detected" << std::endl; if (app.configuration()["fail-on-abandoned-failed-futures"].as<bool>()) { std::cerr << "Failing the test because fail was requested by --fail-on-abandoned-failed-futures" << std::endl; return 3; } } return 0; }); }); init_outcome->give(_exit_code); }); return init_outcome->take(); } void test_runner::run_sync(std::function<future<>()> task) { if (_st_args) { start_thread_args sa = *_st_args; _st_args.reset(); if (int start_status = start_thread(sa.ac, sa.av); start_status != 0) { // something bad happened when starting the reactor or app, and // the _thread has exited before taking any task. but we need to // move on. let's report this bad news with exit code _exit_code = start_status; } } if (_exit_code != 0) { // we failed to start the worker reactor, so we cannot send the task to // it. return; } exchanger<std::exception_ptr> e; _task.give([task = std::move(task), &e] { SEASTAR_ASSERT(engine_is_ready()); try { return task().then_wrapped([&e](auto&& f) { try { f.get(); e.give({}); } catch (...) { e.give(std::current_exception()); } }); } catch (...) { e.give(std::current_exception()); return make_ready_future<>(); } }); auto maybe_exception = e.take(); if (maybe_exception) { std::rethrow_exception(maybe_exception); } } int test_runner::finalize() { if (_thread) { _task.interrupt(stop_execution()); _thread->join(); _thread = nullptr; } return _exit_code; } test_runner& global_test_runner() { return instance; } } }