diff --git a/repos/base/run/registry.run b/repos/base/run/registry.run new file mode 100644 index 0000000000..67a1d8f939 --- /dev/null +++ b/repos/base/run/registry.run @@ -0,0 +1,27 @@ +build "core init test/registry" + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + +} + +build_boot_image "core ld.lib.so init test-registry" + +append qemu_args "-nographic " + +run_genode_until ".*child \"test-registry\" exited with exit value 0.*\n" 20 diff --git a/repos/base/src/lib/base/registry.cc b/repos/base/src/lib/base/registry.cc index 07ef5a2b44..3ac68c64bf 100644 --- a/repos/base/src/lib/base/registry.cc +++ b/repos/base/src/lib/base/registry.cc @@ -134,7 +134,21 @@ void Registry_base::_for_each(Untyped_functor &functor) try { functor.call(e->_obj); } /* propagate exceptions while keeping registry consistent */ - catch (...) { at = _processed(notify, processed, *e, at); throw; } + catch (...) { + + /* handle current element */ + at = _processed(notify, processed, *e, at); + + /* handle the remaining elements without invoking the functor */ + while (Element *e = _elements.first()) { + _elements.remove(e); + at = _processed(notify, processed, *e, at); + }; + _elements = processed; + + /* propagate exception to caller */ + throw; + } at = _processed(notify, processed, *e, at); } diff --git a/repos/base/src/test/registry/main.cc b/repos/base/src/test/registry/main.cc new file mode 100644 index 0000000000..502637bcea --- /dev/null +++ b/repos/base/src/test/registry/main.cc @@ -0,0 +1,79 @@ +/* + * \brief Test for 'Registry' data structure + * \author Norman Feske + * \date 2018-08-21 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include + + +/* + * Check that an exception that occurs during the iteration over + * registry items does not affect the registry content. + */ +static void test_exception_during_for_each() +{ + using namespace Genode; + + struct Item : Interface + { + typedef String<10> Name; + Name const name; + + Item(Name const &name) : name(name) { } + + class Invalid : Exception { }; + + void visit() + { + if (name == "second") + throw Invalid(); + } + }; + + Registry > items { }; + + Registered first (items, "first"); + Registered second(items, "second"); + Registered third (items, "third"); + + auto num_items = [&] () { + unsigned cnt = 0; + items.for_each([&] (Item &) { cnt++; }); + return cnt; + }; + + unsigned const num_items_before_exception = num_items(); + + try { + items.for_each([&] (Item &item) { + /* second item throws an exception */ + item.visit(); + }); + } + catch (Item::Invalid) { log("exception occurred (expected)"); }; + + unsigned const num_items_after_exception = num_items(); + + struct Failed : Exception { }; + if (num_items_before_exception != num_items_after_exception) + throw Failed(); +} + + +void Component::construct(Genode::Env &env) +{ + test_exception_during_for_each(); + + env.parent().exit(0); +} diff --git a/repos/base/src/test/registry/target.mk b/repos/base/src/test/registry/target.mk new file mode 100644 index 0000000000..7eb11de97e --- /dev/null +++ b/repos/base/src/test/registry/target.mk @@ -0,0 +1,3 @@ +TARGET = test-registry +SRC_CC = main.cc +LIBS += base diff --git a/tool/autopilot.list b/tool/autopilot.list index c84f1b52f9..4a603e6be3 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -71,6 +71,7 @@ pthread python ram_fs_chunk reconstructible +registry report_rom resource_request resource_yield