diff --git a/repos/base/include/base/trace/types.h b/repos/base/include/base/trace/types.h index 9da53531d9..b68e66c750 100644 --- a/repos/base/include/base/trace/types.h +++ b/repos/base/include/base/trace/types.h @@ -23,18 +23,12 @@ namespace Genode { namespace Trace { - /********************* - ** Exception types ** - *********************/ + using Thread_name = String<32>; - struct Policy_too_large : Exception { }; - struct Nonexistent_subject : Exception { }; - struct Source_is_dead : Exception { }; - struct Nonexistent_policy : Exception { }; - struct Traced_by_other_session : Exception { }; - struct Subject_not_traced : Exception { }; - - typedef String<32> Thread_name; + struct Num_subjects { unsigned value; }; + struct Policy_size { size_t num_bytes; }; + struct Buffer_size { size_t num_bytes; }; + struct Trace_ok { }; struct Policy_id; struct Subject_id; @@ -48,10 +42,7 @@ namespace Genode { namespace Trace { */ struct Genode::Trace::Policy_id { - unsigned id; - - Policy_id() : id(0) { } - Policy_id(unsigned id) : id(id) { } + unsigned id { }; bool operator == (Policy_id const &other) const { return id == other.id; } }; @@ -62,10 +53,7 @@ struct Genode::Trace::Policy_id */ struct Genode::Trace::Subject_id { - unsigned id; - - Subject_id() : id(0) { } - Subject_id(unsigned id) : id(id) { } + unsigned id { }; bool operator == (Subject_id const &other) const { return id == other.id; } }; diff --git a/repos/base/include/trace_session/client.h b/repos/base/include/trace_session/client.h deleted file mode 100644 index 12cf2c4046..0000000000 --- a/repos/base/include/trace_session/client.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * \brief Client-side TRACE session interface - * \author Norman Feske - * \date 2013-08-12 - */ - -/* - * Copyright (C) 2013-2017 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. - */ - -#ifndef _INCLUDE__TRACE_SESSION__CLIENT_H_ -#define _INCLUDE__TRACE_SESSION__CLIENT_H_ - -#include -#include -#include - -namespace Genode { namespace Trace { struct Session_client; } } - - -struct Genode::Trace::Session_client : Genode::Rpc_client -{ - private: - - /** - * Shared-memory buffer used for carrying the payload of the - * 'subjects()' RPC function. - */ - class Argument_buffer - { - private: - - /* - * Noncopyable - */ - Argument_buffer(Argument_buffer const &); - Argument_buffer &operator = (Argument_buffer const &); - - public: - - Region_map &rm; - char *base; - size_t size; - - Argument_buffer(Region_map &rm, Dataspace_capability ds) - : - rm(rm), - base(rm.attach(ds)), - size(ds.call()) - { } - - ~Argument_buffer() - { - rm.detach(base); - } - }; - - Argument_buffer _argument_buffer; - - public: - - /** - * Constructor - */ - explicit Session_client(Region_map &rm, Capability session) - : - Rpc_client(session), - _argument_buffer(rm, call()) - { } - - /** - * Retrieve subject directory - * - * \throw Out_of_ram - * \throw Out_of_caps - */ - virtual size_t subjects(Subject_id *dst, size_t dst_len) - { - size_t const num_subjects = min(call(), dst_len); - - memcpy(dst, _argument_buffer.base, num_subjects*sizeof(Subject_id)); - - return num_subjects; - } - - struct For_each_subject_info_result { size_t count; size_t limit; }; - - For_each_subject_info_result for_each_subject_info(auto const &fn) - { - size_t const num_subjects = call(); - size_t const max_subjects = _argument_buffer.size / (sizeof(Subject_info) + sizeof(Subject_id)); - - Subject_info * const infos = reinterpret_cast(_argument_buffer.base); - Subject_id * const ids = reinterpret_cast(infos + max_subjects); - - for (unsigned i = 0; i < num_subjects; i++) { - fn(ids[i], infos[i]); - } - - return { .count = num_subjects, .limit = max_subjects }; - } - - Policy_id alloc_policy(size_t size) override { - return call(size); } - - Dataspace_capability policy(Policy_id policy_id) override { - return call(policy_id); } - - void unload_policy(Policy_id policy_id) override { - call(policy_id); } - - void trace(Subject_id s, Policy_id p, size_t buffer_size) override { - call(s, p, buffer_size); } - - void pause(Subject_id subject) override { - call(subject); } - - void resume(Subject_id subject) override { - call(subject); } - - Dataspace_capability buffer(Subject_id subject) override { - return call(subject); } - - void free(Subject_id subject) override { - call(subject); } -}; - -#endif /* _INCLUDE__TRACE_SESSION__CLIENT_H_ */ diff --git a/repos/base/include/trace_session/connection.h b/repos/base/include/trace_session/connection.h index c919d476d8..6f5c07fce5 100644 --- a/repos/base/include/trace_session/connection.h +++ b/repos/base/include/trace_session/connection.h @@ -15,18 +15,36 @@ #define _INCLUDE__TRACE_SESSION__CONNECTION_H_ #include -#include +#include +#include #include +#include namespace Genode { namespace Trace { struct Connection; } } struct Genode::Trace::Connection : Genode::Connection, - Genode::Trace::Session_client + Genode::Rpc_client { + /** + * Shared-memory buffer used for carrying the payload of subject infos + */ + Attached_dataspace _argument_buffer; + + size_t const _max_arg_size; + + template auto _retry(auto const &fn) -> decltype(fn()) { - return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, fn); + for (;;) { + bool retry = false; + auto const result = fn(); + if (result == ERROR::OUT_OF_CAPS) { upgrade_caps(2); retry = true; } + if (result == ERROR::OUT_OF_RAM) { upgrade_ram(8*1024); retry = true; } + + if (!retry) + return result; + } } /** @@ -39,31 +57,141 @@ struct Genode::Trace::Connection : Genode::Connection, : Genode::Connection(env, Label(), Ram_quota { 10*1024 + ram_quota }, Args("arg_buffer_size=", arg_buffer_size)), - Session_client(env.rm(), cap()) + Genode::Rpc_client(cap()), + _argument_buffer(env.rm(), call()), + _max_arg_size(arg_buffer_size) { } - Policy_id alloc_policy(size_t size) override + enum class Alloc_policy_error { INVALID }; + + using Alloc_policy_result = Attempt; + + /** + * Allocate policy-module backing store + */ + Alloc_policy_result alloc_policy(Policy_size size) { - return _retry([&] () { - return Session_client::alloc_policy(size); }); + if (size.num_bytes > _max_arg_size) + return Alloc_policy_error::INVALID; + + Alloc_policy_rpc_result const result = _retry([&] { + return call(size); }); + + return result.convert( + [&] (Policy_id const id) { return id; }, + [&] (Alloc_policy_rpc_error) { return Alloc_policy_error::INVALID; }); } - void trace(Subject_id s, Policy_id p, size_t buffer_size) override + /** + * Request policy-module backing store + * + * \return dataspace capability, or invalid capability if ID does not + * refer to a known policy + */ + Dataspace_capability policy(Policy_id id) { return call(id); } + + /** + * Remove a policy module from the TRACE service + */ + void unload_policy(Policy_id id) { call(id); } + + enum class Trace_error { FOREIGN, SOURCE_IS_DEAD, INVALID_SUBJECT, INVALID_POLICY }; + using Trace_result = Attempt; + + /** + * Start tracing of a subject + */ + Trace_result trace(Subject_id const s, Policy_id const p, Buffer_size const size) { - _retry([&] () { Session_client::trace(s, p, buffer_size); }); + Trace_rpc_result const rpc_result = + _retry([&] () -> Trace_rpc_result { + return call(s, p, size); }); + + return rpc_result.convert( + [&] (Trace_ok ok) { return ok; }, + [&] (Trace_rpc_error e) { + switch (e) { + case Trace_rpc_error::OUT_OF_RAM: /* cannot occur, handled by '_retry' above */ + case Trace_rpc_error::OUT_OF_CAPS: break; + case Trace_rpc_error::FOREIGN: return Trace_error::FOREIGN; + case Trace_rpc_error::SOURCE_IS_DEAD: return Trace_error::SOURCE_IS_DEAD; + case Trace_rpc_error::INVALID_SUBJECT: return Trace_error::INVALID_SUBJECT; + case Trace_rpc_error::INVALID_POLICY: break; + } + return Trace_error::INVALID_POLICY; + }); } - size_t subjects(Subject_id *dst, size_t dst_len) override + /** + * Retrieve subject directory + */ + Num_subjects subjects(Subject_id * const dst, Num_subjects const dst_num_subjects) { - return _retry([&] () { - return Session_client::subjects(dst, dst_len); }); + Subjects_rpc_result const result = _retry([&] { + return call(); }); + + return result.convert( + + [&] (Num_subjects const num_subjects) { + auto const n = min(num_subjects.value, dst_num_subjects.value); + memcpy(dst, _argument_buffer.local_addr(), n*sizeof(Subject_id)); + return Num_subjects { n }; + }, + + [&] (Alloc_rpc_error) { return Num_subjects { 0 }; }); } + struct For_each_subject_info_result { unsigned count; unsigned limit; }; + + /** + * Call 'fn' for each trace subject with 'Subject_info' as argument + */ For_each_subject_info_result for_each_subject_info(auto const &fn) { - return _retry([&] () { - return Session_client::for_each_subject_info(fn); }); + Infos_rpc_result const result = _retry([&] { + return call(); }); + + return result.convert( + [&] (Num_subjects const n) -> For_each_subject_info_result { + + size_t const subject_bytes = sizeof(Subject_info) + sizeof(Subject_id); + + unsigned const max_subjects = unsigned(_argument_buffer.size() / subject_bytes); + + Subject_info * const infos = _argument_buffer.local_addr(); + Subject_id * const ids = reinterpret_cast(infos + max_subjects); + + for (unsigned i = 0; i < n.value; i++) + fn(ids[i], infos[i]); + + return { .count = n.value, .limit = max_subjects }; + }, + + [&] (Alloc_rpc_error) { return For_each_subject_info_result { }; }); } + + /** + * Release subject and free buffers + * + * If the source still exists, the buffers are freed but the subject + * stays intact. + */ + void free(Subject_id id) { call(id); } + + /** + * Pause generation of tracing data + */ + void pause(Subject_id id) { call(id); } + + /** + * Resume generation of tracing data + */ + void resume(Subject_id id) { call(id); } + + /** + * Obtain trace buffer of given subject + */ + Dataspace_capability buffer(Subject_id id) { return call(id); } }; #endif /* _INCLUDE__TRACE_SESSION__CONNECTION_H_ */ diff --git a/repos/base/include/trace_session/trace_session.h b/repos/base/include/trace_session/trace_session.h index 28dfc2aad5..8b8cd4bddb 100644 --- a/repos/base/include/trace_session/trace_session.h +++ b/repos/base/include/trace_session/trace_session.h @@ -14,7 +14,7 @@ #ifndef _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ #define _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ -#include +#include #include #include #include @@ -31,69 +31,17 @@ struct Genode::Trace::Session : Genode::Session enum { CAP_QUOTA = 6 }; - /** - * Allocate policy-module backing store - * - * \throw Out_of_ram - * \throw Out_of_caps - */ - virtual Policy_id alloc_policy(size_t size) = 0; + enum class Alloc_rpc_error { OUT_OF_RAM, OUT_OF_CAPS }; + enum class Alloc_policy_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID }; + enum class Trace_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, FOREIGN, + SOURCE_IS_DEAD, INVALID_SUBJECT, + INVALID_POLICY }; - /** - * Request policy-module backing store - * - * \throw Nonexistent_policy - */ - virtual Dataspace_capability policy(Policy_id) = 0; + using Alloc_policy_rpc_result = Attempt; + using Subjects_rpc_result = Attempt; + using Infos_rpc_result = Attempt; + using Trace_rpc_result = Attempt; - /** - * Remove a policy module from the TRACE service - */ - virtual void unload_policy(Policy_id) = 0; - - /** - * Start tracing of a subject - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Source_is_dead - * \throw Nonexistent_policy - * \throw Nonexistent_subject - * \throw Traced_by_other_session - */ - virtual void trace(Subject_id, Policy_id, size_t buffer_size) = 0; - - /** - * Pause generation of tracing data - * - * \throw Nonexistent_subject - */ - virtual void pause(Subject_id) = 0; - - /** - * Resume generation of tracing data - * - * \throw Nonexistent_subject - * \throw Source_is_dead - */ - virtual void resume(Subject_id) = 0; - - /** - * Obtain trace buffer of given subject - * - * \throw Nonexistent_subject - */ - virtual Dataspace_capability buffer(Subject_id) = 0; - - /** - * Release subject and free buffers - * - * If the source still exists, the buffers are freed but the subject - * stays intact. - * - * \throw Nonexistent_subject - */ - virtual void free(Subject_id) = 0; virtual ~Session() { } @@ -103,34 +51,16 @@ struct Genode::Trace::Session : Genode::Session *********************/ GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); - GENODE_RPC_THROW(Rpc_alloc_policy, Policy_id, alloc_policy, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), - size_t); - GENODE_RPC_THROW(Rpc_policy, Dataspace_capability, policy, - GENODE_TYPE_LIST(Nonexistent_policy), - Policy_id); - GENODE_RPC_THROW(Rpc_unload_policy, void, unload_policy, - GENODE_TYPE_LIST(Nonexistent_policy), Policy_id); - GENODE_RPC_THROW(Rpc_trace, void, trace, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, - Source_is_dead, Nonexistent_subject, - Nonexistent_policy, - Traced_by_other_session), - Subject_id, Policy_id, size_t); - GENODE_RPC_THROW(Rpc_pause, void, pause, - GENODE_TYPE_LIST(Nonexistent_subject), Subject_id); - GENODE_RPC_THROW(Rpc_resume, void, resume, - GENODE_TYPE_LIST(Nonexistent_subject, Source_is_dead), - Subject_id); - GENODE_RPC_THROW(Rpc_subjects, size_t, subjects, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); - GENODE_RPC_THROW(Rpc_subject_infos, size_t, subject_infos, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); - GENODE_RPC_THROW(Rpc_buffer, Dataspace_capability, buffer, - GENODE_TYPE_LIST(Nonexistent_subject, Subject_not_traced), - Subject_id); - GENODE_RPC_THROW(Rpc_free, void, free, - GENODE_TYPE_LIST(Nonexistent_subject), Subject_id); + GENODE_RPC(Rpc_alloc_policy, Alloc_policy_rpc_result, alloc_policy, Policy_size); + GENODE_RPC(Rpc_policy, Dataspace_capability, policy, Policy_id); + GENODE_RPC(Rpc_unload_policy, void, unload_policy, Policy_id); + GENODE_RPC(Rpc_trace, Trace_rpc_result, trace, Subject_id, Policy_id, Buffer_size); + GENODE_RPC(Rpc_pause, void, pause, Subject_id); + GENODE_RPC(Rpc_resume, void, resume, Subject_id); + GENODE_RPC(Rpc_subjects, Subjects_rpc_result, subjects); + GENODE_RPC(Rpc_subject_infos, Infos_rpc_result, subject_infos); + GENODE_RPC(Rpc_buffer, Dataspace_capability, buffer, Subject_id); + GENODE_RPC(Rpc_free, void, free, Subject_id); GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_alloc_policy, Rpc_policy, Rpc_unload_policy, Rpc_trace, Rpc_pause, diff --git a/repos/base/src/core/include/trace/policy_registry.h b/repos/base/src/core/include/trace/policy_registry.h index 8ac864646c..6c9882bbe7 100644 --- a/repos/base/src/core/include/trace/policy_registry.h +++ b/repos/base/src/core/include/trace/policy_registry.h @@ -41,7 +41,7 @@ class Core::Trace::Policy : public List::Element Allocator &_md_alloc; Policy_id const _id; Dataspace_capability _ds; - size_t const _size; + Policy_size const _size; /** * Constructor @@ -49,7 +49,7 @@ class Core::Trace::Policy : public List::Element * \param md_alloc allocator that holds the 'Policy' object */ Policy(Policy_owner const &owner, Policy_id const id, - Allocator &md_alloc, Dataspace_capability ds, size_t size) + Allocator &md_alloc, Dataspace_capability ds, Policy_size size) : _owner(owner), _md_alloc(md_alloc), _id(id), _ds(ds), _size(size) { } @@ -66,7 +66,7 @@ class Core::Trace::Policy : public List::Element public: Dataspace_capability dataspace() const { return _ds; } - size_t size() const { return _size; } + Policy_size size() const { return _size; } }; @@ -81,13 +81,12 @@ class Core::Trace::Policy_registry Mutex _mutex { }; List _policies { }; - Policy &_unsynchronized_lookup(Policy_owner const &owner, Policy_id id) + void _with_policy_unsynchronized(Policy_owner const &owner, + Policy_id const id, auto const &fn) { for (Policy *p = _policies.first(); p; p = p->next()) if (p->owned_by(owner) && p->has_id(id)) - return *p; - - throw Nonexistent_policy(); + fn(*p); } Policy *_any_policy_owned_by(Policy_owner const &owner) @@ -110,7 +109,7 @@ class Core::Trace::Policy_registry } void insert(Policy_owner const &owner, Policy_id const id, - Allocator &md_alloc, Dataspace_capability ds, size_t size) + Allocator &md_alloc, Dataspace_capability ds, Policy_size size) { Mutex::Guard guard(_mutex); @@ -143,18 +142,22 @@ class Core::Trace::Policy_registry } } - Dataspace_capability dataspace(Policy_owner &owner, Policy_id id) + void with_dataspace(Policy_owner &owner, Policy_id id, auto const &fn) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup(owner, id).dataspace(); + _with_policy_unsynchronized(owner, id, [&] (Policy &p) { + fn(p.dataspace()); }); } - size_t size(Policy_owner &owner, Policy_id id) + Policy_size size(Policy_owner &owner, Policy_id id) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup(owner, id).size(); + Policy_size result { 0 }; + _with_policy_unsynchronized(owner, id, [&] (Policy const &p) { + result = p.size(); }); + return result; } }; diff --git a/repos/base/src/core/include/trace/session_component.h b/repos/base/src/core/include/trace/session_component.h index 451de90a4b..0aa7301773 100644 --- a/repos/base/src/core/include/trace/session_component.h +++ b/repos/base/src/core/include/trace/session_component.h @@ -30,8 +30,7 @@ namespace Core { namespace Trace { class Session_component; } } class Core::Trace::Session_component : - public Session_object, + public Session_object, public Trace::Policy_owner { private: @@ -81,17 +80,16 @@ class Core::Trace::Session_component ***********************/ Dataspace_capability dataspace(); - size_t subjects(); - size_t subject_infos(); - - Policy_id alloc_policy(size_t) override; - Dataspace_capability policy(Policy_id) override; - void unload_policy(Policy_id) override; - void trace(Subject_id, Policy_id, size_t) override; - void pause(Subject_id) override; - void resume(Subject_id) override; - Dataspace_capability buffer(Subject_id) override; - void free(Subject_id) override; + Subjects_rpc_result subjects(); + Infos_rpc_result subject_infos(); + Alloc_policy_rpc_result alloc_policy(Policy_size); + Dataspace_capability policy(Policy_id); + void unload_policy(Policy_id); + Trace_rpc_result trace(Subject_id, Policy_id, Buffer_size); + void pause(Subject_id); + void resume(Subject_id); + Dataspace_capability buffer(Subject_id); + void free(Subject_id); }; #endif /* _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/trace/subject_registry.h b/repos/base/src/core/include/trace/subject_registry.h index 7774f79f40..08f2a6d06e 100644 --- a/repos/base/src/core/include/trace/subject_registry.h +++ b/repos/base/src/core/include/trace/subject_registry.h @@ -166,19 +166,6 @@ class Core::Trace::Subject return Subject_info::UNATTACHED; } - void _traceable_or_throw() - { - switch(_state()) { - case Subject_info::DEAD : throw Source_is_dead(); - case Subject_info::FOREIGN : throw Traced_by_other_session(); - case Subject_info::ERROR : throw Source_is_dead(); - case Subject_info::INVALID : throw Nonexistent_subject(); - case Subject_info::UNATTACHED : return; - case Subject_info::ATTACHED : return; - case Subject_info::TRACED : return; - } - } - public: /** @@ -206,31 +193,40 @@ class Core::Trace::Subject */ bool has_source_id(Source::Id id) const { return id.value == _source_id.value; } + enum class Trace_result { OK, OUT_OF_RAM, OUT_OF_CAPS, FOREIGN, + SOURCE_IS_DEAD, INVALID_SUBJECT }; + /** * Start tracing * * \param size trace buffer size - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Source_is_dead - * \throw Traced_by_other_session */ - void trace(Policy_id policy_id, Dataspace_capability policy_ds, - size_t policy_size, Ram_allocator &ram, - Region_map &local_rm, size_t size) + Trace_result trace(Policy_id policy_id, Dataspace_capability policy_ds, + Policy_size policy_size, Ram_allocator &ram, + Region_map &local_rm, Buffer_size size) { - /* check state and throw error in case subject is not traceable */ - _traceable_or_throw(); - - _buffer.setup(ram, size); /* may throw */ + /* check state and return error if subject is not traceable */ + switch(_state()) { + case Subject_info::DEAD: return Trace_result::SOURCE_IS_DEAD; + case Subject_info::ERROR: return Trace_result::SOURCE_IS_DEAD; + case Subject_info::FOREIGN: return Trace_result::FOREIGN; + case Subject_info::INVALID: return Trace_result::INVALID_SUBJECT; + case Subject_info::UNATTACHED: + case Subject_info::ATTACHED: + case Subject_info::TRACED: break; + } try { - _policy.setup(ram, local_rm, policy_ds, policy_size); - } catch (...) { - _buffer.flush(); - throw; + _buffer.setup(ram, size.num_bytes); } + catch (Out_of_ram) { return Trace_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Trace_result::OUT_OF_CAPS; } + + try { + _policy.setup(ram, local_rm, policy_ds, policy_size.num_bytes); + } + catch (Out_of_ram) { _buffer.flush(); return Trace_result::OUT_OF_RAM; } + catch (Out_of_caps) { _buffer.flush(); return Trace_result::OUT_OF_CAPS; } /* inform trace source about the new buffer */ Locked_ptr source(_source); @@ -238,12 +234,13 @@ class Core::Trace::Subject if (!source->try_acquire(*this)) { _policy.flush(); _buffer.flush(); - throw Traced_by_other_session(); + return Trace_result::FOREIGN; } _policy_id = policy_id; source->trace(_policy.dataspace(), _buffer.dataspace()); + return Trace_result::OK; } void pause() @@ -256,17 +253,13 @@ class Core::Trace::Subject /** * Resume tracing of paused source - * - * \throw Source_is_dead */ void resume() { Locked_ptr source(_source); - if (!source.valid()) - throw Source_is_dead(); - - source->enable(); + if (source.valid()) + source->enable(); } Subject_info info() @@ -331,24 +324,19 @@ class Core::Trace::Subject_registry void _unsynchronized_destroy(Subject &s) { _entries.remove(&s); - s.release(); - destroy(&_md_alloc, &s); }; /** * Obtain subject from given session-local ID - * - * \throw Nonexistent_subject */ - Subject &_unsynchronized_lookup_by_id(Subject_id id) + void _with_subject_unsynchronized(Subject_id id, auto const &fn) { - for (Subject *s = _entries.first(); s; s = s->next()) - if (s->id() == id) - return *s; - - throw Nonexistent_subject(); + Subject *ptr = _entries.first(); + for (; ptr && (ptr->id().id != id.id); ptr = ptr->next()); + if (ptr) + fn(*ptr); } public: @@ -404,7 +392,7 @@ class Core::Trace::Subject_registry /** * Retrieve existing subject IDs */ - size_t subjects(Subject_id *dst, size_t dst_len) + unsigned subjects(Subject_id *dst, size_t dst_len) { Mutex::Guard guard(_mutex); @@ -417,7 +405,7 @@ class Core::Trace::Subject_registry /** * Retrieve Subject_infos batched */ - size_t subjects(Subject_info * const dst, Subject_id * ids, size_t const len) + unsigned subjects(Subject_info * const dst, Subject_id * ids, size_t const len) { Mutex::Guard guard(_mutex); @@ -450,15 +438,15 @@ class Core::Trace::Subject_registry { Mutex::Guard guard(_mutex); - Subject &subject = _unsynchronized_lookup_by_id(subject_id); - _unsynchronized_destroy(subject); + _with_subject_unsynchronized(subject_id, [&] (Subject &subject) { + _unsynchronized_destroy(subject); }); } - Subject &lookup_by_id(Subject_id id) + void with_subject(Subject_id id, auto const &fn) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup_by_id(id); + return _with_subject_unsynchronized(id, fn); } }; diff --git a/repos/base/src/core/trace_session_component.cc b/repos/base/src/core/trace_session_component.cc index 919e45c45c..72688722ed 100644 --- a/repos/base/src/core/trace_session_component.cc +++ b/repos/base/src/core/trace_session_component.cc @@ -28,100 +28,139 @@ Dataspace_capability Session_component::dataspace() } -size_t Session_component::subjects() +Session_component::Subjects_rpc_result Session_component::subjects() { - _subjects.import_new_sources(_sources); - - return _subjects.subjects(_argument_buffer.local_addr(), - _argument_buffer.size()/sizeof(Subject_id)); -} - - -size_t Session_component::subject_infos() -{ - _subjects.import_new_sources(_sources); - - size_t const count = _argument_buffer.size() / (sizeof(Subject_info) + sizeof(Subject_id)); - Subject_info *infos = _argument_buffer.local_addr(); - Subject_id *ids = reinterpret_cast(infos + count); - - return _subjects.subjects(infos, ids, count); -} - - -Policy_id Session_component::alloc_policy(size_t size) -{ - if (size > _argument_buffer.size()) - throw Policy_too_large(); - - /* - * Using prefix incrementation makes sure a policy with id == 0 is - * invalid. - */ - Policy_id const id(++_policy_cnt); - - Ram_dataspace_capability ds_cap = _ram.alloc(size); /* may throw */ - try { - _policies.insert(*this, id, _policies_slab, ds_cap, size); - } catch (...) { - _ram.free(ds_cap); - throw; + _subjects.import_new_sources(_sources); } + catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; } - return id; + return Num_subjects { _subjects.subjects(_argument_buffer.local_addr(), + _argument_buffer.size()/sizeof(Subject_id)) }; } -Dataspace_capability Session_component::policy(Policy_id id) -{ - return _policies.dataspace(*this, id); -} - - -void Session_component::unload_policy(Policy_id id) +Session_component::Infos_rpc_result Session_component::subject_infos() { try { - Dataspace_capability ds_cap = _policies.dataspace(*this, id); + _subjects.import_new_sources(_sources); + } + catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; } + + unsigned const count = unsigned(_argument_buffer.size() / + (sizeof(Subject_info) + sizeof(Subject_id))); + + Subject_info * const infos = _argument_buffer.local_addr(); + Subject_id * const ids = reinterpret_cast(infos + count); + + return Num_subjects { _subjects.subjects(infos, ids, count) }; +} + + +Session_component::Alloc_policy_rpc_result Session_component::alloc_policy(Policy_size size) +{ + size.num_bytes = min(size.num_bytes, _argument_buffer.size()); + + Policy_id const id { ++_policy_cnt }; + + return _ram.try_alloc(size.num_bytes).convert( + + [&] (Ram_dataspace_capability const ds_cap) -> Alloc_policy_rpc_result { + try { + _policies.insert(*this, id, _policies_slab, ds_cap, size); + } + catch (Out_of_ram) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_CAPS; } + return id; + }, + [&] (Ram_allocator::Alloc_error const e) -> Alloc_policy_rpc_result { + switch (e) { + case Ram_allocator::Alloc_error::OUT_OF_RAM: return Alloc_policy_rpc_error::OUT_OF_RAM; + case Ram_allocator::Alloc_error::OUT_OF_CAPS: return Alloc_policy_rpc_error::OUT_OF_CAPS; + case Ram_allocator::Alloc_error::DENIED: break; + } + return Alloc_policy_rpc_error::INVALID; + }); +} + + +Dataspace_capability Session_component::policy(Policy_id const id) +{ + Dataspace_capability result { }; + _policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) { + result = ds; }); + return result; +} + + +void Session_component::unload_policy(Policy_id const id) +{ + _policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) { _policies.remove(*this, id); - _ram.free(static_cap_cast(ds_cap)); - } catch (Nonexistent_policy) { } + _ram.free(static_cap_cast(ds)); }); } -void Session_component::trace(Subject_id subject_id, Policy_id policy_id, - size_t buffer_size) +Session_component::Trace_rpc_result +Session_component::trace(Subject_id subject_id, Policy_id policy_id, Buffer_size size) { - size_t const policy_size = _policies.size(*this, policy_id); + Policy_size const policy_size = _policies.size(*this, policy_id); - Trace::Subject &subject = _subjects.lookup_by_id(subject_id); + if (policy_size.num_bytes == 0) + return Trace_rpc_error::INVALID_POLICY; - subject.trace(policy_id, _policies.dataspace(*this, policy_id), - policy_size, _ram, _local_rm, buffer_size); + Dataspace_capability const ds = policy(policy_id); + + auto rpc_result = [] (Subject::Trace_result const result) -> Trace_rpc_result + { + using Result = Subject::Trace_result; + switch (result) { + case Result::OK: return Trace_ok { }; + case Result::OUT_OF_RAM: return Trace_rpc_error::OUT_OF_RAM; + case Result::OUT_OF_CAPS: return Trace_rpc_error::OUT_OF_CAPS; + case Result::FOREIGN: return Trace_rpc_error::FOREIGN; + case Result::SOURCE_IS_DEAD: return Trace_rpc_error::SOURCE_IS_DEAD; + case Result::INVALID_SUBJECT: break; + }; + return Trace_rpc_error::INVALID_SUBJECT; + }; + + Trace_rpc_result result = Trace_rpc_error::INVALID_SUBJECT; + + _subjects.with_subject(subject_id, [&] (Subject &subject) { + result = rpc_result(subject.trace(policy_id, ds, policy_size, _ram, + _local_rm, size)); }); + + return result; } -void Session_component::pause(Subject_id subject_id) +void Session_component::pause(Subject_id id) { - _subjects.lookup_by_id(subject_id).pause(); + _subjects.with_subject(id, [&] (Subject &subject) { subject.pause(); }); } -void Session_component::resume(Subject_id subject_id) +void Session_component::resume(Subject_id id) { - _subjects.lookup_by_id(subject_id).resume(); + _subjects.with_subject(id, [&] (Subject &subject) { subject.resume(); }); } -Dataspace_capability Session_component::buffer(Subject_id subject_id) +Dataspace_capability Session_component::buffer(Subject_id id) { - return _subjects.lookup_by_id(subject_id).buffer(); + Dataspace_capability result { }; + _subjects.with_subject(id, [&] (Subject &subject) { + result = subject.buffer(); }); + return result; } -void Session_component::free(Subject_id subject_id) +void Session_component::free(Subject_id id) { - _subjects.release(subject_id); + _subjects.release(id); } diff --git a/repos/gems/src/app/trace_recorder/monitor.cc b/repos/gems/src/app/trace_recorder/monitor.cc index 14d92824bc..31331eb8ba 100644 --- a/repos/gems/src/app/trace_recorder/monitor.cc +++ b/repos/gems/src/app/trace_recorder/monitor.cc @@ -108,7 +108,7 @@ void Trace_recorder::Monitor::start(Xml_node config) trace_config.session_arg_buffer); /* find matching subjects according to config and start tracing */ - using SC = Genode::Trace::Session_client; + using SC = Genode::Trace::Connection; SC::For_each_subject_info_result const info_result = _trace->for_each_subject_info([&] (Trace::Subject_id const &id, Trace::Subject_info const &info) { @@ -123,16 +123,28 @@ void Trace_recorder::Monitor::start(Xml_node config) if (!session_policy.has_attribute("policy")) return; - Number_of_bytes buffer_sz = + Trace::Buffer_size const buffer_size { session_policy.attribute_value("buffer", - Number_of_bytes(trace_config.default_buf_sz)); + Number_of_bytes(trace_config.default_buf_sz)) }; + + Policy::Name const policy_name = session_policy.attribute_value("policy", Policy::Name()); + + auto trace = [&] (Policy const &policy) + { + policy.id().with_result( + [&] (Trace::Policy_id const policy_id) { + if (_trace->trace(id, policy_id, buffer_size).failed()) + warning("failed to enable tracing for policy '", policy_name, "'"); + }, + [&] (Trace::Connection::Alloc_policy_error) { + warning("skip tracing because of missing policy"); }); + }; /* find and assign policy; create/insert if not present */ - Policy::Name const policy_name = session_policy.attribute_value("policy", Policy::Name()); bool const create = _policies.with_element(policy_name, [&] /* match */ (Policy & policy) { - _trace->trace(id, policy.id(), buffer_sz); + trace(policy); return false; }, [&] /* no_match */ { return true; } @@ -141,7 +153,7 @@ void Trace_recorder::Monitor::start(Xml_node config) /* create policy if it did not exist */ if (create) { Policy &policy = *new (_alloc) Policy(_env, *_trace, policy_name, _policies); - _trace->trace(id, policy.id(), buffer_sz); + trace(policy); } log("Inserting trace policy \"", policy_name, "\" into ", @@ -197,23 +209,19 @@ void Trace_recorder::Monitor::stop() _timer.trigger_periodic(0); _trace_buffers.for_each([&] (Attached_buffer &buf) { - try { - /* stop tracing */ - _trace->pause(buf.subject_id()); - } catch (Trace::Nonexistent_subject) { } + + /* stop tracing */ + _trace->pause(buf.subject_id()); /* read remaining events from buffers */ buf.process_events(*_trace_directory); /* destroy writers */ buf.writers().for_each([&] (Writer_base &writer) { - destroy(_alloc, &writer); - }); + destroy(_alloc, &writer); }); - try { - /* detach buffer */ - _trace->free(buf.subject_id()); - } catch (Trace::Nonexistent_subject) { } + /* detach buffer */ + _trace->free(buf.subject_id()); /* destroy buffer */ destroy(_alloc, &buf); diff --git a/repos/gems/src/app/trace_recorder/policy.cc b/repos/gems/src/app/trace_recorder/policy.cc index f39fbce27f..26d3374239 100644 --- a/repos/gems/src/app/trace_recorder/policy.cc +++ b/repos/gems/src/app/trace_recorder/policy.cc @@ -16,18 +16,27 @@ using namespace Genode; -Trace_recorder::Policy::Policy(Env &env, - Trace::Connection &trace, - Policy::Name const &name, - Policies &policies) -: - Policies::Element(policies, name), - _env(env), _trace(trace), _rom(env, name.string()) + +Trace_recorder::Policy::Id Trace_recorder::Policy::_init_policy() { - Dataspace_capability dst_ds = _trace.policy(_id); - void *dst = _env.rm().attach(dst_ds); - void *src = _env.rm().attach(_ds); - memcpy(dst, src, _size); - _env.rm().detach(dst); - _env.rm().detach(src); + Id const id = _trace.alloc_policy(_size); + + id.with_result( + [&] (Trace::Policy_id const policy_id) { + Dataspace_capability dst_ds = _trace.policy(policy_id); + if (!dst_ds.valid()) { + warning("unable to obtain policy buffer"); + return; + } + + Attached_dataspace const src { _env.rm(), _ds }; + Attached_dataspace dst { _env.rm(), dst_ds }; + + memcpy(dst.local_addr(), src.local_addr(), _size.num_bytes); + }, + [&] (Trace::Connection::Alloc_policy_error) { + warning("failed to allocate policy buffer"); }); + + return id; } + diff --git a/repos/gems/src/app/trace_recorder/policy.h b/repos/gems/src/app/trace_recorder/policy.h index 6653b329dd..1f8ce3b566 100644 --- a/repos/gems/src/app/trace_recorder/policy.h +++ b/repos/gems/src/app/trace_recorder/policy.h @@ -33,6 +33,12 @@ namespace Trace_recorder { */ class Trace_recorder::Policy : Policies::Element { + public: + + using Id = Genode::Trace::Connection::Alloc_policy_result; + using Name = Policy_name; + using Policies::Element::name; + private: friend class Genode::Dictionary; friend class Genode::Avl_node; @@ -42,25 +48,27 @@ class Trace_recorder::Policy : Policies::Element Genode::Trace::Connection &_trace; Genode::Rom_connection _rom; Genode::Rom_dataspace_capability const _ds { _rom.dataspace() }; - Genode::size_t const _size { Genode::Dataspace_client(_ds).size() }; - Genode::Trace::Policy_id const _id { _trace.alloc_policy(_size) }; + Genode::Trace::Policy_size const _size { Genode::Dataspace_client(_ds).size() }; + + Id _init_policy(); + Id const _id = _init_policy(); public: - using Name = Policy_name; - using Policies::Element::name; - Policy(Genode::Env &env, Genode::Trace::Connection &trace, Name const &name, - Policies &policies); - + Policies &policies) + : + Policies::Element(policies, name), + _env(env), _trace(trace), _rom(env, name.string()) + { } /*************** ** Accessors ** ***************/ - Genode::Trace::Policy_id id() const { return _id; } + Id id() const { return _id; } }; #endif /* _POLICY_H_ */ diff --git a/repos/gems/src/lib/vfs/trace/directory_dictionary.h b/repos/gems/src/lib/vfs/trace/directory_dictionary.h index 0242fb1db1..bec87e9855 100644 --- a/repos/gems/src/lib/vfs/trace/directory_dictionary.h +++ b/repos/gems/src/lib/vfs/trace/directory_dictionary.h @@ -55,7 +55,7 @@ class Vfs::Trace_node : public Dictionary::Element public: Trace_node(Allocator &alloc, Dictionary &dict, Session_label const &label, - Trace::Subject_id const id = 0) + Trace::Subject_id const id = { }) : Dictionary::Element(dict, Label(label)), _alloc(alloc), _id(id) @@ -85,7 +85,7 @@ class Vfs::Trace_node : public Dictionary::Element void xml(Xml_generator &xml) const { _dict.for_each([&] (Trace_node const &node) { - if (node.id() == 0) + if (node.id().id == 0) xml.node("dir", [&] () { xml.attribute("name", node.name); node.xml(xml); diff --git a/repos/gems/src/lib/vfs/trace/vfs.cc b/repos/gems/src/lib/vfs/trace/vfs.cc index 4d887e2c57..8b1c804754 100644 --- a/repos/gems/src/lib/vfs/trace/vfs.cc +++ b/repos/gems/src/lib/vfs/trace/vfs.cc @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -74,11 +75,13 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system enum State { OFF, TRACE, PAUSED } _state { OFF }; + using Policy_id = Trace::Connection::Alloc_policy_result; + Vfs::Env &_env; Trace::Connection &_trace; - Trace::Policy_id _policy; + Policy_id _policy; Trace::Subject_id _id; - size_t _buffer_size { 1024 * 1024 }; + Trace::Buffer_size _buffer_size { 1024 * 1024 }; size_t _stat_size { 0 }; Trace_entries _entries { _env }; @@ -98,12 +101,14 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system { _entries.flush(); - try { - _trace.trace(_id, _policy, _buffer_size); - } catch (...) { - error("failed to start tracing"); - return; - } + _policy.with_result( + [&] (Trace::Policy_id policy_id) { + if (_trace.trace(_id, policy_id, _buffer_size).failed()) + error("failed to start tracing"); + }, + [&] (Trace::Connection::Alloc_policy_error) { + warning("skip tracing because of invalid policy"); + }); _entries.setup(_trace.buffer(_id)); } @@ -196,9 +201,9 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system ** FS event handlers ** ***********************/ - bool resize_buffer(size_t size) + bool resize_buffer(Trace::Buffer_size size) { - if (size == 0) return false; + if (size.num_bytes == 0) return false; _buffer_size = size; @@ -317,7 +322,7 @@ class Vfs_trace::Subject : private Subject_factory, void _buffer_size() { - Number_of_bytes size = _buffer_size_fs.value(); + Trace::Buffer_size const size { _buffer_size_fs.value() }; if (_trace_fs.resize_buffer(size) == false) { /* restore old value */ @@ -332,7 +337,7 @@ class Vfs_trace::Subject : private Subject_factory, Subject(Vfs::Env &env, Trace::Connection &trace, Trace::Policy_id policy, Xml_node node) - : Subject_factory(env, trace, policy, node.attribute_value("id", 0u)), + : Subject_factory(env, trace, policy, { node.attribute_value("id", 0u) }), Dir_file_system(env, Xml_node(_config(node).string()), *this) { } @@ -344,11 +349,12 @@ class Vfs_trace::Subject : private Subject_factory, struct Vfs_trace::Local_factory : File_system_factory { - Vfs::Env &_env; + using Policy_id = Trace::Connection::Alloc_policy_result; - Trace::Connection _trace; - Trace::Policy_id _policy_id { 0 }; - Trace_directory _directory { _env.alloc() }; + Vfs::Env &_env; + Trace::Connection _trace; + Policy_id _policy_id = Trace::Connection::Alloc_policy_error::INVALID; + Trace_directory _directory { _env.alloc() }; void _install_null_policy() { @@ -357,7 +363,7 @@ struct Vfs_trace::Local_factory : File_system_factory try { null_policy.construct(_env.env(), "null"); - _policy_id = _trace.alloc_policy(null_policy->size()); + _policy_id = _trace.alloc_policy(Trace::Policy_size { null_policy->size() }); } catch (Out_of_caps) { throw; } catch (Out_of_ram) { throw; } @@ -368,9 +374,16 @@ struct Vfs_trace::Local_factory : File_system_factory } /* copy policy into trace session */ - void *dst = _env.env().rm().attach(_trace.policy(_policy_id)); - memcpy(dst, null_policy->local_addr(), null_policy->size()); - _env.env().rm().detach(dst); + _policy_id.with_result( + [&] (Trace::Policy_id const id) { + Dataspace_capability ds_cap = _trace.policy(id); + if (ds_cap.valid()) { + Attached_dataspace dst { _env.env().rm(), ds_cap }; + memcpy(dst.local_addr(), null_policy->local_addr(), null_policy->size()); + } + }, + [&] (Trace::Connection::Alloc_policy_error) { } + ); } size_t _config_session_ram(Xml_node config) @@ -399,10 +412,15 @@ struct Vfs_trace::Local_factory : File_system_factory Vfs::File_system *create(Vfs::Env&, Xml_node node) override { - if (node.has_type(Subject::type_name())) - return new (_env.alloc()) Subject(_env, _trace, _policy_id, node); + Vfs::File_system *result = nullptr; - return nullptr; + if (node.has_type(Subject::type_name())) + _policy_id.with_result( + [&] (Trace::Policy_id const id) { + result = new (_env.alloc()) Subject(_env, _trace, id, node); }, + [&] (Trace::Connection::Alloc_policy_error) { }); + + return result; } }; diff --git a/repos/os/src/app/trace_logger/main.cc b/repos/os/src/app/trace_logger/main.cc index befe4f112c..fa0ffa412e 100644 --- a/repos/os/src/app/trace_logger/main.cc +++ b/repos/os/src/app/trace_logger/main.cc @@ -162,8 +162,7 @@ class Main if (_config.verbose) log("destroy monitor: subject ", monitor.subject_id().id); - try { _trace.free(monitor.subject_id()); } - catch (Trace::Nonexistent_subject) { } + _trace.free(monitor.subject_id()); monitors.remove(&monitor); destroy(_heap, &monitor); } @@ -172,32 +171,30 @@ class Main Trace::Subject_id const id, Xml_node const &session_policy) { - auto warn_msg = [] (auto reason) { - warning("Cannot activate tracing: ", reason); }; + Trace::Buffer_size const buffer_size { + session_policy.attribute_value("buffer", Number_of_bytes(_config.default_buf_sz)) }; - try { - Number_of_bytes const buffer_sz = - session_policy.attribute_value("buffer", Number_of_bytes(_config.default_buf_sz)); + Policy_name const policy_name = + session_policy.attribute_value("policy", _config.default_policy_name); - Policy_name const policy_name = - session_policy.attribute_value("policy", _config.default_policy_name); + auto trace = [&] (Policy const &policy) + { + policy.id.with_result( + [&] (Trace::Policy_id const policy_id) { + _trace.trace(id, policy_id, buffer_size); }, + [&] (auto) { + warning("skip tracing because of invalid policy '", policy_name, "'"); + }); + }; - _policies.with_element(policy_name, - [&] (Policy const &policy) { - _trace.trace(id.id, policy.id(), buffer_sz); - }, - [&] /* no match */ { - Policy &policy = *new (_heap) Policy(_env, _trace, _policies, policy_name); - _trace.trace(id.id, policy.id(), buffer_sz); - } - ); - monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id)); - } - catch (Trace::Source_is_dead ) { warn_msg("Source_is_dead" ); return; } - catch (Trace::Nonexistent_policy ) { warn_msg("Nonexistent_policy" ); return; } - catch (Trace::Traced_by_other_session) { warn_msg("Traced_by_other_session"); return; } - catch (Trace::Nonexistent_subject ) { warn_msg("Nonexistent_subject" ); return; } - catch (Region_map::Invalid_dataspace ) { warn_msg("Loading policy failed" ); return; } + _policies.with_element(policy_name, + [&] (Policy const &policy) { + trace(policy); }, + [&] /* no match */ { + Policy &policy = *new (_heap) Policy(_env, _trace, _policies, policy_name); + trace(policy); }); + + monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id)); } void _handle_period(Duration) diff --git a/repos/os/src/app/trace_logger/policy.cc b/repos/os/src/app/trace_logger/policy.cc index 918e5d639b..6bd6eca35c 100644 --- a/repos/os/src/app/trace_logger/policy.cc +++ b/repos/os/src/app/trace_logger/policy.cc @@ -22,10 +22,20 @@ Policy::Policy(Env &env, Trace::Connection &trace, Policy_dict &dict, : Policy_dict::Element(dict, name), _env(env), _trace(trace) { - Dataspace_capability dst_ds = _trace.policy(_id); - void *dst = _env.rm().attach(dst_ds); - void *src = _env.rm().attach(_ds); - memcpy(dst, src, _size); - _env.rm().detach(dst); - _env.rm().detach(src); + id.with_result( + [&] (Trace::Policy_id id) { + Dataspace_capability const dst_ds = _trace.policy(id); + if (dst_ds.valid()) { + void * const dst = _env.rm().attach(dst_ds); + void const * const src = _env.rm().attach(_ds); + memcpy(dst, src, _size); + _env.rm().detach(dst); + _env.rm().detach(src); + return; + } + warning("failed to obtain policy buffer for '", name, "'"); + }, + [&] (Trace::Connection::Alloc_policy_error) { + warning("failed to allocate policy buffer for '", name, "'"); + }); } diff --git a/repos/os/src/app/trace_logger/policy.h b/repos/os/src/app/trace_logger/policy.h index 9876b91a9b..6024e61b7f 100644 --- a/repos/os/src/app/trace_logger/policy.h +++ b/repos/os/src/app/trace_logger/policy.h @@ -38,16 +38,17 @@ class Policy : public Policy_dict::Element Genode::Rom_connection _rom { _env, name }; Genode::Rom_dataspace_capability const _ds { _rom.dataspace() }; Genode::size_t const _size { Genode::Dataspace_client(_ds).size() }; - Genode::Trace::Policy_id const _id { _trace.alloc_policy(_size) }; public: + using Id = Genode::Trace::Connection::Alloc_policy_result; + + Id const id { _trace.alloc_policy({_size}) }; + Policy(Genode::Env &env, Genode::Trace::Connection &trace, Policy_dict &dict, Policy_name const &name); - - Genode::Trace::Policy_id id() const { return _id; } }; #endif /* _POLICY_H_ */ diff --git a/repos/os/src/app/trace_subject_reporter/main.cc b/repos/os/src/app/trace_subject_reporter/main.cc index c3c314d3ea..5546887200 100644 --- a/repos/os/src/app/trace_subject_reporter/main.cc +++ b/repos/os/src/app/trace_subject_reporter/main.cc @@ -58,8 +58,9 @@ struct Trace_subject_registry return nullptr; } - enum { MAX_SUBJECTS = 512 }; - Genode::Trace::Subject_id _subjects[MAX_SUBJECTS]; + static constexpr Genode::Trace::Num_subjects MAX_SUBJECTS { 512 }; + + Genode::Trace::Subject_id _subjects[MAX_SUBJECTS.value]; void _sort_by_recent_execution_time() { @@ -81,14 +82,6 @@ struct Trace_subject_registry _entries = sorted; } - unsigned update_subjects(Genode::Trace::Connection &trace) - { - return (unsigned)Genode::retry( - [&] () { return trace.subjects(_subjects, MAX_SUBJECTS); }, - [&] () { trace.upgrade_ram(4096); } - ); - } - public: void update(Genode::Trace::Connection &trace, Genode::Allocator &alloc) diff --git a/repos/os/src/server/cpu_balancer/schedule.cc b/repos/os/src/server/cpu_balancer/schedule.cc index 44cbf1c2ee..7907dbd631 100644 --- a/repos/os/src/server/cpu_balancer/schedule.cc +++ b/repos/os/src/server/cpu_balancer/schedule.cc @@ -39,21 +39,24 @@ void Cpu::Session::update_threads(Trace &trace, Session_label const &cpu_balance Execution_time time { }; /* request execution time and current location */ - try { - trace.retrieve(subject_id.id, [&] (Execution_time const time_current, - Affinity::Location const current_loc) - { - current = current_loc; - time = time_current; + bool subject_exists = false; + trace.retrieve(subject_id, [&] (Execution_time const time_current, + Affinity::Location const current_loc) + { + subject_exists = true; - if (_verbose) - log("[", _label, "] name='", name, "' at ", - current_loc.xpos(), "x", current_loc.ypos(), - " has ec/sc time ", time.thread_context, "/", - time.scheduling_context, - " policy=", policy.string()); - }); - } catch (Genode::Trace::Nonexistent_subject) { + current = current_loc; + time = time_current; + + if (_verbose) + log("[", _label, "] name='", name, "' at ", + current_loc.xpos(), "x", current_loc.ypos(), + " has ec/sc time ", time.thread_context, "/", + time.scheduling_context, + " policy=", policy.string()); + }); + + if (!subject_exists) { /* how could that be ? */ error("[", _label, "] name='", name, "'" " subject id invalid ?? ", subject_id.id); diff --git a/repos/os/src/server/cpu_balancer/trace.h b/repos/os/src/server/cpu_balancer/trace.h index 028295b06e..028a7a148b 100644 --- a/repos/os/src/server/cpu_balancer/trace.h +++ b/repos/os/src/server/cpu_balancer/trace.h @@ -64,9 +64,8 @@ class Cpu::Trace * stored trace ids are not valid if used with subject_info(id) * and we get exception thrown about unknown ids. */ - _trace->_retry([&] () { - _trace->call(); - }); + _trace->_retry([&] { + return _trace->call(); }); _subject_id_reread ++; } diff --git a/repos/os/src/test/trace/main.cc b/repos/os/src/test/trace/main.cc index 2878a4cb33..1053b21f49 100644 --- a/repos/os/src/test/trace/main.cc +++ b/repos/os/src/test/trace/main.cc @@ -27,27 +27,27 @@ using namespace Genode; struct Test_thread : Thread { - Env &env; - Timer::Connection timer { env }; - bool stop { false }; + Env &_env; + Timer::Connection _timer { _env }; + bool _stop { false }; void entry() override { - for (unsigned i = 0; !stop; i++) { + for (unsigned i = 0; !_stop; i++) { if (i & 0x3) { - Ram_dataspace_capability ds_cap = env.ram().alloc(1024); - env.ram().free(ds_cap); + Ram_dataspace_capability ds_cap = _env.ram().alloc(1024); + _env.ram().free(ds_cap); } - timer.msleep(250); + _timer.msleep(250); } } - Test_thread(Env &env, Name &name) - : Thread(env, name, 1024 * sizeof(addr_t)), env(env) { start(); } + Test_thread(Env &env, Name const &name) + : Thread(env, name, 1024 * sizeof(addr_t)), _env(env) { start(); } ~Test_thread() { - stop = true; + _stop = true; this->join(); } @@ -141,7 +141,7 @@ struct Test_out_of_metadata * error-handling procedure. */ - enum { MAX_SUBJECT_IDS = 16 }; + static constexpr unsigned MAX_SUBJECT_IDS = 16; Trace::Subject_id subject_ids[MAX_SUBJECT_IDS]; try { @@ -169,7 +169,7 @@ struct Test_out_of_metadata Trace::Connection trace(env, sizeof(subject_ids) + 5*4096, sizeof(subject_ids)); - trace.subjects(subject_ids, MAX_SUBJECT_IDS); + trace.subjects(subject_ids, { MAX_SUBJECT_IDS }); /* we should never arrive here */ struct Unexpectedly_got_no_exception{}; @@ -185,66 +185,70 @@ struct Test_out_of_metadata struct Test_tracing { - Env &env; - Attached_rom_dataspace config { env, "config" }; - Trace::Connection trace { env, 1024*1024, 64*1024 }; - Timer::Connection timer { env }; - Test_thread::Name thread_name { "test-thread" }; - Test_thread thread { env, thread_name }; - Trace::Policy_id policy_id { }; - - Constructible test_monitor { }; - + using Policy_id = Trace::Connection::Alloc_policy_result; using String = Genode::String<64>; - String policy_label { }; - String policy_module { }; - String policy_thread { }; + Env &_env; + Attached_rom_dataspace _config { _env, "config" }; + Trace::Connection _trace { _env, 1024*1024, 64*1024 }; + Timer::Connection _timer { _env }; + Test_thread::Name _thread_name { "test-thread" }; + Test_thread _thread { _env, _thread_name }; - Rom_dataspace_capability policy_module_rom_ds { }; + static String _trace_policy_attr(Xml_node const &config, auto const &attr_name) + { + String result { }; + config.with_optional_sub_node("trace_policy", [&] (Xml_node const &policy) { + result = policy.attribute_value(attr_name, String()); }); + return result; + } + + String const _policy_label = _trace_policy_attr(_config.xml(), "label"); + String const _policy_module = _trace_policy_attr(_config.xml(), "module"); + String const _policy_thread = _trace_policy_attr(_config.xml(), "thread"); + + Policy_id _init_policy() + { + log("test Tracing"); + + try { + log("load module: '", _policy_module, "' for label: '", _policy_label, "'"); + Attached_rom_dataspace const rom { _env, _policy_module.string() }; + + Policy_id const policy_id = _trace.alloc_policy(Trace::Policy_size { rom.size() }); + + Dataspace_capability ds_cap { }; + policy_id.with_result( + [&] (Trace::Policy_id id) { ds_cap = _trace.policy(id); }, + [&] (Trace::Connection::Alloc_policy_error) { }); + + if (!ds_cap.valid()) { + error("failed to obtain policy buffer"); + throw Failed(); + } + + Attached_dataspace dst { _env.rm(), ds_cap }; + memcpy(dst.local_addr(), rom.local_addr(), rom.size()); + + return policy_id; + + } catch (...) { + error("could not load module '", _policy_module, "' for " + "label '", _policy_label, "'"); + throw Failed(); + } + } + + Policy_id const _policy_id = _init_policy(); + + Constructible _test_monitor { }; struct Failed : Genode::Exception { }; - Test_tracing(Env &env) : env(env) + Test_tracing(Env &env) : _env(env) { - enum { MAX_SUBJECTS = 128 }; - - log("test Tracing"); - - config.xml().with_optional_sub_node("trace_policy", [&] (Xml_node const &policy) { - policy_label = policy.attribute_value("label", String()); - policy_module = policy.attribute_value("module", String()); - policy_thread = policy.attribute_value("thread", String()); - }); - - try { - Rom_connection policy_rom(env, policy_module.string()); - policy_module_rom_ds = policy_rom.dataspace(); - - size_t rom_size = Dataspace_client(policy_module_rom_ds).size(); - - policy_id = trace.alloc_policy(rom_size); - Dataspace_capability ds_cap = trace.policy(policy_id); - - if (ds_cap.valid()) { - void *ram = env.rm().attach(ds_cap); - void *rom = env.rm().attach(policy_module_rom_ds); - memcpy(ram, rom, rom_size); - - env.rm().detach(ram); - env.rm().detach(rom); - } - - log("load module: '", policy_module, "' for " - "label: '", policy_label, "'"); - } catch (...) { - error("could not load module '", policy_module, "' for " - "label '", policy_label, "'"); - throw Failed(); - } - /* wait some time before querying the subjects */ - timer.msleep(1500); + _timer.msleep(1500); auto print_info = [this] (Trace::Subject_id id, Trace::Subject_info info) { @@ -259,7 +263,7 @@ struct Test_tracing "quantum:", info.execution_time().quantum); }; - trace.for_each_subject_info(print_info); + _trace.for_each_subject_info(print_info); auto check_unattached = [this] (Trace::Subject_id id, Trace::Subject_info info) { @@ -267,48 +271,59 @@ struct Test_tracing error("Subject ", id.id, " is not UNATTACHED"); }; - trace.for_each_subject_info(check_unattached); + _trace.for_each_subject_info(check_unattached); /* enable tracing for test-thread */ auto enable_tracing = [this, &env] (Trace::Subject_id id, Trace::Subject_info info) { - if (info.session_label() != policy_label - || info.thread_name() != policy_thread) { + if (info.session_label() != _policy_label + || info.thread_name() != _policy_thread) { return; } - try { - log("enable tracing for " - "thread:'", info.thread_name().string(), "' with " - "policy:", policy_id.id); + _policy_id.with_result( + [&] (Trace::Policy_id policy_id) { + log("enable tracing for " + "thread:'", info.thread_name(), "' with " + "policy:", policy_id.id); - trace.trace(id.id, policy_id, 16384U); + Trace::Connection::Trace_result const trace_result = + _trace.trace(id, policy_id, Trace::Buffer_size{16384}); - Dataspace_capability ds_cap = trace.buffer(id.id); - test_monitor.construct(env.rm(), id.id, ds_cap); + trace_result.with_result( + [&] (Trace::Trace_ok) { + Dataspace_capability ds_cap = _trace.buffer(id); + _test_monitor.construct(env.rm(), id, ds_cap); + }, + [&] (Trace::Connection::Trace_error e) { + if (e == Trace::Connection::Trace_error::SOURCE_IS_DEAD) + error("source is dead"); - } catch (Trace::Source_is_dead) { - error("source is dead"); - throw Failed(); - } + throw Failed(); + }); + }, + [&] (Trace::Connection::Alloc_policy_error) { + error("policy alloc failed"); + throw Failed(); + }); }; - trace.for_each_subject_info(enable_tracing); + _trace.for_each_subject_info(enable_tracing); /* give the test thread some time to run */ - timer.msleep(1000); + _timer.msleep(1000); - trace.for_each_subject_info(print_info); + _trace.for_each_subject_info(print_info); /* read events from trace buffer */ - if (test_monitor.constructed()) { - test_monitor->dump(); - test_monitor.destruct(); + if (_test_monitor.constructed()) { + _test_monitor->dump(); + _test_monitor.destruct(); log("passed Tracing test"); } else - error("Thread '", policy_thread, "' not found for session ", policy_label); + error("Thread '", _policy_thread, "' not found for session ", _policy_label); } };