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.

! <start name="test">
!   <resource name="CPU" quantum="75"/>
! </start>

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
devel
Martin Stein 9 years ago committed by Christian Helmuth
parent f60e2af21f
commit 8f9355b360

@ -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; }

@ -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);

@ -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);
/**

@ -98,7 +98,7 @@ Weak_ptr<Address_space> 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)
{

@ -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);

@ -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();

@ -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);
/**

@ -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);

@ -151,7 +151,8 @@ Weak_ptr<Address_space> 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));

@ -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);

@ -25,8 +25,8 @@ namespace Genode {
explicit Foc_cpu_session_client(Cpu_session_capability session)
: Rpc_client<Foc_cpu_session>(static_cap_cast<Foc_cpu_session>(session)) { }
Thread_capability create_thread(Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(name, utcb); }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(0, name, utcb); }
Ram_dataspace_capability utcb(Thread_capability thread) {
return call<Rpc_utcb>(thread); }
@ -93,6 +93,16 @@ namespace Genode {
Native_capability alloc_irq() {
return call<Rpc_alloc_irq>(); }
int ref_account(Cpu_session_capability session) {
return call<Rpc_ref_account>(session); }
int transfer_quota(Cpu_session_capability session, size_t amount) {
return call<Rpc_transfer_quota>(session, amount); }
size_t quota() { return call<Rpc_quota>(); }
size_t used() { return call<Rpc_used>(); }
};
}

@ -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()

@ -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);

@ -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_component, 1024> 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<Cpu_session_component> _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();
/***********************************

@ -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()

@ -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() { }

@ -0,0 +1,161 @@
#
# Build
#
build "core init drivers/timer test/cpu_quota"
#
# Boot image
#
create_boot_directory
install_config {
<config prio_levels="4">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="10M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="init_1" priority="-1">
<binary name="init"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="10"/>
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<!-- should receive 10 % of the CPU time -->
<start name="test_slow" priority="-1">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="50"/>
</start>
</config>
</start>
<start name="init_2" priority="-2">
<binary name="init"/>
<resource name="RAM" quantum="100M"/>
<resource name="CPU" quantum="80"/>
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service><parent/></any-service>
</default-route>
<!-- should receive 25 % of the CPU time -->
<start name="test_middle">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="25"/>
</start>
<!-- should receive 65 % of the CPU time -->
<start name="test_fast">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="75"/>
</start>
</config>
</start>
</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"
}

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

@ -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);
}

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

@ -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

@ -59,7 +59,7 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
*/
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()); }

@ -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

@ -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;

@ -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());

@ -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());
}

@ -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)
{ }

@ -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();

@ -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())

@ -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 <base/printf.h>
#include <base/thread.h>
#include <base/env.h>
#include <base/sleep.h>
#include <timer_session/connection.h>
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();
}

@ -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

@ -24,8 +24,8 @@ namespace Genode {
explicit Linux_cpu_session_client(Capability<Linux_cpu_session> session)
: Rpc_client<Linux_cpu_session>(session) { }
Thread_capability create_thread(Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(name, utcb); }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(0, name, utcb); }
Ram_dataspace_capability utcb(Thread_capability thread) {
return call<Rpc_utcb>(thread); }
@ -78,6 +78,15 @@ namespace Genode {
Dataspace_capability trace_policy(Thread_capability thread) {
return call<Rpc_trace_policy>(thread); }
int ref_account(Cpu_session_capability session) {
return call<Rpc_ref_account>(session); }
int transfer_quota(Cpu_session_capability session, size_t amount) {
return call<Rpc_transfer_quota>(session, amount); }
size_t quota() { return call<Rpc_quota>(); }
size_t used() { return call<Rpc_used>(); }
/*****************************
* Linux-specific extension **

@ -43,10 +43,10 @@ struct Genode::Expanding_cpu_session_client
Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap)
: Upgradeable_client<Genode::Linux_cpu_session_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<Cpu_session::Out_of_metadata>(
[&] () { return Linux_cpu_session_client::create_thread(name, utcb); },
[&] () { return Linux_cpu_session_client::create_thread(0, name, utcb); },
[&] () { upgrade_ram(8*1024); });
}
};

@ -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<Linux_pd_session>(_pd.cap()));

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

@ -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<Cpu_session_component> _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();
/*******************************

@ -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() { }

@ -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()
{

@ -28,8 +28,8 @@ namespace Genode {
explicit Cpu_session_client(Cpu_session_capability session)
: Rpc_client<Nova_cpu_session>(static_cap_cast<Nova_cpu_session>(session)) { }
Thread_capability create_thread(Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(name, utcb); }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(0, name, utcb); }
Ram_dataspace_capability utcb(Thread_capability thread) {
return call<Rpc_utcb>(thread); }
@ -88,6 +88,16 @@ namespace Genode {
Dataspace_capability trace_policy(Thread_capability thread) {
return call<Rpc_trace_policy>(thread); }
int ref_account(Cpu_session_capability session) {
return call<Rpc_ref_account>(session); }
int transfer_quota(Cpu_session_capability session, size_t amount) {
return call<Rpc_transfer_quota>(session, amount); }
size_t quota() { return call<Rpc_quota>(); }
size_t used() { return call<Rpc_used>(); }
private:
Native_capability pause_sync(Thread_capability target) {

@ -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<unsigned long>(_context->name + 6)),
_client_exc_vcpu(Native_thread::INVALID_INDEX)
{

@ -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)

@ -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();

@ -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_component, 1024> 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<Cpu_session_component> _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();
/******************************

@ -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

@ -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

@ -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;

@ -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);

@ -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);

@ -178,7 +178,7 @@ Weak_ptr<Address_space> 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)