/* * \brief Timers and ticks * \author Christian Helmuth * \date 2008-10-22 */ /* * Copyright (C) 2008-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. */ #include #include #include #include extern "C" { #include } #include "thread.h" using namespace Genode; /************************ ** Timer tick symbols ** ************************/ volatile unsigned long dde_kit_timer_ticks; /*************************** ** Timer thread and tick ** ***************************/ class Timer_thread : Dde_kit::Thread, public Alarm_scheduler { private: unsigned _period_in_ms; void(*_init)(void *); void *_priv; Timer::Connection _timer; List _destroy_list; Lock _destroy_list_lock; void _enqueue_destroy(dde_kit_timer *timer) { Lock::Guard lock_guard(_destroy_list_lock); _destroy_list.insert(timer); } dde_kit_timer * _dequeue_next_destroy() { Lock::Guard lock_guard(_destroy_list_lock); dde_kit_timer *timer = _destroy_list.first(); if (timer) _destroy_list.remove(timer); return timer; } public: Timer_thread(unsigned hz, void(*init)(void *), void *priv) : Dde_kit::Thread("timer"), _period_in_ms(1000/hz), _init(init), _priv(priv) { dde_kit_timer_ticks = 0; start(); } void entry() { dde_kit_thread_adopt_myself("timer"); /* call provided init function */ if (_init) _init(_priv); /* timer tick loop */ while (true) { dde_kit_timer *timer; /* * XXX This approach drifts with the execution time of handlers * and timer destruction. */ _timer.msleep(_period_in_ms); ++dde_kit_timer_ticks; /* execute all scheduled alarms */ Alarm_scheduler::handle(dde_kit_timer_ticks); /* finish pending alarm object destruction */ while ((timer = _dequeue_next_destroy())) destroy(env()->heap(), timer); } }; /** * Schedule timer for destruction (garbage collection) * * \param timer timer fo destroy */ void destroy_timer(dde_kit_timer *timer) { _enqueue_destroy(timer); } }; static Timer_thread *_timer_thread; /*************+****** ** Timer facility ** ********************/ class dde_kit_timer : public Alarm, public List::Element { private: void (*_handler)(void *); /* handler function */ void *_priv; /* private handler token */ bool _pending; /* true if timer is pending */ protected: bool on_alarm(unsigned) override { /* if timer is really pending, call registered handler function */ if (_pending) { _pending = false; _handler(_priv); } /* do not schedule again */ return false; } public: dde_kit_timer(void (*handler)(void *), void *priv, unsigned long absolute_timeout) : _handler(handler), _priv(priv), _pending(true) { schedule(absolute_timeout); } void schedule(unsigned long absolute_timeout) { _pending = true; _timer_thread->schedule_absolute(this, absolute_timeout); } bool pending() const { return _pending; } /** * Schedule destruction of this timer on next tick * * Note: The timed event scheduler (alarm.h) does not allow to modify * alarm objects in the on_alarm function. But, drivers do this * frequently when modifying timer objects on timeout occurence. */ void destroy() { _pending = false; _timer_thread->destroy_timer(this); } }; extern "C" struct dde_kit_timer *dde_kit_timer_add(void (*fn)(void *), void *priv, unsigned long timeout) { try { return new (env()->heap()) dde_kit_timer(fn, priv, timeout); } catch (...) { PERR("timer creation failed"); return 0; } } extern "C" void dde_kit_timer_schedule_absolute(struct dde_kit_timer *timer, unsigned long timeout) { timer->schedule(timeout); } extern "C" void dde_kit_timer_del(struct dde_kit_timer *timer) { try { timer->destroy(); } catch (...) { } } extern "C" int dde_kit_timer_pending(struct dde_kit_timer *timer) { return timer->pending(); } extern "C" void dde_kit_timer_init(void(*thread_init)(void *), void *priv) { try { static Timer_thread t(DDE_KIT_HZ, thread_init, priv); _timer_thread = &t; } catch (...) { PERR("Timer thread creation failed"); } }