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);
mtc()->virt_user_entry();
@ -747,7 +747,7 @@ namespace Kernel
}
}
void scheduled_next()
void proceed()
{
/* set context pointer for mode switch */
_mt_client_context_ptr = (addr_t)_state;
@ -785,9 +785,7 @@ namespace Kernel
initial = 0;
}
/* create scheduler with a permanent idle thread */
static unsigned const user_time_slice =
timer()->ms_to_tics(USER_TIME_SLICE_MS);
static Cpu_scheduler cpu_sched(&idle, user_time_slice);
static Cpu_scheduler cpu_sched(&idle);
return &cpu_sched;
}
@ -827,8 +825,9 @@ namespace Kernel
case Timer::IRQ: {
/* clear interrupt at timer */
cpu_scheduler()->yield();
timer()->clear_interrupt();
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
break; }
default: {
@ -1439,18 +1438,13 @@ extern "C" void init_phys_kernel() {
*/
extern "C" void kernel()
{
static unsigned user_time = 0;
static bool initial_call = true;
/* an exception occured */
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 */
cpu_scheduler()->current_entry()->handle_exception();
cpu_scheduler()->head()->handle_exception();
/* kernel initialization */
} else {
@ -1495,16 +1489,11 @@ extern "C" void kernel()
0, core_id(), &cm_utcb, &cm_utcb);
/* kernel initialization finished */
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
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 */
next->scheduled_next();
cpu_scheduler()->head()->proceed();
}

View File

@ -49,7 +49,7 @@ namespace Kernel
/* kernel configuration */
enum {
DEFAULT_STACK_SIZE = 1*1024*1024,
USER_TIME_SLICE_MS = 100,
USER_LAP_TIME_MS = 100,
MAX_PDS = 256,
MAX_THREADS = 256,
MAX_SIGNAL_RECEIVERS = 256,
@ -412,102 +412,50 @@ namespace Kernel
public:
/**
* Base class for 'ENTRY_T' to support scheduling
* Provides schedulability through inheritance
*/
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) { }
};
class Entry : public Double_list<ENTRY_T>::Entry { };
protected:
ENTRY_T * const _idle; /* Default entry, can't be removed */
Double_list<ENTRY_T> _entries; /* List of entries beside '_idle' */
unsigned const _lap_time; /* Time that an entry gets for one
* scheduling lap to consume */
/* gets scheduled when '_entries' is empty */
ENTRY_T * const _idle;
/* scheduling participants beside '_idle' */
Double_list<ENTRY_T> _entries;
public:
/**
* Constructor
*/
Scheduler(ENTRY_T * const idle, unsigned const lap_time)
: _idle(idle), _lap_time(lap_time) { assert(_lap_time && _idle); }
Scheduler(ENTRY_T * const idle)
: _idle(idle) { assert(_idle); }
/**
* Returns the entry wich shall scheduled next
*
* \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.
* Get currently scheduled entry
*/
ENTRY_T * next_entry(unsigned & t)
{
/* 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 {
ENTRY_T * head() const {
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)
{
if (e == _idle) return;
e->Entry::_time = _lap_time;
_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); }
/**
* 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;
@ -521,7 +469,7 @@ namespace Kernel
public:
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
*/
void scheduled_next();
void proceed();
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;
}
unsigned stop_one_shot()
{
return read<Clo>();
}
void clear_interrupt()
{
write<Cs::Status>(1);

View File

@ -34,31 +34,13 @@ namespace Cortex_a9
*/
struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/**
* Timer control register
*/
struct Control : Register<0x8, 32>
{
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 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 */
};
/**
* Stop counting
*/
void _disable() { write<Control::Timer_enable>(0); }
public:
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
@ -83,20 +60,20 @@ namespace Cortex_a9
*/
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
{
_disable();
write<Control::Timer_enable>(0);
clear_interrupt();
}
/**
* Start a one-shot run
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
* Start one-shot run with an IRQ delay of 'tics'
*/
inline void start_one_shot(uint32_t const tics)
{
/* reset timer */
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 */
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) {
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned stop_one_shot()
static uint32_t ms_to_tics(unsigned const ms)
{
unsigned const v = read<Counter>();
_disable();
return v;
return ms * TICS_PER_MS;
}
/**
* Clear interrupt output line
*/
void clear_interrupt() {
write<Interrupt_status::Event>(1); }
void clear_interrupt()
{
write<Interrupt_status::Event>(1);
}
};
}

View File

@ -38,19 +38,6 @@ namespace Exynos_mct
{
struct Prescaler : Bitfield<0, 8> { };
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> { };
/**
* Local timer 0 free running counter observation
*/
struct L0_frcnto : Register<0x314, 32> { };
/**
* Local timer 0 configuration
*/
struct L0_tcon : Register<0x320, 32> {
struct L0_tcon : Register<0x320, 32>
{
struct Frc_start : Bitfield<3, 1> { };
};
/**
* 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> { };
};
/**
* Local timer 0 interrupt enable
*/
struct L0_int_enb : Register<0x334, 32> {
struct L0_int_enb : Register<0x334, 32>
{
struct Frceie : Bitfield<1, 1> { };
};
/**
* 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 Tcon : Bitfield<3, 1> { };
};
@ -110,9 +96,11 @@ namespace Exynos_mct
/**
* Start and stop counting
*/
void _run(bool const run) {
void _run(bool const run)
{
_acked_write<L0_tcon, L0_wstat::Tcon>
(L0_tcon::Frc_start::bits(run)); }
(L0_tcon::Frc_start::bits(run));
}
public:
@ -122,15 +110,15 @@ namespace Exynos_mct
Timer(addr_t const base, unsigned const clk)
: 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));
}
/**
* Start a one-shot run
*
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
* Start one-shot run with an IRQ delay of '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) {
return ms * _tics_per_ms; }
/**
* Stop the timer and return last timer value
*/
unsigned stop_one_shot() { return read<L0_frcnto>(); }
unsigned ms_to_tics(unsigned const ms)
{
return ms * _tics_per_ms;
}
/**
* Clear interrupt output line