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 */