hw: touch kernel scheduler and timer less often

fix #857
fix #855
This commit is contained in:
Martin Stein 2013-08-23 00:18:58 +02:00 committed by Christian Helmuth
parent d0eaca9915
commit 0d803266ea
5 changed files with 63 additions and 175 deletions

View File

@ -532,7 +532,7 @@ void Kernel::Thread::handle_exception()
} }
void Kernel::Thread::scheduled_next() void Kernel::Thread::proceed()
{ {
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this); _mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
mtc()->virt_user_entry(); mtc()->virt_user_entry();
@ -747,7 +747,7 @@ namespace Kernel
} }
} }
void scheduled_next() void proceed()
{ {
/* set context pointer for mode switch */ /* set context pointer for mode switch */
_mt_client_context_ptr = (addr_t)_state; _mt_client_context_ptr = (addr_t)_state;
@ -785,9 +785,7 @@ namespace Kernel
initial = 0; initial = 0;
} }
/* create scheduler with a permanent idle thread */ /* create scheduler with a permanent idle thread */
static unsigned const user_time_slice = static Cpu_scheduler cpu_sched(&idle);
timer()->ms_to_tics(USER_TIME_SLICE_MS);
static Cpu_scheduler cpu_sched(&idle, user_time_slice);
return &cpu_sched; return &cpu_sched;
} }
@ -827,8 +825,9 @@ namespace Kernel
case Timer::IRQ: { case Timer::IRQ: {
/* clear interrupt at timer */ cpu_scheduler()->yield();
timer()->clear_interrupt(); timer()->clear_interrupt();
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
break; } break; }
default: { default: {
@ -1439,18 +1438,13 @@ extern "C" void init_phys_kernel() {
*/ */
extern "C" void kernel() extern "C" void kernel()
{ {
static unsigned user_time = 0;
static bool initial_call = true; static bool initial_call = true;
/* an exception occured */ /* an exception occured */
if (!initial_call) if (!initial_call)
{ {
/* update how much time the last user has consumed */
unsigned const timer_value = timer()->stop_one_shot();
user_time = timer_value < user_time ? user_time - timer_value : 0;
/* handle exception that interrupted the last user */ /* handle exception that interrupted the last user */
cpu_scheduler()->current_entry()->handle_exception(); cpu_scheduler()->head()->handle_exception();
/* kernel initialization */ /* kernel initialization */
} else { } else {
@ -1495,16 +1489,11 @@ extern "C" void kernel()
0, core_id(), &cm_utcb, &cm_utcb); 0, core_id(), &cm_utcb, &cm_utcb);
/* kernel initialization finished */ /* kernel initialization finished */
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
initial_call = false; initial_call = false;
} }
/* offer next user context to the mode transition PIC */
Schedule_context * const next = cpu_scheduler()->next_entry(user_time);
/* limit user mode execution in time */
timer()->start_one_shot(user_time);
/* will jump to the context related mode-switch */ /* will jump to the context related mode-switch */
next->scheduled_next(); cpu_scheduler()->head()->proceed();
} }

View File

@ -49,7 +49,7 @@ namespace Kernel
/* kernel configuration */ /* kernel configuration */
enum { enum {
DEFAULT_STACK_SIZE = 1*1024*1024, DEFAULT_STACK_SIZE = 1*1024*1024,
USER_TIME_SLICE_MS = 100, USER_LAP_TIME_MS = 100,
MAX_PDS = 256, MAX_PDS = 256,
MAX_THREADS = 256, MAX_THREADS = 256,
MAX_SIGNAL_RECEIVERS = 256, MAX_SIGNAL_RECEIVERS = 256,
@ -412,102 +412,50 @@ namespace Kernel
public: public:
/** /**
* Base class for 'ENTRY_T' to support scheduling * Provides schedulability through inheritance
*/ */
class Entry : public Double_list<ENTRY_T>::Entry class Entry : public Double_list<ENTRY_T>::Entry { };
{
friend class Scheduler<ENTRY_T>;
unsigned _time; /* time wich remains for current lap */
/**
* Apply consumption of 'time'
*/
void _consume(unsigned const time)
{ _time = _time > time ? _time - time : 0; }
public:
/**
* Constructor
*/
Entry() : _time(0) { }
};
protected: protected:
ENTRY_T * const _idle; /* Default entry, can't be removed */ /* gets scheduled when '_entries' is empty */
Double_list<ENTRY_T> _entries; /* List of entries beside '_idle' */ ENTRY_T * const _idle;
unsigned const _lap_time; /* Time that an entry gets for one
* scheduling lap to consume */ /* scheduling participants beside '_idle' */
Double_list<ENTRY_T> _entries;
public: public:
/** /**
* Constructor * Constructor
*/ */
Scheduler(ENTRY_T * const idle, unsigned const lap_time) Scheduler(ENTRY_T * const idle)
: _idle(idle), _lap_time(lap_time) { assert(_lap_time && _idle); } : _idle(idle) { assert(_idle); }
/** /**
* Returns the entry wich shall scheduled next * Get currently scheduled entry
*
* \param t At the call it contains the time, wich was consumed
* by the last entry. At the return it is updated to
* the next timeslice.
*/ */
ENTRY_T * next_entry(unsigned & t) ENTRY_T * head() const {
{
/* update current entry */
ENTRY_T * e = _entries.head();
if (!e) {
t = _lap_time;
return _idle;
}
e->Entry::_consume(t);
/* lookup entry with time > 0, refresh depleted timeslices */
while (!e->Entry::_time) {
e->Entry::_time = _lap_time;
_entries.head_to_tail();
e = _entries.head();
}
/* return next entry and appropriate portion of time */
t = e->Entry::_time;
return e;
}
/**
* Get the currently scheduled entry
*/
ENTRY_T * current_entry() const {
return _entries.head() ? _entries.head() : _idle; } return _entries.head() ? _entries.head() : _idle; }
/** /**
* Ensure that 'e' does participate in scheduling afterwards * End turn of currently scheduled entry
*/
void yield() { _entries.head_to_tail(); }
/**
* Include 'e' in scheduling
*/ */
void insert(ENTRY_T * const e) void insert(ENTRY_T * const e)
{ {
if (e == _idle) return; if (e == _idle) return;
e->Entry::_time = _lap_time;
_entries.insert_tail(e); _entries.insert_tail(e);
} }
/** /**
* Ensures that 'e' doesn't participate in scheduling afterwards * Exclude 'e' from scheduling
*/ */
void remove(ENTRY_T * const e) { _entries.remove(e); } void remove(ENTRY_T * const e) { _entries.remove(e); }
/**
* Set remaining time of currently scheduled entry to 0
*/
void yield()
{
ENTRY_T * const e = _entries.head();
if (e) e->_time = 0;
return;
}
}; };
class Schedule_context; class Schedule_context;
@ -521,7 +469,7 @@ namespace Kernel
public: public:
virtual void handle_exception() = 0; virtual void handle_exception() = 0;
virtual void scheduled_next() = 0; virtual void proceed() = 0;
}; };
/** /**
@ -942,7 +890,7 @@ namespace Kernel
/** /**
* Continue executing this thread in userland * Continue executing this thread in userland
*/ */
void scheduled_next(); void proceed();
void kill_signal_context_blocks(); void kill_signal_context_blocks();

View File

@ -61,11 +61,6 @@ class Kernel::Timer : public Genode::Mmio
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms; return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
} }
unsigned stop_one_shot()
{
return read<Clo>();
}
void clear_interrupt() void clear_interrupt()
{ {
write<Cs::Status>(1); write<Cs::Status>(1);

View File

@ -34,31 +34,13 @@ namespace Cortex_a9
*/ */
struct Load : Register<0x0, 32> { }; struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/** /**
* Timer control register * Timer control register
*/ */
struct Control : Register<0x8, 32> struct Control : Register<0x8, 32>
{ {
struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ struct Timer_enable : Bitfield<0,1> { }; /* enable counting */
struct Auto_reload : Bitfield<1,1> { }; /* reload at zero */
struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */
struct Prescaler : Bitfield<8,8> { }; /* modify frequency */
/**
* Configure for a one-shot
*/
static access_t init_one_shot()
{
return Timer_enable::bits(0) |
Auto_reload::bits(0) |
Irq_enable::bits(1) |
Prescaler::bits(0);
}
}; };
/** /**
@ -69,11 +51,6 @@ namespace Cortex_a9
struct Event : Bitfield<0,1> { }; /* if counter hit zero */ struct Event : Bitfield<0,1> { }; /* if counter hit zero */
}; };
/**
* Stop counting
*/
void _disable() { write<Control::Timer_enable>(0); }
public: public:
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ }; enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
@ -83,20 +60,20 @@ namespace Cortex_a9
*/ */
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE) Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
{ {
_disable(); write<Control::Timer_enable>(0);
clear_interrupt(); clear_interrupt();
} }
/** /**
* Start a one-shot run * Start one-shot run with an IRQ delay of 'tics'
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/ */
inline void start_one_shot(uint32_t const tics) inline void start_one_shot(uint32_t const tics)
{ {
/* reset timer */ /* reset timer */
clear_interrupt(); clear_interrupt();
write<Control>(Control::init_one_shot()); Control::access_t control = 0;
Control::Irq_enable::set(control, 1);
write<Control>(control);
/* load timer and start decrementing */ /* load timer and start decrementing */
write<Load>(tics); write<Load>(tics);
@ -104,26 +81,20 @@ namespace Cortex_a9
} }
/** /**
* Translate milliseconds to a native timer value * Translate 'ms' milliseconds to a native timer value
*/ */
static uint32_t ms_to_tics(unsigned const ms) { static uint32_t ms_to_tics(unsigned const ms)
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned stop_one_shot()
{ {
unsigned const v = read<Counter>(); return ms * TICS_PER_MS;
_disable();
return v;
} }
/** /**
* Clear interrupt output line * Clear interrupt output line
*/ */
void clear_interrupt() { void clear_interrupt()
write<Interrupt_status::Event>(1); } {
write<Interrupt_status::Event>(1);
}
}; };
} }

View File

@ -38,19 +38,6 @@ namespace Exynos_mct
{ {
struct Prescaler : Bitfield<0, 8> { }; struct Prescaler : Bitfield<0, 8> { };
struct Div_mux : Bitfield<8, 3> { }; struct Div_mux : Bitfield<8, 3> { };
struct Tick_mon_sel : Bitfield<11, 2> { };
struct Int_mon_sel : Bitfield<13, 3> { };
/**
* Initialization value
*/
static access_t init_value()
{
return Prescaler::bits(PRESCALER) |
Div_mux::bits(DIV_MUX) |
Tick_mon_sel::bits(0) |
Int_mon_sel::bits(0);
}
}; };
/** /**
@ -58,36 +45,35 @@ namespace Exynos_mct
*/ */
struct L0_frcntb : Register<0x310, 32> { }; struct L0_frcntb : Register<0x310, 32> { };
/**
* Local timer 0 free running counter observation
*/
struct L0_frcnto : Register<0x314, 32> { };
/** /**
* Local timer 0 configuration * Local timer 0 configuration
*/ */
struct L0_tcon : Register<0x320, 32> { struct L0_tcon : Register<0x320, 32>
{
struct Frc_start : Bitfield<3, 1> { }; struct Frc_start : Bitfield<3, 1> { };
}; };
/** /**
* Local timer 0 expired status * Local timer 0 expired status
*/ */
struct L0_int_cstat : Register<0x330, 32, true> { struct L0_int_cstat : Register<0x330, 32, true>
{
struct Frcnt : Bitfield<1, 1> { }; struct Frcnt : Bitfield<1, 1> { };
}; };
/** /**
* Local timer 0 interrupt enable * Local timer 0 interrupt enable
*/ */
struct L0_int_enb : Register<0x334, 32> { struct L0_int_enb : Register<0x334, 32>
{
struct Frceie : Bitfield<1, 1> { }; struct Frceie : Bitfield<1, 1> { };
}; };
/** /**
* Local timer 0 write status * Local timer 0 write status
*/ */
struct L0_wstat : Register<0x340, 32, true> { struct L0_wstat : Register<0x340, 32, true>
{
struct Frcntb : Bitfield<2, 1> { }; struct Frcntb : Bitfield<2, 1> { };
struct Tcon : Bitfield<3, 1> { }; struct Tcon : Bitfield<3, 1> { };
}; };
@ -110,9 +96,11 @@ namespace Exynos_mct
/** /**
* Start and stop counting * Start and stop counting
*/ */
void _run(bool const run) { void _run(bool const run)
{
_acked_write<L0_tcon, L0_wstat::Tcon> _acked_write<L0_tcon, L0_wstat::Tcon>
(L0_tcon::Frc_start::bits(run)); } (L0_tcon::Frc_start::bits(run));
}
public: public:
@ -122,15 +110,15 @@ namespace Exynos_mct
Timer(addr_t const base, unsigned const clk) Timer(addr_t const base, unsigned const clk)
: Mmio(base), _tics_per_ms((float)clk / (PRESCALER + 1) / (1 << DIV_MUX) / 1000) : Mmio(base), _tics_per_ms((float)clk / (PRESCALER + 1) / (1 << DIV_MUX) / 1000)
{ {
write<Mct_cfg>(Mct_cfg::init_value()); Mct_cfg::access_t mct_cfg = 0;
Mct_cfg::Prescaler::set(mct_cfg, PRESCALER);
Mct_cfg::Div_mux::set(mct_cfg, DIV_MUX);
write<Mct_cfg>(mct_cfg);
write<L0_int_enb>(L0_int_enb::Frceie::bits(1)); write<L0_int_enb>(L0_int_enb::Frceie::bits(1));
} }
/** /**
* Start a one-shot run * Start one-shot run with an IRQ delay of 'tics'
*
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/ */
inline void start_one_shot(unsigned const tics) inline void start_one_shot(unsigned const tics)
{ {
@ -140,15 +128,12 @@ namespace Exynos_mct
} }
/** /**
* Translate milliseconds to a native timer value * Translate 'ms' milliseconds to a native timer value
*/ */
unsigned ms_to_tics(unsigned const ms) { unsigned ms_to_tics(unsigned const ms)
return ms * _tics_per_ms; } {
return ms * _tics_per_ms;
/** }
* Stop the timer and return last timer value
*/
unsigned stop_one_shot() { return read<L0_frcnto>(); }
/** /**
* Clear interrupt output line * Clear interrupt output line