From 8f9355b360fd0217572cfc98bf1f050dd456ab9e Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 16 Oct 2014 11:15:46 +0200 Subject: [PATCH] thread API & CPU session: accounting of CPU quota In the init configuration one can configure the donation of CPU time via 'resource' tags that have the attribute 'name' set to "CPU" and the attribute 'quantum' set to the percentage of CPU quota that init shall donate. The pattern is the same as when donating RAM quota. ! ! ! This would cause init to try donating 75% of its CPU quota to the child "test". Init and core do not preserve CPU quota for their own requirements by default as it is done with RAM quota. The CPU quota that a process owns can be applied through the thread constructor. The constructor has been enhanced by an argument that indicates the percentage of the programs CPU quota that shall be granted to the new thread. So 'Thread(33, "test")' would cause the backing CPU session to try to grant 33% of the programs CPU quota to the thread "test". By now, the CPU quota of a thread can't be altered after construction. Constructing a thread with CPU quota 0 doesn't mean the thread gets never scheduled but that the thread has no guaranty to receive CPU time. Such threads have to live with excess CPU time. Threads that already existed in the official repositories of Genode were adapted in the way that they receive a quota of 0. This commit also provides a run test 'cpu_quota' in base-hw (the only kernel that applies the CPU-quota scheme currently). The test basically runs three threads with different physical CPU quota. The threads simply count for 30 seconds each and the test then checks wether the counter values relate to the CPU-quota distribution. fix #1275 --- .../src/base/thread/thread_bootstrap.cc | 2 +- .../src/base/thread/thread_start.cc | 2 +- .../src/core/include/platform_thread.h | 2 +- .../base-codezero/src/core/platform_thread.cc | 2 +- repos/base-codezero/src/core/thread_start.cc | 3 +- .../src/base/thread/thread_bootstrap.cc | 2 +- .../src/core/include/platform_thread.h | 2 +- repos/base-fiasco/src/core/platform.cc | 5 +- repos/base-fiasco/src/core/platform_thread.cc | 3 +- repos/base-fiasco/src/core/thread_start.cc | 3 +- .../base-foc/include/foc_cpu_session/client.h | 14 +- repos/base-foc/src/base/thread/thread.cc | 11 +- .../base-foc/src/base/thread/thread_start.cc | 4 +- .../src/core/include/cpu_session_component.h | 34 +++- repos/base-foc/src/core/thread_start.cc | 2 +- repos/base-host/src/core/thread_host.cc | 2 +- repos/base-hw/run/cpu_quota.run | 161 ++++++++++++++++++ repos/base-hw/src/base/thread/start.cc | 4 +- .../src/core/include/kernel/core_interface.h | 5 +- repos/base-hw/src/core/include/kernel/cpu.h | 11 +- .../base-hw/src/core/include/kernel/thread.h | 4 +- repos/base-hw/src/core/include/kernel/vm.h | 2 +- .../src/core/include/platform_thread.h | 11 +- repos/base-hw/src/core/kernel/cpu.cc | 2 +- repos/base-hw/src/core/kernel/kernel.cc | 2 +- repos/base-hw/src/core/kernel/thread.cc | 10 +- repos/base-hw/src/core/pager.cc | 2 +- repos/base-hw/src/core/platform_thread.cc | 7 +- repos/base-hw/src/core/thread_start.cc | 2 +- repos/base-hw/src/test/cpu_quota/main.cc | 63 +++++++ repos/base-hw/src/test/cpu_quota/target.mk | 14 ++ .../include/linux_cpu_session/client.h | 13 +- repos/base-linux/src/base/env/platform_env.h | 4 +- repos/base-linux/src/base/process/process.cc | 2 +- .../src/base/thread/thread_linux.cc | 4 +- .../src/core/include/cpu_session_component.h | 34 +++- repos/base-linux/src/core/thread_linux.cc | 2 +- repos/base-linux/src/platform/lx_hybrid.cc | 10 +- repos/base-nova/include/cpu_session/client.h | 14 +- repos/base-nova/src/base/pager/pager.cc | 2 +- repos/base-nova/src/base/server/server.cc | 2 +- .../base-nova/src/base/thread/thread_nova.cc | 4 +- .../src/core/include/cpu_session_component.h | 34 +++- .../src/core/irq_session_component.cc | 2 +- repos/base-nova/src/core/thread_start.cc | 2 +- .../src/base/thread/thread_bootstrap.cc | 2 +- .../src/core/include/platform_thread.h | 2 +- repos/base-okl4/src/core/platform.cc | 2 +- repos/base-okl4/src/core/platform_thread.cc | 2 +- repos/base-okl4/src/core/thread_start.cc | 2 +- .../src/base/thread/thread_bootstrap.cc | 2 +- .../src/core/include/platform_thread.h | 2 +- repos/base-pistachio/src/core/platform.cc | 4 +- .../src/core/platform_thread.cc | 3 +- repos/base-pistachio/src/core/thread_start.cc | 3 +- repos/base/include/base/pager.h | 2 +- repos/base/include/base/thread.h | 39 +++-- repos/base/include/cpu_session/capability.h | 7 +- repos/base/include/cpu_session/client.h | 15 +- repos/base/include/cpu_session/cpu_session.h | 81 ++++++++- repos/base/src/base/env/platform_env.h | 6 +- repos/base/src/base/process/process.cc | 2 +- repos/base/src/base/server/common.cc | 2 +- repos/base/src/base/thread/thread.cc | 11 +- repos/base/src/base/thread/thread_start.cc | 2 +- repos/base/src/core/cpu_session_component.cc | 127 ++++++++++++-- repos/base/src/core/include/cpu_root.h | 11 +- .../src/core/include/cpu_session_component.h | 91 +++++++++- repos/base/src/core/main.cc | 9 + repos/libports/src/lib/pthread/thread.h | 2 +- repos/os/include/init/child.h | 92 ++++++---- repos/os/include/os/irq_activation.h | 2 +- repos/ports-foc/src/lib/l4lx/include/vcpu.h | 2 +- repos/ports/include/vmm/vcpu_dispatcher.h | 2 +- repos/ports/include/vmm/vcpu_thread.h | 4 +- .../app/gdb_monitor/cpu_session_component.cc | 12 +- .../app/gdb_monitor/cpu_session_component.h | 6 +- repos/ports/src/noux/cpu_session_component.h | 10 +- repos/qt4/include/genode/thread_qt.h | 2 +- 79 files changed, 898 insertions(+), 187 deletions(-) create mode 100644 repos/base-hw/run/cpu_quota.run create mode 100644 repos/base-hw/src/test/cpu_quota/main.cc create mode 100644 repos/base-hw/src/test/cpu_quota/target.mk diff --git a/repos/base-codezero/src/base/thread/thread_bootstrap.cc b/repos/base-codezero/src/base/thread/thread_bootstrap.cc index 8a34574ac..7b81f061f 100644 --- a/repos/base-codezero/src/base/thread/thread_bootstrap.cc +++ b/repos/base-codezero/src/base/thread/thread_bootstrap.cc @@ -82,7 +82,7 @@ void Genode::Thread_base::_thread_bootstrap() } -void Genode::Thread_base::_init_platform_thread(Type type) +void Genode::Thread_base::_init_platform_thread(size_t, Type type) { if (type == NORMAL) { return; } diff --git a/repos/base-codezero/src/base/thread/thread_start.cc b/repos/base-codezero/src/base/thread/thread_start.cc index 7292329f0..658d901f3 100644 --- a/repos/base-codezero/src/base/thread/thread_start.cc +++ b/repos/base-codezero/src/base/thread/thread_start.cc @@ -55,7 +55,7 @@ void Thread_base::start() /* create thread at core */ char buf[48]; name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf); + _thread_cap = _cpu_session->create_thread(0, buf); /* assign thread to protection domain */ env()->pd_session()->bind_thread(_thread_cap); diff --git a/repos/base-codezero/src/core/include/platform_thread.h b/repos/base-codezero/src/core/include/platform_thread.h index f9c8cf27c..5b2b12ddd 100644 --- a/repos/base-codezero/src/core/include/platform_thread.h +++ b/repos/base-codezero/src/core/include/platform_thread.h @@ -60,7 +60,7 @@ namespace Genode { /** * Constructor */ - Platform_thread(const char *name = 0, unsigned priority = 0, + Platform_thread(size_t, const char *name = 0, unsigned priority = 0, addr_t utcb = 0, int thread_id = THREAD_INVALID); /** diff --git a/repos/base-codezero/src/core/platform_thread.cc b/repos/base-codezero/src/core/platform_thread.cc index b4e377784..515e82654 100644 --- a/repos/base-codezero/src/core/platform_thread.cc +++ b/repos/base-codezero/src/core/platform_thread.cc @@ -98,7 +98,7 @@ Weak_ptr Platform_thread::address_space() } -Platform_thread::Platform_thread(const char *name, unsigned, addr_t, +Platform_thread::Platform_thread(size_t, const char *name, unsigned, addr_t, int thread_id) : _tid(THREAD_INVALID) { diff --git a/repos/base-codezero/src/core/thread_start.cc b/repos/base-codezero/src/core/thread_start.cc index dc45ffcb5..f09341e83 100644 --- a/repos/base-codezero/src/core/thread_start.cc +++ b/repos/base-codezero/src/core/thread_start.cc @@ -98,7 +98,8 @@ void Thread_base::_thread_start() void Thread_base::start() { /* create and start platform thread */ - _tid.pt = new(platform()->core_mem_alloc()) Platform_thread(_context->name); + _tid.pt = new(platform()->core_mem_alloc()) + Platform_thread(0, _context->name); _tid.l4id = create_thread(1, stack_top(), (void *)&_thread_start); diff --git a/repos/base-fiasco/src/base/thread/thread_bootstrap.cc b/repos/base-fiasco/src/base/thread/thread_bootstrap.cc index d100895ed..8da83a2aa 100644 --- a/repos/base-fiasco/src/base/thread/thread_bootstrap.cc +++ b/repos/base-fiasco/src/base/thread/thread_bootstrap.cc @@ -34,7 +34,7 @@ void prepare_reinit_main_thread() { } void Thread_base::_thread_bootstrap() { } -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { if (type == NORMAL) { return; } _thread_cap = Genode::env()->parent()->main_thread_cap(); diff --git a/repos/base-fiasco/src/core/include/platform_thread.h b/repos/base-fiasco/src/core/include/platform_thread.h index 762d1f9f6..cae41e725 100644 --- a/repos/base-fiasco/src/core/include/platform_thread.h +++ b/repos/base-fiasco/src/core/include/platform_thread.h @@ -53,7 +53,7 @@ namespace Genode { /** * Constructor */ - Platform_thread(const char *name = 0, unsigned priority = 0, + Platform_thread(size_t, const char *name = 0, unsigned priority = 0, addr_t utcb = 0, int thread_id = THREAD_INVALID); /** diff --git a/repos/base-fiasco/src/core/platform.cc b/repos/base-fiasco/src/core/platform.cc index 53105239e..dcbaeda48 100644 --- a/repos/base-fiasco/src/core/platform.cc +++ b/repos/base-fiasco/src/core/platform.cc @@ -145,7 +145,7 @@ Platform::Sigma0 *Platform::sigma0() Platform::Core_pager::Core_pager(Platform_pd *core_pd) : - Platform_thread("core.pager"), Pager_object(0, Affinity::Location()) + Platform_thread(0, "core.pager"), Pager_object(0, Affinity::Location()) { Platform_thread::pager(sigma0()); @@ -496,7 +496,8 @@ Platform::Platform() : * We setup the thread object for thread0 in core pd using a special * interface that allows us to specify the lthread number. */ - Platform_thread *core_thread = new(core_mem_alloc()) Platform_thread("core.main", myself.id.lthread); + Platform_thread *core_thread = new(core_mem_alloc()) + Platform_thread(0, "core.main", myself.id.lthread); core_thread->pager(sigma0()); _core_pd->bind_thread(core_thread); diff --git a/repos/base-fiasco/src/core/platform_thread.cc b/repos/base-fiasco/src/core/platform_thread.cc index a684469ab..ba9b611c8 100644 --- a/repos/base-fiasco/src/core/platform_thread.cc +++ b/repos/base-fiasco/src/core/platform_thread.cc @@ -151,7 +151,8 @@ Weak_ptr Platform_thread::address_space() } -Platform_thread::Platform_thread(const char *name, unsigned, addr_t, int thread_id) +Platform_thread::Platform_thread(size_t, const char *name, unsigned, addr_t, + int thread_id) : _thread_id(thread_id), _l4_thread_id(L4_INVALID_ID), _pager(0) { strncpy(_name, name, sizeof(_name)); diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index 666edb8f9..60712f63d 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -34,7 +34,8 @@ void Thread_base::_thread_start() void Thread_base::start() { /* create and start platform thread */ - _tid.pt = new(platform()->core_mem_alloc()) Platform_thread(_context->name); + _tid.pt = new(platform()->core_mem_alloc()) + Platform_thread(0, _context->name); platform_specific()->core_pd()->bind_thread(_tid.pt); diff --git a/repos/base-foc/include/foc_cpu_session/client.h b/repos/base-foc/include/foc_cpu_session/client.h index 98168f34d..fe39bf211 100644 --- a/repos/base-foc/include/foc_cpu_session/client.h +++ b/repos/base-foc/include/foc_cpu_session/client.h @@ -25,8 +25,8 @@ namespace Genode { explicit Foc_cpu_session_client(Cpu_session_capability session) : Rpc_client(static_cap_cast(session)) { } - Thread_capability create_thread(Name const &name, addr_t utcb = 0) { - return call(name, utcb); } + Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) { + return call(0, name, utcb); } Ram_dataspace_capability utcb(Thread_capability thread) { return call(thread); } @@ -93,6 +93,16 @@ namespace Genode { Native_capability alloc_irq() { return call(); } + + int ref_account(Cpu_session_capability session) { + return call(session); } + + int transfer_quota(Cpu_session_capability session, size_t amount) { + return call(session, amount); } + + size_t quota() { return call(); } + + size_t used() { return call(); } }; } diff --git a/repos/base-foc/src/base/thread/thread.cc b/repos/base-foc/src/base/thread/thread.cc index 9fbbdb746..5ccf4544c 100644 --- a/repos/base-foc/src/base/thread/thread.cc +++ b/repos/base-foc/src/base/thread/thread.cc @@ -186,8 +186,8 @@ void Thread_base::free_secondary_stack(void* stack_addr) } -Thread_base::Thread_base(const char *name, size_t stack_size, Type const type, - Cpu_session *cpu_session) +Thread_base::Thread_base(size_t, const char *name, size_t stack_size, + Type const type, Cpu_session *cpu_session) : _cpu_session(cpu_session), _context(type == REINITIALIZED_MAIN ? @@ -195,12 +195,13 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type const type, _join_lock(Lock::LOCKED) { strncpy(_context->name, name, sizeof(_context->name)); - _init_platform_thread(type); + _init_platform_thread(0, type); } -Thread_base::Thread_base(const char *name, size_t stack_size, Type type) -: Thread_base(name, stack_size, type, nullptr) { } +Thread_base::Thread_base(size_t, const char *name, size_t stack_size, + Type type) +: Thread_base(0, name, stack_size, type, nullptr) { } Thread_base::~Thread_base() diff --git a/repos/base-foc/src/base/thread/thread_start.cc b/repos/base-foc/src/base/thread/thread_start.cc index bf388a5d6..5bfa10a35 100644 --- a/repos/base-foc/src/base/thread/thread_start.cc +++ b/repos/base-foc/src/base/thread/thread_start.cc @@ -39,7 +39,7 @@ void Thread_base::_deinit_platform_thread() } -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { /* if no cpu session is given, use it from the environment */ if (!_cpu_session) @@ -50,7 +50,7 @@ void Thread_base::_init_platform_thread(Type type) /* create thread at core */ char buf[48]; name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf); + _thread_cap = _cpu_session->create_thread(0, buf); /* assign thread to protection domain */ env()->pd_session()->bind_thread(_thread_cap); diff --git a/repos/base-foc/src/core/include/cpu_session_component.h b/repos/base-foc/src/core/include/cpu_session_component.h index 588b972b4..3ab17ca59 100644 --- a/repos/base-foc/src/core/include/cpu_session_component.h +++ b/repos/base-foc/src/core/include/cpu_session_component.h @@ -64,7 +64,7 @@ namespace Genode { public: - Cpu_thread_component(Session_label const &label, + Cpu_thread_component(size_t, Session_label const &label, Thread_name const &name, unsigned priority, addr_t utcb, Signal_context_capability sigh, @@ -88,6 +88,7 @@ namespace Genode { bool bound() const { return _bound; } void bound(bool b) { _bound = b; } Trace::Source *trace_source() { return &_trace_source; } + size_t quota() { return 0; } void sigh(Signal_context_capability sigh) { @@ -122,6 +123,7 @@ namespace Genode { typedef Tslab Cpu_thread_allocator; Session_label _label; + Rpc_entrypoint *_session_ep; Rpc_entrypoint *_thread_ep; Pager_entrypoint *_pager_ep; Allocator_guard _md_alloc; /* guarded meta-data allocator */ @@ -136,6 +138,24 @@ namespace Genode { session */ Trace::Source_registry &_trace_sources; Trace::Control_area _trace_control_area; + Cpu_session_component * _ref; + size_t _used; + size_t _quota; + List _ref_members; + Lock _ref_members_lock; + + size_t _global_to_local(size_t const q) const { return 0; } + size_t _avail() { return 0; } + void _deinit_ref_account(); + void _deinit_threads(); + size_t _local_to_global(size_t) const { return 0; } + void _insuff_for_consume(size_t); + int _insuff_for_transfer(size_t); + int _transfer_back(size_t) { return -1; } + int _transfer_forth(Cpu_session_component *, size_t) { return -1; } + void _insert_ref_member(Cpu_session_component *) { } + void _remove_ref_member(Cpu_session_component *) { } + void _unsync_remove_ref_member(Cpu_session_component *) { } /** * Exception handler that will be invoked unless overridden by a @@ -158,11 +178,13 @@ namespace Genode { /** * Constructor */ - Cpu_session_component(Rpc_entrypoint *thread_ep, + Cpu_session_component(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, Pager_entrypoint *pager_ep, Allocator *md_alloc, Trace::Source_registry &trace_sources, - const char *args, Affinity const &affinity); + const char *args, Affinity const &affinity, + size_t quota); /** * Destructor @@ -179,7 +201,7 @@ namespace Genode { ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t); + Thread_capability create_thread(size_t, Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); Thread_capability first(); @@ -200,6 +222,10 @@ namespace Genode { unsigned trace_control_index(Thread_capability); Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_policy(Thread_capability); + int ref_account(Cpu_session_capability c); + int transfer_quota(Cpu_session_capability c, size_t q); + size_t used(); + size_t quota(); /*********************************** diff --git a/repos/base-foc/src/core/thread_start.cc b/repos/base-foc/src/core/thread_start.cc index efbafe02c..ad678c20d 100644 --- a/repos/base-foc/src/core/thread_start.cc +++ b/repos/base-foc/src/core/thread_start.cc @@ -35,7 +35,7 @@ void Thread_base::_deinit_platform_thread() } -void Thread_base::_init_platform_thread(Type) { } +void Thread_base::_init_platform_thread(size_t, Type) { } void Thread_base::start() diff --git a/repos/base-host/src/core/thread_host.cc b/repos/base-host/src/core/thread_host.cc index 7bad8451f..b4ce5f7c6 100644 --- a/repos/base-host/src/core/thread_host.cc +++ b/repos/base-host/src/core/thread_host.cc @@ -17,7 +17,7 @@ using namespace Genode; -void Thread_base::_init_platform_thread() { } +void Thread_base::_init_platform_thread(size_t, Type) { } void Thread_base::_deinit_platform_thread() { } void Thread_base::start() { } void Thread_base::cancel_blocking() { } diff --git a/repos/base-hw/run/cpu_quota.run b/repos/base-hw/run/cpu_quota.run new file mode 100644 index 000000000..0834edd61 --- /dev/null +++ b/repos/base-hw/run/cpu_quota.run @@ -0,0 +1,161 @@ +# +# Build +# + +build "core init drivers/timer test/cpu_quota" + +# +# Boot image +# + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +build_boot_image "core init timer test-cpu_quota" + +# +# Execution +# + +append qemu_args "-nographic -m 64" + +run_genode_until "test.*\n.*test.*\n.*test.*\n" 60 + +# +# Conclusion +# + +set slow_opt 0.10 +set middle_opt 0.25 +set fast_opt 0.65 +set err 0.02 + +regexp {[0-9]+} [regexp -inline {slow.*[0-9]+} $output] slow_cnt +regexp {[0-9]+} [regexp -inline {middle.*[0-9]+} $output] middle_cnt +regexp {[0-9]+} [regexp -inline {fast.*[0-9]+} $output] fast_cnt +set total_cnt [expr $fast_cnt + $middle_cnt + $slow_cnt] + +set slow_fac [expr $slow_cnt / double($total_cnt) ] +set middle_fac [expr $middle_cnt / double($total_cnt) ] +set fast_fac [expr $fast_cnt / double($total_cnt) ] + +set failed 0 +if {[expr $slow_fac > $slow_opt + $err || $slow_fac < $slow_opt - $err]} { + set is_pc [expr round($slow_fac * 10000) / 100] + set opt_pc [expr round($slow_opt * 10000) / 100] + puts stderr "Error: Slow counter received $is_pc% of the CPU time." + puts stderr " Should receive $opt_pc%." + set failed 1 +} +if {[expr $middle_fac > $middle_opt + $err || $middle_fac < $middle_opt - $err]} { + set is_pc [expr round($middle_fac * 10000) / 100] + set opt_pc [expr round($middle_opt * 10000) / 100] + puts stderr "Error: Middle counter received $is_pc% of the CPU time." + puts stderr " Should receive $opt_pc%." + set failed 1 +} +if {[expr $fast_fac > $fast_opt + $err || $fast_fac < $fast_opt - $err]} { + set is_pc [expr round($fast_fac * 10000) / 100] + set opt_pc [expr round($fast_opt * 10000) / 100] + puts stderr "Error: Fast counter received $is_pc% of the CPU time." + puts stderr " Should receive $opt_pc%." + set failed 1 +} +if {$failed} { + exit -1 +} else { + puts "Test succeeded" +} diff --git a/repos/base-hw/src/base/thread/start.cc b/repos/base-hw/src/base/thread/start.cc index 8d8f9ffef..7b1cdccc5 100644 --- a/repos/base-hw/src/base/thread/start.cc +++ b/repos/base-hw/src/base/thread/start.cc @@ -36,7 +36,7 @@ Native_utcb * main_thread_utcb() { return UTCB_MAIN_THREAD; } ** Thread_base ** *****************/ -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t quota, Type type) { if (!_cpu_session) { _cpu_session = env()->cpu_session(); } if (type == NORMAL) { @@ -44,7 +44,7 @@ void Thread_base::_init_platform_thread(Type type) /* create server object */ char buf[48]; name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb); + _thread_cap = _cpu_session->create_thread(quota, buf, (addr_t)&_context->utcb); return; } /* if we got reinitialized we have to get rid of the old UTCB */ diff --git a/repos/base-hw/src/core/include/kernel/core_interface.h b/repos/base-hw/src/core/include/kernel/core_interface.h index d11792a75..31f3377ed 100644 --- a/repos/base-hw/src/core/include/kernel/core_interface.h +++ b/repos/base-hw/src/core/include/kernel/core_interface.h @@ -98,16 +98,17 @@ namespace Kernel * * \param p memory donation for the new kernel thread object * \param priority scheduling priority of the new thread + * \param quota CPU-time quota of the new thread in milliseconds * \param label debugging label of the new thread * * \retval >0 kernel name of the new thread * \retval 0 failed */ inline unsigned new_thread(void * const p, unsigned const priority, - char const * const label) + size_t const quota, char const * const label) { return call(call_id_new_thread(), (Call_arg)p, (Call_arg)priority, - (Call_arg)label); + (Call_arg)quota, (Call_arg)label); } diff --git a/repos/base-hw/src/core/include/kernel/cpu.h b/repos/base-hw/src/core/include/kernel/cpu.h index fcc72165b..a4405bf8d 100644 --- a/repos/base-hw/src/core/include/kernel/cpu.h +++ b/repos/base-hw/src/core/include/kernel/cpu.h @@ -136,9 +136,10 @@ class Kernel::Cpu_job : public Cpu_share virtual void proceed(unsigned const id) = 0; /** - * Construct a job with scheduling priority 'p' + * Construct a job with scheduling priority 'p' and time quota 'q' */ - Cpu_job(Cpu_priority const p) : Cpu_share(p, 0), _cpu(0) { } + Cpu_job(Cpu_priority const p, unsigned const q) + : Cpu_share(p, q), _cpu(0) { } /** * Destructor @@ -313,6 +314,12 @@ class Kernel::Cpu_pool * Return object of primary CPU */ Cpu * primary_cpu() const { return cpu(Cpu::primary_id()); } + + /* + * Accessors + */ + + Timer * timer() { return &_timer; } }; #endif /* _KERNEL__CPU_H_ */ diff --git a/repos/base-hw/src/core/include/kernel/thread.h b/repos/base-hw/src/core/include/kernel/thread.h index 64bfe5573..114995858 100644 --- a/repos/base-hw/src/core/include/kernel/thread.h +++ b/repos/base-hw/src/core/include/kernel/thread.h @@ -270,9 +270,11 @@ class Kernel::Thread * Constructor * * \param priority scheduling priority + * \param quota CPU-time quota * \param label debugging label */ - Thread(unsigned const priority, char const * const label); + Thread(unsigned const priority, unsigned const quota, + char const * const label); /** * Prepare thread to get scheduled the first time diff --git a/repos/base-hw/src/core/include/kernel/vm.h b/repos/base-hw/src/core/include/kernel/vm.h index 0aecc13f0..f376095ee 100644 --- a/repos/base-hw/src/core/include/kernel/vm.h +++ b/repos/base-hw/src/core/include/kernel/vm.h @@ -59,7 +59,7 @@ class Kernel::Vm : public Object, */ Vm(void * const state, Signal_context * const context) : - Cpu_job(Cpu_priority::min), _state((Vm_state * const)state), + Cpu_job(Cpu_priority::min, 0), _state((Vm_state * const)state), _context(context) { affinity(cpu_pool()->primary_cpu()); } diff --git a/repos/base-hw/src/core/include/platform_thread.h b/repos/base-hw/src/core/include/platform_thread.h index e56e823d0..b1c8919bf 100644 --- a/repos/base-hw/src/core/include/platform_thread.h +++ b/repos/base-hw/src/core/include/platform_thread.h @@ -75,6 +75,12 @@ namespace Genode { */ bool _attaches_utcb_by_itself(); + static size_t _generic_to_platform_quota(size_t const q) + { + assert(Kernel::cpu_quota_ms <= Cpu_session::QUOTA_LIMIT); + return (q * Kernel::cpu_quota_ms) >> 15; + } + public: /** @@ -88,12 +94,13 @@ namespace Genode { /** * Constructor for threads outside of core * + * \param quota CPU quota that shall be granted to the thread * \param label debugging label * \param virt_prio unscaled processor-scheduling priority * \param utcb core local pointer to userland thread-context */ - Platform_thread(const char * const label, unsigned const virt_prio, - addr_t const utcb); + Platform_thread(size_t const quota, const char * const label, + unsigned const virt_prio, addr_t const utcb); /** * Destructor diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 18c7feb14..9119be291 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -120,7 +120,7 @@ void Cpu_job::affinity(Cpu * const cpu) ** Cpu_idle ** **************/ -Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::min) +Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::min, 0) { Cpu_job::cpu(cpu); cpu_exception = RESET; diff --git a/repos/base-hw/src/core/kernel/kernel.cc b/repos/base-hw/src/core/kernel/kernel.cc index c18c844a0..7fa71c73e 100644 --- a/repos/base-hw/src/core/kernel/kernel.cc +++ b/repos/base-hw/src/core/kernel/kernel.cc @@ -253,7 +253,7 @@ void init_kernel_mp_primary() /* start thread with stack pointer at the top of stack */ static Native_utcb utcb; - static Thread t(Cpu_priority::max, "core"); + static Thread t(Cpu_priority::max, 0, "core"); _main_thread_id = t.id(); _main_thread_utcb = &utcb; _main_thread_utcb->start_info()->init(t.id(), Genode::Native_capability()); diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index a47d9afa3..3a38e339e 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -145,9 +145,10 @@ void Thread::_unschedule(State const s) } -Thread::Thread(unsigned const priority, char const * const label) +Thread::Thread(unsigned const priority, unsigned const quota, + char const * const label) : - Cpu_job(priority), Thread_base(this), _state(AWAITS_START), _pd(0), + Cpu_job(priority, quota), Thread_base(this), _state(AWAITS_START), _pd(0), _utcb_phys(0), _signal_receiver(0), _label(label) { cpu_exception = RESET; } @@ -268,8 +269,9 @@ void Thread::_call_new_thread() /* create new thread */ void * const p = (void *)user_arg_1(); unsigned const priority = user_arg_2(); - char const * const label = (char *)user_arg_3(); - Thread * const t = new (p) Thread(priority, label); + unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_3()); + char const * const label = (char *)user_arg_4(); + Thread * const t = new (p) Thread(priority, quota, label); user_arg_0(t->id()); } diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc index c125909f3..9cd4fcef4 100644 --- a/repos/base-hw/src/core/pager.cc +++ b/repos/base-hw/src/core/pager.cc @@ -92,7 +92,7 @@ void Pager_activation_base::ep(Pager_entrypoint * const ep) { _ep = ep; } Pager_activation_base::Pager_activation_base(char const * const name, size_t const stack_size) : - Thread_base(name, stack_size), _cap_valid(Lock::LOCKED), _ep(0) + Thread_base(0, name, stack_size), _cap_valid(Lock::LOCKED), _ep(0) { } diff --git a/repos/base-hw/src/core/platform_thread.cc b/repos/base-hw/src/core/platform_thread.cc index fc7b4c0fd..b6511c207 100644 --- a/repos/base-hw/src/core/platform_thread.cc +++ b/repos/base-hw/src/core/platform_thread.cc @@ -102,7 +102,7 @@ Platform_thread::Platform_thread(const char * const label, /* create kernel object */ constexpr unsigned prio = Kernel::Cpu_priority::max; - _id = Kernel::new_thread(_kernel_thread, prio, _label); + _id = Kernel::new_thread(_kernel_thread, prio, 0, _label); if (!_id) { PERR("failed to create kernel object"); throw Cpu_session::Thread_creation_failed(); @@ -110,7 +110,7 @@ Platform_thread::Platform_thread(const char * const label, } -Platform_thread::Platform_thread(const char * const label, +Platform_thread::Platform_thread(size_t quota, const char * const label, unsigned const virt_prio, addr_t const utcb) : @@ -139,7 +139,8 @@ Platform_thread::Platform_thread(const char * const label, /* create kernel object */ constexpr unsigned max_prio = Kernel::Cpu_priority::max; auto const phys_prio = Cpu_session::scale_priority(max_prio, virt_prio); - _id = Kernel::new_thread(_kernel_thread, phys_prio, _label); + quota = _generic_to_platform_quota(quota); + _id = Kernel::new_thread(_kernel_thread, phys_prio, quota, _label); if (!_id) { PERR("failed to create kernel object"); throw Cpu_session::Thread_creation_failed(); diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index e543c8e4f..cc2b7ea7e 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -50,7 +50,7 @@ void Thread_base::_deinit_platform_thread() } -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { /* create platform thread */ _tid.platform_thread = new (platform()->core_mem_alloc()) diff --git a/repos/base-hw/src/test/cpu_quota/main.cc b/repos/base-hw/src/test/cpu_quota/main.cc new file mode 100644 index 000000000..4dca62db2 --- /dev/null +++ b/repos/base-hw/src/test/cpu_quota/main.cc @@ -0,0 +1,63 @@ +/* + * \brief Diversified test of the Register and MMIO framework + * \author Martin Stein + * \date 2012-01-09 + */ + +/* + * Copyright (C) 2012-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +using namespace Genode; + +class My_thread : public Thread<8 * 1024> +{ + private: + + Signal_receiver * const _sigr; + bool volatile _stop; + + public: + + My_thread(Signal_receiver * const sigr) + : Thread(Cpu_session::pc_to_quota(100), "counter"), + _sigr(sigr), _stop(0) { } + + void entry() + { + _sigr->wait_for_signal(); + unsigned volatile i = 0; + while(!_stop) { i++; } + printf("%u\n", i); + sleep_forever(); + } + + void stop() { _stop = 1; } +}; + +int main() +{ + Timer::Connection timer; + Signal_receiver sigr; + Signal_context sigx; + Signal_context_capability sigc = sigr.manage(&sigx); + Signal_transmitter sigt(sigc); + My_thread thread(&sigr); + thread.start(); + timer.msleep(3000); + sigt.submit(); + timer.msleep(30000); + thread.stop(); + sleep_forever(); +} + diff --git a/repos/base-hw/src/test/cpu_quota/target.mk b/repos/base-hw/src/test/cpu_quota/target.mk new file mode 100644 index 000000000..f0d82308d --- /dev/null +++ b/repos/base-hw/src/test/cpu_quota/target.mk @@ -0,0 +1,14 @@ +# +# \brief Test static configuration of CPU-time distribution +# \author Martin Stein +# \date 2014-10-13 +# + +# Set program name +TARGET = test-cpu_quota + +# Add C++ sources +SRC_CC += main.cc + +# Add libraries +LIBS += base diff --git a/repos/base-linux/include/linux_cpu_session/client.h b/repos/base-linux/include/linux_cpu_session/client.h index bf827b0f0..a957e3893 100644 --- a/repos/base-linux/include/linux_cpu_session/client.h +++ b/repos/base-linux/include/linux_cpu_session/client.h @@ -24,8 +24,8 @@ namespace Genode { explicit Linux_cpu_session_client(Capability session) : Rpc_client(session) { } - Thread_capability create_thread(Name const &name, addr_t utcb = 0) { - return call(name, utcb); } + Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) { + return call(0, name, utcb); } Ram_dataspace_capability utcb(Thread_capability thread) { return call(thread); } @@ -78,6 +78,15 @@ namespace Genode { Dataspace_capability trace_policy(Thread_capability thread) { return call(thread); } + int ref_account(Cpu_session_capability session) { + return call(session); } + + int transfer_quota(Cpu_session_capability session, size_t amount) { + return call(session, amount); } + + size_t quota() { return call(); } + + size_t used() { return call(); } /***************************** * Linux-specific extension ** diff --git a/repos/base-linux/src/base/env/platform_env.h b/repos/base-linux/src/base/env/platform_env.h index 7d3a18978..ca8f2ce3b 100644 --- a/repos/base-linux/src/base/env/platform_env.h +++ b/repos/base-linux/src/base/env/platform_env.h @@ -43,10 +43,10 @@ struct Genode::Expanding_cpu_session_client Expanding_cpu_session_client(Genode::Capability cap) : Upgradeable_client(cap) { } - Thread_capability create_thread(Name const &name, addr_t utcb) + Thread_capability create_thread(size_t, Name const &name, addr_t utcb) { return retry( - [&] () { return Linux_cpu_session_client::create_thread(name, utcb); }, + [&] () { return Linux_cpu_session_client::create_thread(0, name, utcb); }, [&] () { upgrade_ram(8*1024); }); } }; diff --git a/repos/base-linux/src/base/process/process.cc b/repos/base-linux/src/base/process/process.cc index 06866b380..0bc54601a 100644 --- a/repos/base-linux/src/base/process/process.cc +++ b/repos/base-linux/src/base/process/process.cc @@ -80,7 +80,7 @@ Process::Process(Dataspace_capability elf_data_ds_cap, * thread. Those information will be provided to core by the constructor of * the 'Platform_env' of the new process. */ - _thread0_cap = _cpu_session_client.create_thread(name); + _thread0_cap = _cpu_session_client.create_thread(0, name); Linux_pd_session_client lx_pd(static_cap_cast(_pd.cap())); diff --git a/repos/base-linux/src/base/thread/thread_linux.cc b/repos/base-linux/src/base/thread/thread_linux.cc index 40678bc16..d1d3fd535 100644 --- a/repos/base-linux/src/base/thread/thread_linux.cc +++ b/repos/base-linux/src/base/thread/thread_linux.cc @@ -69,7 +69,7 @@ void Thread_base::_thread_start() } -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { /* if no cpu session is given, use it from the environment */ if (!_cpu_session) @@ -77,7 +77,7 @@ void Thread_base::_init_platform_thread(Type type) /* for normal threads create an object at the CPU session */ if (type == NORMAL) { - _thread_cap = _cpu_session->create_thread(_context->name); + _thread_cap = _cpu_session->create_thread(0, _context->name); return; } /* adjust initial object state for main threads */ diff --git a/repos/base-linux/src/core/include/cpu_session_component.h b/repos/base-linux/src/core/include/cpu_session_component.h index a3973c477..51206d30c 100644 --- a/repos/base-linux/src/core/include/cpu_session_component.h +++ b/repos/base-linux/src/core/include/cpu_session_component.h @@ -63,7 +63,7 @@ namespace Genode { public: - Cpu_thread_component(Session_label const &label, + Cpu_thread_component(size_t, Session_label const &label, Thread_name const &name, unsigned priority, addr_t utcb, Signal_context_capability sigh, @@ -87,6 +87,7 @@ namespace Genode { bool bound() const { return _bound; } void bound(bool b) { _bound = b; } Trace::Source *trace_source() { return &_trace_source; } + size_t quota() { return 0; } void sigh(Signal_context_capability sigh) { @@ -115,6 +116,7 @@ namespace Genode { private: Session_label _label; + Rpc_entrypoint *_session_ep; Rpc_entrypoint *_thread_ep; Pager_entrypoint *_pager_ep; Allocator_guard _md_alloc; /* guarded meta-data allocator */ @@ -129,6 +131,24 @@ namespace Genode { session */ Trace::Source_registry &_trace_sources; Trace::Control_area _trace_control_area; + Cpu_session_component * _ref; + size_t _used; + size_t _quota; + List _ref_members; + Lock _ref_members_lock; + + size_t _global_to_local(size_t const q) const { return 0; } + size_t _avail() { return 0; } + void _deinit_ref_account(); + void _deinit_threads(); + size_t _local_to_global(size_t) const { return 0; } + void _insuff_for_consume(size_t); + int _insuff_for_transfer(size_t); + int _transfer_back(size_t) { return -1; } + int _transfer_forth(Cpu_session_component *, size_t) { return -1; } + void _insert_ref_member(Cpu_session_component *) { } + void _remove_ref_member(Cpu_session_component *) { } + void _unsync_remove_ref_member(Cpu_session_component *) { } /** * Exception handler that will be invoked unless overridden by a @@ -151,11 +171,13 @@ namespace Genode { /** * Constructor */ - Cpu_session_component(Rpc_entrypoint *thread_ep, + Cpu_session_component(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, Pager_entrypoint *pager_ep, Allocator *md_alloc, Trace::Source_registry &trace_sources, - const char *args, Affinity const &affinity); + const char *args, Affinity const &affinity, + size_t quota); /** * Destructor @@ -172,7 +194,7 @@ namespace Genode { ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t); + Thread_capability create_thread(size_t, Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); int set_pager(Thread_capability, Pager_capability); @@ -190,6 +212,10 @@ namespace Genode { unsigned trace_control_index(Thread_capability); Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_policy(Thread_capability); + int ref_account(Cpu_session_capability c); + int transfer_quota(Cpu_session_capability c, size_t q); + size_t used(); + size_t quota(); /******************************* diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index b4ae6dd45..4e5c248b3 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -46,7 +46,7 @@ void Thread_base::_thread_start() } -void Thread_base::_init_platform_thread(Type) { } +void Thread_base::_init_platform_thread(size_t, Type) { } void Thread_base::_deinit_platform_thread() { } diff --git a/repos/base-linux/src/platform/lx_hybrid.cc b/repos/base-linux/src/platform/lx_hybrid.cc index 6684d8a80..b13a24b40 100644 --- a/repos/base-linux/src/platform/lx_hybrid.cc +++ b/repos/base-linux/src/platform/lx_hybrid.cc @@ -401,8 +401,8 @@ void Thread_base::join() } -Thread_base::Thread_base(const char *name, size_t stack_size, Type type, - Cpu_session * cpu_sess) +Thread_base::Thread_base(size_t, const char *name, size_t stack_size, + Type type, Cpu_session * cpu_sess) : _cpu_session(cpu_sess) { _tid.meta_data = new (env()->heap()) Thread_meta_data_created(this); @@ -420,13 +420,13 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type type, Linux_cpu_session *cpu = cpu_session(_cpu_session); - _thread_cap = cpu->create_thread(name); + _thread_cap = cpu->create_thread(0, name); cpu->thread_id(_thread_cap, _tid.pid, _tid.tid); } -Thread_base::Thread_base(const char *name, size_t stack_size, Type type) -: Thread_base(name, stack_size, type, env()->cpu_session()) { } +Thread_base::Thread_base(size_t, const char *name, size_t stack_size, Type type) +: Thread_base(0, name, stack_size, type, env()->cpu_session()) { } void Thread_base::cancel_blocking() { diff --git a/repos/base-nova/include/cpu_session/client.h b/repos/base-nova/include/cpu_session/client.h index ad164a541..dad4e5425 100644 --- a/repos/base-nova/include/cpu_session/client.h +++ b/repos/base-nova/include/cpu_session/client.h @@ -28,8 +28,8 @@ namespace Genode { explicit Cpu_session_client(Cpu_session_capability session) : Rpc_client(static_cap_cast(session)) { } - Thread_capability create_thread(Name const &name, addr_t utcb = 0) { - return call(name, utcb); } + Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) { + return call(0, name, utcb); } Ram_dataspace_capability utcb(Thread_capability thread) { return call(thread); } @@ -88,6 +88,16 @@ namespace Genode { Dataspace_capability trace_policy(Thread_capability thread) { return call(thread); } + int ref_account(Cpu_session_capability session) { + return call(session); } + + int transfer_quota(Cpu_session_capability session, size_t amount) { + return call(session, amount); } + + size_t quota() { return call(); } + + size_t used() { return call(); } + private: Native_capability pause_sync(Thread_capability target) { diff --git a/repos/base-nova/src/base/pager/pager.cc b/repos/base-nova/src/base/pager/pager.cc index 68f9dac71..5af39a4e2 100644 --- a/repos/base-nova/src/base/pager/pager.cc +++ b/repos/base-nova/src/base/pager/pager.cc @@ -332,7 +332,7 @@ static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd, Pager_object::Pager_object(unsigned long badge, Affinity::Location location) : - Thread_base("pager:", PF_HANDLER_STACK_SIZE), + Thread_base(0, "pager:", PF_HANDLER_STACK_SIZE), _badge(reinterpret_cast(_context->name + 6)), _client_exc_vcpu(Native_thread::INVALID_INDEX) { diff --git a/repos/base-nova/src/base/server/server.cc b/repos/base-nova/src/base/server/server.cc index 9c8aa513c..c06e17a5f 100644 --- a/repos/base-nova/src/base/server/server.cc +++ b/repos/base-nova/src/base/server/server.cc @@ -195,7 +195,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size, const char *name, bool start_on_construction, Affinity::Location location) : - Thread_base(name, stack_size), + Thread_base(0, name, stack_size), _curr_obj(start_on_construction ? 0 : (Rpc_object_base *)~0UL), _delay_start(Lock::LOCKED), _cap_session(cap_session) diff --git a/repos/base-nova/src/base/thread/thread_nova.cc b/repos/base-nova/src/base/thread/thread_nova.cc index 941d834b6..45777efa8 100644 --- a/repos/base-nova/src/base/thread/thread_nova.cc +++ b/repos/base-nova/src/base/thread/thread_nova.cc @@ -65,7 +65,7 @@ void Thread_base::_thread_start() ** Thread base ** *****************/ -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { using namespace Nova; @@ -102,7 +102,7 @@ void Thread_base::_init_platform_thread(Type type) char buf[48]; name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf); + _thread_cap = _cpu_session->create_thread(0, buf); if (!_thread_cap.valid()) throw Cpu_session::Thread_creation_failed(); diff --git a/repos/base-nova/src/core/include/cpu_session_component.h b/repos/base-nova/src/core/include/cpu_session_component.h index 3d0897ba8..5b99bbaed 100644 --- a/repos/base-nova/src/core/include/cpu_session_component.h +++ b/repos/base-nova/src/core/include/cpu_session_component.h @@ -64,7 +64,7 @@ namespace Genode { public: - Cpu_thread_component(Session_label const &label, + Cpu_thread_component(size_t, Session_label const &label, Thread_name const &name, unsigned priority, addr_t utcb, Signal_context_capability sigh, @@ -88,6 +88,7 @@ namespace Genode { bool bound() const { return _bound; } void bound(bool b) { _bound = b; } Trace::Source *trace_source() { return &_trace_source; } + size_t quota() { return 0; } void sigh(Signal_context_capability sigh) { @@ -122,6 +123,7 @@ namespace Genode { typedef Tslab Cpu_thread_allocator; Session_label _label; + Rpc_entrypoint *_session_ep; Rpc_entrypoint *_thread_ep; Pager_entrypoint *_pager_ep; Allocator_guard _md_alloc; /* guarded meta-data allocator */ @@ -136,6 +138,24 @@ namespace Genode { session */ Trace::Source_registry &_trace_sources; Trace::Control_area _trace_control_area; + Cpu_session_component * _ref; + size_t _used; + size_t _quota; + List _ref_members; + Lock _ref_members_lock; + + size_t _global_to_local(size_t const q) const { return 0; } + size_t _avail() { return 0; } + void _deinit_ref_account(); + void _deinit_threads(); + size_t _local_to_global(size_t) const { return 0; } + void _insuff_for_consume(size_t); + int _insuff_for_transfer(size_t); + int _transfer_back(size_t) { return -1; } + int _transfer_forth(Cpu_session_component *, size_t) { return -1; } + void _insert_ref_member(Cpu_session_component *) { } + void _remove_ref_member(Cpu_session_component *) { } + void _unsync_remove_ref_member(Cpu_session_component *) { } /** * Exception handler that will be invoked unless overridden by a @@ -158,11 +178,13 @@ namespace Genode { /** * Constructor */ - Cpu_session_component(Rpc_entrypoint *thread_ep, + Cpu_session_component(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, Pager_entrypoint *pager_ep, Allocator *md_alloc, Trace::Source_registry &trace_sources, - const char *args, Affinity const &affinity); + const char *args, Affinity const &affinity, + size_t quota); /** * Destructor @@ -179,7 +201,7 @@ namespace Genode { ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t); + Thread_capability create_thread(size_t, Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); int set_pager(Thread_capability, Pager_capability); @@ -198,6 +220,10 @@ namespace Genode { unsigned trace_control_index(Thread_capability); Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_policy(Thread_capability); + int ref_account(Cpu_session_capability c); + int transfer_quota(Cpu_session_capability c, size_t q); + size_t used(); + size_t quota(); /****************************** diff --git a/repos/base-nova/src/core/irq_session_component.cc b/repos/base-nova/src/core/irq_session_component.cc index adf5f76f2..f63d93c01 100644 --- a/repos/base-nova/src/core/irq_session_component.cc +++ b/repos/base-nova/src/core/irq_session_component.cc @@ -49,7 +49,7 @@ class Irq_thread : public Thread_base public: - Irq_thread(char const *name) : Thread_base(name, 1024 * sizeof(addr_t)) { } + Irq_thread(char const *name) : Thread_base(0, name, 1024 * sizeof(addr_t)) { } /** * Create global EC, associate it to SC diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 51e9ad8f2..2de55ef7d 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -27,7 +27,7 @@ using namespace Genode; -void Thread_base::_init_platform_thread(Type type) +void Thread_base::_init_platform_thread(size_t, Type type) { /* * This function is called for constructing server activations and pager diff --git a/repos/base-okl4/src/base/thread/thread_bootstrap.cc b/repos/base-okl4/src/base/thread/thread_bootstrap.cc index b9996f936..fe03b53c0 100644 --- a/repos/base-okl4/src/base/thread/thread_bootstrap.cc +++ b/repos/base-okl4/src/base/thread/thread_bootstrap.cc @@ -79,7 +79,7 @@ void Genode::Thread_base::_thread_bootstrap() } -void Genode::Thread_base::_init_platform_thread(Type type) +void Genode::Thread_base::_init_platform_thread(size_t, Type type) { if (type == NORMAL) { return; } _tid.l4id.raw = main_thread_tid.raw; diff --git a/repos/base-okl4/src/core/include/platform_thread.h b/repos/base-okl4/src/core/include/platform_thread.h index 98b2b8192..066d6114f 100644 --- a/repos/base-okl4/src/core/include/platform_thread.h +++ b/repos/base-okl4/src/core/include/platform_thread.h @@ -48,7 +48,7 @@ namespace Genode { /** * Constructor */ - Platform_thread(const char *name = 0, + Platform_thread(size_t, const char *name = 0, unsigned priority = 0, addr_t utcb = 0, int thread_id = THREAD_INVALID); diff --git a/repos/base-okl4/src/core/platform.cc b/repos/base-okl4/src/core/platform.cc index 18a7b0211..a5f55c9bf 100644 --- a/repos/base-okl4/src/core/platform.cc +++ b/repos/base-okl4/src/core/platform.cc @@ -302,7 +302,7 @@ Platform::Platform() : * not destroy this task, it should be no problem. */ Platform_thread *core_thread = - new(&_thread_slab) Platform_thread("core.main"); + new(&_thread_slab) Platform_thread(0, "core.main"); core_thread->set_l4_thread_id(Okl4::L4_rootserver); diff --git a/repos/base-okl4/src/core/platform_thread.cc b/repos/base-okl4/src/core/platform_thread.cc index 47fe8ddd7..42f178184 100644 --- a/repos/base-okl4/src/core/platform_thread.cc +++ b/repos/base-okl4/src/core/platform_thread.cc @@ -178,7 +178,7 @@ Weak_ptr Platform_thread::address_space() } -Platform_thread::Platform_thread(const char *name, unsigned prio, addr_t, int thread_id) +Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, addr_t, int thread_id) : _thread_id(thread_id), _l4_thread_id(L4_nilthread), _platform_pd(0), _priority(prio), _pager(0) { diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index 5ecb37cf6..5f165260d 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -35,7 +35,7 @@ void Thread_base::start() { /* create and start platform thread */ _tid.pt = new(platform_specific()->thread_slab()) - Platform_thread(_context->name); + Platform_thread(0, _context->name); platform_specific()->core_pd()->bind_thread(_tid.pt); diff --git a/repos/base-pistachio/src/base/thread/thread_bootstrap.cc b/repos/base-pistachio/src/base/thread/thread_bootstrap.cc index f7da3caae..a9dd91768 100644 --- a/repos/base-pistachio/src/base/thread/thread_bootstrap.cc +++ b/repos/base-pistachio/src/base/thread/thread_bootstrap.cc @@ -46,7 +46,7 @@ void Genode::Thread_base::_thread_bootstrap() } -void Genode::Thread_base::_init_platform_thread(Type type) +void Genode::Thread_base::_init_platform_thread(size_t, Type type) { if (type == NORMAL) { return; } _tid.l4id = main_thread_tid; diff --git a/repos/base-pistachio/src/core/include/platform_thread.h b/repos/base-pistachio/src/core/include/platform_thread.h index ab67181a1..da9c9ef94 100644 --- a/repos/base-pistachio/src/core/include/platform_thread.h +++ b/repos/base-pistachio/src/core/include/platform_thread.h @@ -55,7 +55,7 @@ namespace Genode { /** * Constructor */ - Platform_thread(const char *name = 0, unsigned priority = 0, + Platform_thread(size_t, const char *name = 0, unsigned priority = 0, addr_t utcb = 0, int thread_id = THREAD_INVALID); /** diff --git a/repos/base-pistachio/src/core/platform.cc b/repos/base-pistachio/src/core/platform.cc index 07428a30a..9adb671a2 100644 --- a/repos/base-pistachio/src/core/platform.cc +++ b/repos/base-pistachio/src/core/platform.cc @@ -214,7 +214,7 @@ Platform::Sigma0 *Platform::sigma0() Platform::Core_pager::Core_pager(Platform_pd *core_pd) : - Platform_thread("core.pager"), Pager_object(0, Affinity::Location()) + Platform_thread(0, "core.pager"), Pager_object(0, Affinity::Location()) { Platform_thread::pager(sigma0()); @@ -665,7 +665,7 @@ Platform::Platform() : * thread_id of first task. But since we do not destroy this * task, it should be no problem. */ - static Platform_thread core_thread("core.main"); + static Platform_thread core_thread(0, "core.main"); core_thread.set_l4_thread_id(Pistachio::L4_MyGlobalId()); core_thread.pager(sigma0()); diff --git a/repos/base-pistachio/src/core/platform_thread.cc b/repos/base-pistachio/src/core/platform_thread.cc index ef31133ca..3274e5d35 100644 --- a/repos/base-pistachio/src/core/platform_thread.cc +++ b/repos/base-pistachio/src/core/platform_thread.cc @@ -243,7 +243,8 @@ Weak_ptr Platform_thread::address_space() } -Platform_thread::Platform_thread(const char *name, unsigned prio, addr_t, int id) +Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, + addr_t, int id) : _thread_id(id), _l4_thread_id(L4_nilthread), _priority(prio), _pager(0) { strncpy(_name, name, sizeof(_name)); diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index 666edb8f9..60712f63d 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -34,7 +34,8 @@ void Thread_base::_thread_start() void Thread_base::start() { /* create and start platform thread */ - _tid.pt = new(platform()->core_mem_alloc()) Platform_thread(_context->name); + _tid.pt = new(platform()->core_mem_alloc()) + Platform_thread(0, _context->name); platform_specific()->core_pd()->bind_thread(_tid.pt); diff --git a/repos/base/include/base/pager.h b/repos/base/include/base/pager.h index 6a0f4377b..7e987e895 100644 --- a/repos/base/include/base/pager.h +++ b/repos/base/include/base/pager.h @@ -136,7 +136,7 @@ namespace Genode { public: Pager_activation_base(const char *name, size_t stack_size) : - Thread_base(name, stack_size), + Thread_base(0, name, stack_size), _cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED) { } /** diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index bbfa99d95..b299d951e 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -326,15 +326,17 @@ namespace Genode { /** * Hook for platform-specific constructor supplements * - * \param main_thread whether this is the main thread + * \param quota CPU quota that shall be granted to the thread + * \param type enables selection of special initialization */ - void _init_platform_thread(Type type); + void _init_platform_thread(size_t quota, Type type); public: /** * Constructor * + * \param quota CPU quota that shall be granted to the thread * \param name thread name for debugging * \param stack_size stack size * \param type enables selection of special construction @@ -354,12 +356,13 @@ namespace Genode { * at least set Context::ds_cap in a way that it references * the dataspace of the already attached stack. */ - Thread_base(const char *name, size_t stack_size, + Thread_base(size_t quota, const char *name, size_t stack_size, Type type = NORMAL); /** * Constructor * + * \param quota CPU quota that shall be granted to the thread * \param name thread name for debugging * \param stack_size stack size * \param type enables selection of special construction @@ -369,8 +372,8 @@ namespace Genode { * \throw Stack_alloc_failed * \throw Context_alloc_failed */ - Thread_base(const char *name, size_t stack_size, Type type, - Cpu_session *); + Thread_base(size_t quota, const char *name, size_t stack_size, + Type type, Cpu_session *); /** * Destructor @@ -513,20 +516,36 @@ namespace Genode { /** * Constructor * - * \param name thread name (for debugging) - * \param type enables selection of special construction + * \param quota CPU quota that shall be granted to the thread + * \param name thread name (for debugging) + * \param type enables selection of special construction */ - explicit Thread(const char *name, Type type = NORMAL) - : Thread_base(name, STACK_SIZE, type) { } + explicit Thread(size_t quota, const char *name, Type type = NORMAL) + : Thread_base(quota, name, STACK_SIZE, type) { } /** * Constructor * + * \param quota CPU quota that shall be granted to the thread * \param name thread name (for debugging) * \param cpu_session thread created via specific cpu session */ + explicit Thread(size_t quota, const char *name, Cpu_session * cpu_session) + : Thread_base(quota, name, STACK_SIZE, Type::NORMAL, cpu_session) + { } + + /** + * Shortcut for 'Thread(0, name, type)' + */ + explicit Thread(const char *name, Type type = NORMAL) + : Thread_base(0, name, STACK_SIZE, type) { } + + /** + * Shortcut for 'Thread(0, name, cpu_session)' + */ explicit Thread(const char *name, Cpu_session * cpu_session) - : Thread_base(name, STACK_SIZE, Type::NORMAL, cpu_session) { } + : Thread_base(0, name, STACK_SIZE, Type::NORMAL, cpu_session) + { } }; } diff --git a/repos/base/include/cpu_session/capability.h b/repos/base/include/cpu_session/capability.h index 4f68a87b9..dc51053e6 100644 --- a/repos/base/include/cpu_session/capability.h +++ b/repos/base/include/cpu_session/capability.h @@ -15,8 +15,11 @@ #define _INCLUDE__CPU_SESSION__CAPABILITY_H_ #include -#include -namespace Genode { typedef Capability Cpu_session_capability; } +namespace Genode +{ + class Cpu_session; + typedef Capability Cpu_session_capability; +} #endif /* _INCLUDE__CPU_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/cpu_session/client.h b/repos/base/include/cpu_session/client.h index a50222905..11260f4d5 100644 --- a/repos/base/include/cpu_session/client.h +++ b/repos/base/include/cpu_session/client.h @@ -24,8 +24,9 @@ namespace Genode { explicit Cpu_session_client(Cpu_session_capability session) : Rpc_client(session) { } - Thread_capability create_thread(Name const &name, addr_t utcb = 0) { - return call(name, utcb); } + Thread_capability + create_thread(size_t quota, Name const &name, addr_t utcb = 0) { + return call(quota, name, utcb); } Ram_dataspace_capability utcb(Thread_capability thread) { return call(thread); } @@ -77,6 +78,16 @@ namespace Genode { Dataspace_capability trace_policy(Thread_capability thread) { return call(thread); } + + int ref_account(Cpu_session_capability session) { + return call(session); } + + int transfer_quota(Cpu_session_capability session, size_t amount) { + return call(session, amount); } + + size_t quota() { return call(); } + + size_t used() { return call(); } }; } diff --git a/repos/base/include/cpu_session/cpu_session.h b/repos/base/include/cpu_session/cpu_session.h index c6f3e807b..e452594e8 100644 --- a/repos/base/include/cpu_session/cpu_session.h +++ b/repos/base/include/cpu_session/cpu_session.h @@ -29,6 +29,7 @@ #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_ #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_ +#include #include #include #include @@ -50,12 +51,15 @@ namespace Genode { class Thread_creation_failed : public Exception { }; class State_access_failed : public Exception { }; + class Quota_exceeded : public Thread_creation_failed { }; class Out_of_metadata : public Exception { }; static const char *service_name() { return "CPU"; } enum { THREAD_NAME_LEN = 48 }; enum { PRIORITY_LIMIT = 1 << 16 }; + enum { QUOTA_LIMIT_LOG2 = 15 }; + enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 }; enum { DEFAULT_PRIORITY = 0 }; typedef Rpc_in_buffer Name; @@ -65,13 +69,16 @@ namespace Genode { /** * Create a new thread * - * \param name name for the thread - * \param utcb Base of the UTCB that will be used by the thread - * \return capability representing the new thread - * \throw Thread_creation_failed - * \throw Out_of_metadata + * \param quota CPU quota that shall be granted to the thread + * \param name name for the thread + * \param utcb Base of the UTCB that will be used by the thread + * \return capability representing the new thread + * \throw Thread_creation_failed + * \throw Out_of_metadata + * \throw Quota_exceeded */ - virtual Thread_capability create_thread(Name const &name, + virtual Thread_capability create_thread(size_t quota, + Name const &name, addr_t utcb = 0) = 0; /** @@ -254,6 +261,56 @@ namespace Genode { */ virtual Dataspace_capability trace_policy(Thread_capability thread) = 0; + /** + * Define reference account for the CPU session + * + * \param cpu_session reference account + * + * \return 0 on success + * + * Each CPU session requires another CPU session as reference + * account to transfer quota to and from. The reference account can + * be defined only once. + */ + virtual int ref_account(Cpu_session_capability cpu_session) = 0; + + /** + * Transfer quota to another CPU session + * + * \param cpu_session receiver of quota donation + * \param amount amount of quota to donate + * \return 0 on success + * + * Quota can only be transfered if the specified CPU session is + * either the reference account for this session or vice versa. + */ + virtual int transfer_quota(Cpu_session_capability cpu_session, + size_t amount) = 0; + + /** + * Return current quota limit + */ + virtual size_t quota() = 0; + + /** + * Return amount of used quota + */ + virtual size_t used() = 0; + + /** + * Return amount of available quota + */ + size_t avail() + { + size_t q = quota(), u = used(); + return q > u ? q - u : 0; + } + + /** + * Transform percentage of CPU utilization into CPU quota + */ + static size_t pc_to_quota(size_t const pc) { + return (pc << QUOTA_LIMIT_LOG2) / 100; } /********************* ** RPC declaration ** @@ -261,7 +318,7 @@ namespace Genode { GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread, GENODE_TYPE_LIST(Thread_creation_failed, Out_of_metadata), - Name const &, addr_t); + size_t, Name const &, addr_t); GENODE_RPC(Rpc_utcb, Ram_dataspace_capability, utcb, Thread_capability); GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability); GENODE_RPC(Rpc_set_pager, int, set_pager, Thread_capability, Pager_capability); @@ -284,6 +341,10 @@ namespace Genode { GENODE_RPC(Rpc_trace_control_index, unsigned, trace_control_index, Thread_capability); GENODE_RPC(Rpc_trace_buffer, Dataspace_capability, trace_buffer, Thread_capability); GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability); + GENODE_RPC(Rpc_ref_account, int, ref_account, Cpu_session_capability); + GENODE_RPC(Rpc_transfer_quota, int, transfer_quota, Cpu_session_capability, size_t); + GENODE_RPC(Rpc_quota, size_t, quota); + GENODE_RPC(Rpc_used, size_t, used); /* * 'GENODE_RPC_INTERFACE' declaration done manually @@ -311,8 +372,12 @@ namespace Genode { Meta::Type_tuple - > > > > > > > > > > > > > > > > > Rpc_functions; + > > > > > > > > > > > > > > > > > > > > > Rpc_functions; }; } diff --git a/repos/base/src/base/env/platform_env.h b/repos/base/src/base/env/platform_env.h index 79063d8c3..1b89dd643 100644 --- a/repos/base/src/base/env/platform_env.h +++ b/repos/base/src/base/env/platform_env.h @@ -78,10 +78,12 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client(cap)) { } - Thread_capability create_thread(Name const &name, addr_t utcb) + Thread_capability + create_thread(size_t quota, Name const &name, addr_t utcb) { return retry( - [&] () { return Cpu_session_client::create_thread(name, utcb); }, + [&] () { + return Cpu_session_client::create_thread(quota, name, utcb); }, [&] () { upgrade_ram(8*1024); }); } }; diff --git a/repos/base/src/base/process/process.cc b/repos/base/src/base/process/process.cc index c9a615adf..d62414115 100644 --- a/repos/base/src/base/process/process.cc +++ b/repos/base/src/base/process/process.cc @@ -198,7 +198,7 @@ Process::Process(Dataspace_capability elf_ds_cap, /* create thread0 */ try { - _thread0_cap = _cpu_session_client.create_thread(name); + _thread0_cap = _cpu_session_client.create_thread(0, name); } catch (Cpu_session::Thread_creation_failed) { PERR("Creation of thread0 failed"); throw THREAD_FAIL; diff --git a/repos/base/src/base/server/common.cc b/repos/base/src/base/server/common.cc index ee7b6d16b..243b4ccdf 100644 --- a/repos/base/src/base/server/common.cc +++ b/repos/base/src/base/server/common.cc @@ -102,7 +102,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size, char const *name, bool start_on_construction, Affinity::Location location) : - Thread_base(name, stack_size), + Thread_base(0, name, stack_size), _cap(Untyped_capability()), _curr_obj(0), _cap_valid(Lock::LOCKED), _delay_start(Lock::LOCKED), _delay_exit(Lock::LOCKED), diff --git a/repos/base/src/base/thread/thread.cc b/repos/base/src/base/thread/thread.cc index e2f531613..0899bf9b6 100644 --- a/repos/base/src/base/thread/thread.cc +++ b/repos/base/src/base/thread/thread.cc @@ -191,8 +191,8 @@ void Thread_base::free_secondary_stack(void* stack_addr) } -Thread_base::Thread_base(const char *name, size_t stack_size, Type type, - Cpu_session *cpu_session) +Thread_base::Thread_base(size_t quota, const char *name, size_t stack_size, + Type type, Cpu_session *cpu_session) : _cpu_session(cpu_session), _context(type == REINITIALIZED_MAIN ? @@ -200,12 +200,13 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type type, _join_lock(Lock::LOCKED) { strncpy(_context->name, name, sizeof(_context->name)); - _init_platform_thread(type); + _init_platform_thread(quota, type); } -Thread_base::Thread_base(const char *name, size_t stack_size, Type type) -: Thread_base(name, stack_size, type, nullptr) { } +Thread_base::Thread_base(size_t quota, const char *name, size_t stack_size, + Type type) +: Thread_base(quota, name, stack_size, type, nullptr) { } Thread_base::~Thread_base() diff --git a/repos/base/src/base/thread/thread_start.cc b/repos/base/src/base/thread/thread_start.cc index 1eec30546..d1ea02d3f 100644 --- a/repos/base/src/base/thread/thread_start.cc +++ b/repos/base/src/base/thread/thread_start.cc @@ -54,7 +54,7 @@ void Thread_base::start() /* create thread at core */ char buf[48]; name(buf, sizeof(buf)); - _thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb); + _thread_cap = _cpu_session->create_thread(0, buf, (addr_t)&_context->utcb); /* assign thread to protection domain */ env()->pd_session()->bind_thread(_thread_cap); diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc index 436c3f139..afc355065 100644 --- a/repos/base/src/core/cpu_session_component.cc +++ b/repos/base/src/core/cpu_session_component.cc @@ -24,6 +24,7 @@ using namespace Genode; +static constexpr bool verbose = false; void Cpu_thread_component::update_exception_sigh() { @@ -32,9 +33,14 @@ void Cpu_thread_component::update_exception_sigh() }; -Thread_capability Cpu_session_component::create_thread(Name const &name, - addr_t utcb) +Thread_capability Cpu_session_component::create_thread(size_t quota, + Name const &name, + addr_t utcb) { + /* check for sufficient quota */ + quota = _local_to_global(quota); + if (quota > avail()) { _insuff_for_consume(quota); } + unsigned trace_control_index = 0; if (!_trace_control_area.alloc(trace_control_index)) throw Out_of_metadata(); @@ -47,12 +53,14 @@ Thread_capability Cpu_session_component::create_thread(Name const &name, Cpu_thread_component *thread = 0; try { Lock::Guard slab_lock_guard(_thread_alloc_lock); - thread = new(&_thread_alloc) Cpu_thread_component(_label, - thread_name, - _priority, utcb, - _default_exception_handler, - trace_control_index, - *trace_control); + thread = new(&_thread_alloc) + Cpu_thread_component( + quota, _label, thread_name, _priority, utcb, + _default_exception_handler, trace_control_index, + *trace_control); + + /* account quota */ + _used += quota; /* set default affinity defined by CPU session */ thread->platform_thread()->affinity(_location); @@ -78,6 +86,8 @@ void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *th unsigned const trace_control_index = thread->trace_control_index(); + _used -= thread->quota(); + Lock::Guard lock_guard(_thread_alloc_lock); destroy(&_thread_alloc, thread); @@ -280,13 +290,54 @@ static size_t remaining_session_ram_quota(char const *args) } -Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep, +int Cpu_session_component::transfer_quota(Cpu_session_capability c, size_t q) +{ + /* lookup targeted CPU-session */ + Object_pool::Guard s(_session_ep->lookup_and_lock(c)); + if (!s) { return -1; } + + /* translate quota argument and check limits */ + q = _local_to_global(q); + if (q > avail()) { return _insuff_for_transfer(q); } + + /* transfer quota to targeted CPU-session */ + if (s->_ref == this) { return _transfer_forth(s, q); } + if (s == _ref) { return _transfer_back(q); } + return -2; +} + + +int Cpu_session_component::ref_account(Cpu_session_capability c) +{ + /* + * Ensure that the ref account is set only once + * + * FIXME Add check for cycles along the tree of reference accounts + */ + if (_ref) { return -2; } + + /* lookup targeted CPU-session */ + Object_pool::Guard s(_session_ep->lookup_and_lock(c)); + if (!s) { return -1; } + if (s == this) { return -3; } + + /* establish ref-account relation from targeted CPU-session to us */ + _ref = s; + _ref->_insert_ref_member(this); + return 0; +} + + +Cpu_session_component::Cpu_session_component(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, Pager_entrypoint *pager_ep, Allocator *md_alloc, Trace::Source_registry &trace_sources, char const *args, - Affinity const &affinity) + Affinity const &affinity, + size_t quota) : + _session_ep(session_ep), _thread_ep(thread_ep), _pager_ep(pager_ep), _md_alloc(md_alloc, remaining_session_ram_quota(args)), _thread_alloc(&_md_alloc), _priority(0), @@ -294,7 +345,7 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep, /* map affinity to a location within the physical affinity space */ _location(affinity.scale_to(platform()->affinity_space())), - _trace_sources(trace_sources) + _trace_sources(trace_sources), _ref(0), _used(0), _quota(quota) { /* remember session label */ char buf[Session_label::size()]; @@ -312,6 +363,34 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep, Cpu_session_component::~Cpu_session_component() +{ + _deinit_threads(); + _deinit_ref_account(); +} + + +void Cpu_session_component::_deinit_ref_account() +{ + /* without a ref-account, nothing has do be done */ + if (!_ref) { return; } + + /* give back our remaining quota to our ref account */ + _transfer_back(_quota); + + /* remove ref-account relation between us and our ref-account */ + Cpu_session_component * const orig_ref = _ref; + _ref->_remove_ref_member(this); + + /* redirect ref-account relation of ref members to our prior ref account */ + Lock::Guard lock_guard(_ref_members_lock); + for (Cpu_session_component * s; (s = _ref_members.first()); ) { + _unsync_remove_ref_member(s); + orig_ref->_insert_ref_member(s); + } +} + + +void Cpu_session_component::_deinit_threads() { Lock::Guard lock_guard(_thread_list_lock); @@ -326,6 +405,32 @@ Cpu_session_component::~Cpu_session_component() } +int Cpu_session_component::_insuff_for_transfer(size_t const q) +{ + if (verbose) { + PWRN("Insufficient CPU quota for transfer: %s", _label.string()); + PWRN(" avail %zu", _avail()); + PWRN(" needed %zu", q); + } + return -3; +} + + +void Cpu_session_component::_insuff_for_consume(size_t const q) +{ + if (verbose) { + PWRN("Insufficient CPU quota for consumption: %s", _label.string()); + PWRN(" avail %zu", _avail()); + PWRN(" needed %zu", q); + } + throw Quota_exceeded(); +} + +size_t Cpu_session_component::used() { return _global_to_local(_used); } + +size_t Cpu_session_component::quota() { return _global_to_local(_quota); } + + /**************************** ** Trace::Source_registry ** ****************************/ diff --git a/repos/base/src/core/include/cpu_root.h b/repos/base/src/core/include/cpu_root.h index 279507fb7..ca28eca65 100644 --- a/repos/base/src/core/include/cpu_root.h +++ b/repos/base/src/core/include/cpu_root.h @@ -43,8 +43,11 @@ namespace Genode { throw Root::Quota_exceeded(); return new (md_alloc()) - Cpu_session_component(_thread_ep, _pager_ep, _md_alloc, - _trace_sources, args, affinity); } + Cpu_session_component( + Root_component::ep(), + _thread_ep, _pager_ep, _md_alloc, _trace_sources, + args, affinity, 0); + } void _upgrade_session(Cpu_session_component *cpu, const char *args) { @@ -68,8 +71,8 @@ namespace Genode { Trace::Source_registry &trace_sources) : Root_component(session_ep, md_alloc), - _thread_ep(thread_ep), _pager_ep(pager_ep), _md_alloc(md_alloc), - _trace_sources(trace_sources) + _thread_ep(thread_ep), _pager_ep(pager_ep), + _md_alloc(md_alloc), _trace_sources(trace_sources) { } }; } diff --git a/repos/base/src/core/include/cpu_session_component.h b/repos/base/src/core/include/cpu_session_component.h index 8232c4e36..8d58b697c 100644 --- a/repos/base/src/core/include/cpu_session_component.h +++ b/repos/base/src/core/include/cpu_session_component.h @@ -53,6 +53,7 @@ namespace Genode { private: + size_t const _quota; Thread_name const _name; Platform_thread _platform_thread; bool _bound; /* pd binding flag */ @@ -62,16 +63,17 @@ namespace Genode { public: - Cpu_thread_component(Session_label const &label, + Cpu_thread_component(size_t quota, Session_label const &label, Thread_name const &name, unsigned priority, addr_t utcb, Signal_context_capability sigh, unsigned trace_control_index, Trace::Control &trace_control) : - _name(name), - _platform_thread(name.string(), priority, utcb), _bound(false), - _sigh(sigh), _trace_control_index(trace_control_index), + _quota(quota), _name(name), + _platform_thread(quota, name.string(), priority, utcb), + _bound(false), _sigh(sigh), + _trace_control_index(trace_control_index), _trace_source(label, _name, trace_control) { update_exception_sigh(); @@ -86,6 +88,7 @@ namespace Genode { bool bound() const { return _bound; } void bound(bool b) { _bound = b; } Trace::Source *trace_source() { return &_trace_source; } + size_t quota() const { return _quota; } void sigh(Signal_context_capability sigh) { @@ -105,7 +108,8 @@ namespace Genode { }; - class Cpu_session_component : public Rpc_object + class Cpu_session_component : public Rpc_object, + public List::Element { public: @@ -114,6 +118,7 @@ namespace Genode { private: Session_label _label; + Rpc_entrypoint * const _session_ep; Rpc_entrypoint *_thread_ep; Pager_entrypoint *_pager_ep; Allocator_guard _md_alloc; /* guarded meta-data allocator */ @@ -129,6 +134,70 @@ namespace Genode { Trace::Source_registry &_trace_sources; Trace::Control_area _trace_control_area; + /* + * Members for quota accounting + */ + + Cpu_session_component * _ref; + size_t _used; + size_t _quota; + List _ref_members; + Lock _ref_members_lock; + + /* + * Utilities for quota accounting + */ + + size_t _avail() { return _quota - _used; } + + size_t _local_to_global(size_t const q) const { + return (q * _quota) >> Cpu_session::QUOTA_LIMIT_LOG2; } + + size_t _global_to_local(size_t const q) const { + if (!_quota) { return 0; } + return (q << Cpu_session::QUOTA_LIMIT_LOG2) / _quota; } + + int _insuff_for_transfer(size_t const q); + + void _insuff_for_consume(size_t const q); + + int _transfer_back(size_t const q) + { + _quota -= q; + _ref->_used -= q; + return 0; + } + + int _transfer_forth(Cpu_session_component * const s, size_t const q) + { + s->_quota += q; + _used += q; + return 0; + } + + void _insert_ref_member(Cpu_session_component * const s) + { + Lock::Guard lock_guard(_ref_members_lock); + _ref_members.insert(s); + s->_ref = this; + } + + void _unsync_remove_ref_member(Cpu_session_component * const s) + { + s->_ref = 0; + _ref_members.remove(s); + } + + void _remove_ref_member(Cpu_session_component * const s) + { + Lock::Guard lock_guard(_ref_members_lock); + _unsync_remove_ref_member(s); + } + + void _deinit_ref_account(); + + void _deinit_threads(); + /** * Exception handler that will be invoked unless overridden by a * call of 'Cpu_session::exception_handler'. @@ -150,11 +219,13 @@ namespace Genode { /** * Constructor */ - Cpu_session_component(Rpc_entrypoint *thread_ep, + Cpu_session_component(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, Pager_entrypoint *pager_ep, Allocator *md_alloc, Trace::Source_registry &trace_sources, - const char *args, Affinity const &affinity); + const char *args, Affinity const &affinity, + size_t quota); /** * Destructor @@ -171,7 +242,7 @@ namespace Genode { ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t); + Thread_capability create_thread(size_t, Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); int set_pager(Thread_capability, Pager_capability); @@ -189,6 +260,10 @@ namespace Genode { unsigned trace_control_index(Thread_capability); Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_policy(Thread_capability); + int ref_account(Cpu_session_capability c); + int transfer_quota(Cpu_session_capability c, size_t q); + size_t used(); + size_t quota(); }; } diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index a426bb50a..c4ed6a8a0 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -266,7 +266,16 @@ int main() = static_cap_cast(ram_root.session("ram_quota=32K", Affinity())); Ram_session_client(init_ram_session_cap).ref_account(env()->ram_session_cap()); + /* create CPU session for init and transfer all of the CPU quota to it */ + constexpr size_t cpu_quota = Cpu_session::QUOTA_LIMIT; + static Cpu_session_component + cpu(e, e, rm_root.pager_ep(), &sliced_heap, trace_sources, + "label=\"core\"", Affinity(), cpu_quota); + Cpu_session_capability cpu_cap = core_env()->entrypoint()->manage(&cpu); Cpu_connection init_cpu("init"); + init_cpu.ref_account(cpu_cap); + cpu.transfer_quota(init_cpu, cpu_quota); + Rm_connection init_rm; /* transfer all left memory to init, but leave some memory left for core */ diff --git a/repos/libports/src/lib/pthread/thread.h b/repos/libports/src/lib/pthread/thread.h index c5bea0843..a8df90f37 100644 --- a/repos/libports/src/lib/pthread/thread.h +++ b/repos/libports/src/lib/pthread/thread.h @@ -41,7 +41,7 @@ extern "C" { pthread(pthread_attr_t attr, void *(*start_routine) (void *), void *arg, size_t stack_size, char const * name, Genode::Cpu_session * cpu) - : Thread_base(name, stack_size, Type::NORMAL, cpu), + : Thread_base(0, name, stack_size, Type::NORMAL, cpu), _attr(attr), _start_routine(start_routine), _arg(arg) diff --git a/repos/os/include/init/child.h b/repos/os/include/init/child.h index b64002f04..9a30d00c7 100644 --- a/repos/os/include/init/child.h +++ b/repos/os/include/init/child.h @@ -94,36 +94,11 @@ namespace Init { } - inline Genode::size_t read_ram_quota(Genode::Xml_node start_node) - { - Genode::Number_of_bytes ram_quota = 0; - try { - Genode::Xml_node rsc = start_node.sub_node("resource"); - for (;; rsc = rsc.next("resource")) { - - try { - if (rsc.attribute("name").has_value("RAM")) { - rsc.attribute("quantum").value(&ram_quota); - } - } catch (...) { } - } - } catch (...) { } - - /* - * If the configured quota exceeds our own quota, we donate - * all remaining quota to the child but we need to count in - * our allocation of the child meta data from the heap. - * Hence, we preserve some of our own quota. - */ - if (ram_quota > avail_slack_ram_quota()) { - ram_quota = avail_slack_ram_quota(); - if (config_verbose) - Genode::printf("Warning: Specified quota exceeds available quota.\n" - " Proceeding with a quota of %zu bytes.\n", - (Genode::size_t)ram_quota); - } - return ram_quota; - } + /** + * Return amount of CPU time that is currently unused + */ + static inline Genode::size_t avail_slack_cpu_quota() { + return Genode::env()->cpu_session()->avail(); } /** @@ -411,15 +386,65 @@ namespace Init { Pd_args(Genode::Xml_node start_node); } _pd_args; + struct Read_quota + { + void warn_unsuff_quota(Genode::size_t const avail) + { + using namespace Genode; + if (!config_verbose) { return; } + Genode::printf("Warning: Specified quota exceeds available quota.\n"); + Genode::printf(" Proceeding with a quota of %zu.\n", avail); + } + + Read_quota(Genode::Xml_node start_node, Genode::size_t & ram_quota, + Genode::size_t & cpu_quota) + { + Genode::Number_of_bytes ram_bytes = 0; + Genode::size_t cpu_percent = 0; + try { + Genode::Xml_node rsc = start_node.sub_node("resource"); + for (;; rsc = rsc.next("resource")) { + try { + if (rsc.attribute("name").has_value("RAM")) { + rsc.attribute("quantum").value(&ram_bytes); + } else if (rsc.attribute("name").has_value("CPU")) { + rsc.attribute("quantum").value(&cpu_percent); } + } catch (...) { } + } + } catch (...) { } + ram_quota = ram_bytes; + cpu_quota = Genode::Cpu_session::pc_to_quota(cpu_percent); + + /* + * If the configured RAM quota exceeds our own quota, we donate + * all remaining quota to the child but we need to count in + * our allocation of the child meta data from the heap. + * Hence, we preserve some of our own quota. + */ + Genode::size_t const ram_avail = avail_slack_ram_quota(); + if (ram_quota > ram_avail) { + ram_quota = ram_avail; + warn_unsuff_quota(ram_avail); + } + + Genode::size_t const cpu_avail = avail_slack_cpu_quota(); + if (cpu_quota > cpu_avail) { + cpu_quota = cpu_avail; + warn_unsuff_quota(cpu_avail); + } + } + }; + /** * Resources assigned to the child */ - struct Resources + struct Resources : Read_quota { long prio_levels_log2; long priority; Genode::Affinity affinity; Genode::size_t ram_quota; + Genode::size_t cpu_quota; Genode::Ram_connection ram; Genode::Cpu_connection cpu; Genode::Rm_connection rm; @@ -428,11 +453,11 @@ namespace Init { long prio_levels_log2, Genode::Affinity::Space const &affinity_space) : + Read_quota(start_node, ram_quota, cpu_quota), prio_levels_log2(prio_levels_log2), priority(read_priority(start_node)), affinity(affinity_space, read_affinity_location(affinity_space, start_node)), - ram_quota(read_ram_quota(start_node)), ram(label), cpu(label, priority*(Genode::Cpu_session::PRIORITY_LIMIT >> prio_levels_log2), @@ -449,6 +474,9 @@ namespace Init { ram.ref_account(Genode::env()->ram_session_cap()); Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota); + + cpu.ref_account(Genode::env()->cpu_session_cap()); + Genode::env()->cpu_session()->transfer_quota(cpu.cap(), cpu_quota); } } _resources; diff --git a/repos/os/include/os/irq_activation.h b/repos/os/include/os/irq_activation.h index f9ed033fb..ac7020be3 100644 --- a/repos/os/include/os/irq_activation.h +++ b/repos/os/include/os/irq_activation.h @@ -57,7 +57,7 @@ namespace Genode { */ Irq_activation(int irq_number, Irq_handler &handler, size_t stack_size) : - Thread_base(_create_thread_name(irq_number), stack_size), + Thread_base(0, _create_thread_name(irq_number), stack_size), _number(irq_number), _connection(irq_number), _handler(handler) { start(); diff --git a/repos/ports-foc/src/lib/l4lx/include/vcpu.h b/repos/ports-foc/src/lib/l4lx/include/vcpu.h index 02e898197..8b0c93901 100644 --- a/repos/ports-foc/src/lib/l4lx/include/vcpu.h +++ b/repos/ports-foc/src/lib/l4lx/include/vcpu.h @@ -50,7 +50,7 @@ namespace L4lx { Genode::size_t stack_size, Genode::addr_t vcpu_state, unsigned cpu_nr) - : Genode::Thread_base(str, stack_size), + : Genode::Thread_base(0, str, stack_size), _lock(Genode::Cancelable_lock::LOCKED), _func(func), _data(data ? *data : 0), diff --git a/repos/ports/include/vmm/vcpu_dispatcher.h b/repos/ports/include/vmm/vcpu_dispatcher.h index 08b67cab0..8a9e8d224 100644 --- a/repos/ports/include/vmm/vcpu_dispatcher.h +++ b/repos/ports/include/vmm/vcpu_dispatcher.h @@ -61,7 +61,7 @@ class Vmm::Vcpu_dispatcher : public T Cpu_session * cpu_session, Genode::Affinity::Location location) : - T("vCPU dispatcher", stack_size), + T(0, "vCPU dispatcher", stack_size), _cap(cap) { using namespace Genode; diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h index 0ab087206..c7b453bd8 100644 --- a/repos/ports/include/vmm/vcpu_thread.h +++ b/repos/ports/include/vmm/vcpu_thread.h @@ -62,7 +62,7 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread { using namespace Genode; - Thread_capability vcpu_vm = _cpu_session->create_thread("vCPU"); + Thread_capability vcpu_vm = _cpu_session->create_thread(0, "vCPU"); /* assign thread to protection domain */ _pd_session.bind_thread(vcpu_vm); @@ -109,7 +109,7 @@ class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread_base Vcpu_same_pd(size_t stack_size, Cpu_session * cpu_session, Genode::Affinity::Location location) : - Thread_base("vCPU", stack_size, Type::NORMAL, cpu_session) + Thread_base(0, "vCPU", stack_size, Type::NORMAL, cpu_session) { /* release pre-allocated selectors of Thread */ Genode::cap_map()->remove(tid().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2); diff --git a/repos/ports/src/app/gdb_monitor/cpu_session_component.cc b/repos/ports/src/app/gdb_monitor/cpu_session_component.cc index 47b5c4243..8d339a422 100644 --- a/repos/ports/src/app/gdb_monitor/cpu_session_component.cc +++ b/repos/ports/src/app/gdb_monitor/cpu_session_component.cc @@ -63,10 +63,10 @@ Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid) } -Thread_capability Cpu_session_component::create_thread(Cpu_session::Name const &name, addr_t utcb) +Thread_capability Cpu_session_component::create_thread(size_t, Cpu_session::Name const &name, addr_t utcb) { Thread_capability thread_cap = - _parent_cpu_session.create_thread(name.string(), utcb); + _parent_cpu_session.create_thread(0, name.string(), utcb); if (thread_cap.valid()) { Thread_info *thread_info = new (env()->heap()) Thread_info(thread_cap, new_lwpid++); @@ -238,3 +238,11 @@ Cpu_session_component::Cpu_session_component(Signal_receiver *exception_signal_r Cpu_session_component::~Cpu_session_component() { } + +size_t Cpu_session_component::quota() { return 0; } + +size_t Cpu_session_component::used() { return 0; } + +int Cpu_session_component::ref_account(Cpu_session_capability) { return -1; } + +int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; } diff --git a/repos/ports/src/app/gdb_monitor/cpu_session_component.h b/repos/ports/src/app/gdb_monitor/cpu_session_component.h index 7f6f77841..1a722f926 100644 --- a/repos/ports/src/app/gdb_monitor/cpu_session_component.h +++ b/repos/ports/src/app/gdb_monitor/cpu_session_component.h @@ -56,7 +56,7 @@ class Cpu_session_component : public Rpc_object ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t); + Thread_capability create_thread(size_t, Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); int set_pager(Thread_capability, Pager_capability); @@ -76,6 +76,10 @@ class Cpu_session_component : public Rpc_object unsigned trace_control_index(Thread_capability); Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_policy(Thread_capability); + int ref_account(Cpu_session_capability c); + int transfer_quota(Cpu_session_capability c, size_t q); + size_t used(); + size_t quota(); }; #endif /* _CPU_SESSION_COMPONENT_H_ */ diff --git a/repos/ports/src/noux/cpu_session_component.h b/repos/ports/src/noux/cpu_session_component.h index 789961673..78d81d12a 100644 --- a/repos/ports/src/noux/cpu_session_component.h +++ b/repos/ports/src/noux/cpu_session_component.h @@ -71,7 +71,8 @@ namespace Noux { ** Cpu_session interface ** ***************************/ - Thread_capability create_thread(Name const &name, addr_t utcb) + Thread_capability create_thread(size_t, Name const &name, + addr_t utcb) { /* * Prevent any attempt to create more than the main @@ -82,7 +83,7 @@ namespace Noux { while (1); return Thread_capability(); } - _main_thread = _cpu.create_thread(name, utcb); + _main_thread = _cpu.create_thread(0, name, utcb); return _main_thread; } @@ -145,6 +146,11 @@ namespace Noux { Dataspace_capability trace_policy(Thread_capability thread) { return _cpu.trace_policy(thread); } + + size_t quota() { return 0; } + size_t used() { return 0; } + int ref_account(Cpu_session_capability) { return -1; } + int transfer_quota(Cpu_session_capability, size_t) { return -1; } }; } diff --git a/repos/qt4/include/genode/thread_qt.h b/repos/qt4/include/genode/thread_qt.h index e4dd56ad1..6cd1b7dc2 100644 --- a/repos/qt4/include/genode/thread_qt.h +++ b/repos/qt4/include/genode/thread_qt.h @@ -49,7 +49,7 @@ namespace Genode { size_t stack_size, Thread_entry *thread_entry) : - Thread_base(name, stack_size), + Thread_base(0, name, stack_size), _thread_entry(thread_entry) { /* start Genode thread */