From 0d803266eaacc2ba7df81bc173eb21658abe4a0e Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 23 Aug 2013 00:18:58 +0200 Subject: [PATCH] hw: touch kernel scheduler and timer less often fix #857 fix #855 --- base-hw/src/core/kernel.cc | 27 +++------ base-hw/src/core/kernel/thread.h | 94 +++++++---------------------- base-hw/src/core/rpi/timer.h | 5 -- base-hw/src/core/timer/cortex_a9.h | 53 ++++------------ base-hw/src/core/timer/exynos_mct.h | 59 +++++++----------- 5 files changed, 63 insertions(+), 175 deletions(-) diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index e58fb0810..1b1cc08f5 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -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(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(); } diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 838c6f5bb..29bb476c3 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -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 - { - friend class Scheduler; - - 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 { }; protected: - ENTRY_T * const _idle; /* Default entry, can't be removed */ - Double_list _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 _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(); diff --git a/base-hw/src/core/rpi/timer.h b/base-hw/src/core/rpi/timer.h index be9a56aee..0f55f772d 100644 --- a/base-hw/src/core/rpi/timer.h +++ b/base-hw/src/core/rpi/timer.h @@ -61,11 +61,6 @@ class Kernel::Timer : public Genode::Mmio return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms; } - unsigned stop_one_shot() - { - return read(); - } - void clear_interrupt() { write(1); diff --git a/base-hw/src/core/timer/cortex_a9.h b/base-hw/src/core/timer/cortex_a9.h index 3f72c5641..23290cad4 100644 --- a/base-hw/src/core/timer/cortex_a9.h +++ b/base-hw/src/core/timer/cortex_a9.h @@ -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(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(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::init_one_shot()); + Control::access_t control = 0; + Control::Irq_enable::set(control, 1); + write(control); /* load timer and start decrementing */ write(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(); - _disable(); - return v; + return ms * TICS_PER_MS; } /** * Clear interrupt output line */ - void clear_interrupt() { - write(1); } + void clear_interrupt() + { + write(1); + } }; } diff --git a/base-hw/src/core/timer/exynos_mct.h b/base-hw/src/core/timer/exynos_mct.h index fced8e0d6..d742c9f10 100644 --- a/base-hw/src/core/timer/exynos_mct.h +++ b/base-hw/src/core/timer/exynos_mct.h @@ -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::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::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); write(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(); } + unsigned ms_to_tics(unsigned const ms) + { + return ms * _tics_per_ms; + } /** * Clear interrupt output line