diff --git a/repos/dde_rump/lib/mk/rump.inc b/repos/dde_rump/lib/mk/rump.inc index d2bdb9ad12..9e26a93db1 100644 --- a/repos/dde_rump/lib/mk/rump.inc +++ b/repos/dde_rump/lib/mk/rump.inc @@ -4,7 +4,7 @@ SHARED_LIB = yes LIBS += rump_include CC_OPT += -DLIBRUMPUSER -SRC_CC = dummies.cc hypercall.cc bootstrap.cc io.cc sync.cc env.cc alarm.cc +SRC_CC = dummies.cc hypercall.cc bootstrap.cc io.cc sync.cc env.cc CC_C_OPT += -DHAVE_PROP_DICTIONARY_T SRC_C = __main.c \ diff --git a/repos/dde_rump/src/include/rump/alarm.h b/repos/dde_rump/src/include/rump/alarm.h deleted file mode 100644 index f3707f5766..0000000000 --- a/repos/dde_rump/src/include/rump/alarm.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * \brief Timed event scheduler interface - * \date 2005-10-24 - * \author Norman Feske - */ - -/* - * Copyright (C) 2005-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__ALARM_H_ -#define _INCLUDE__BASE__ALARM_H_ - -#include - -namespace Genode { - class Alarm_scheduler; - class Alarm; -} - - -class Genode::Alarm -{ - public: - - typedef uint64_t Time; - - private: - - friend class Alarm_scheduler; - - struct Raw - { - Time deadline; /* next deadline */ - bool deadline_period; - Time period; /* duration between alarms */ - - bool is_pending_at(uint64_t time, bool time_period) const; - }; - - Mutex _dispatch_mutex { }; /* taken during handle method */ - Raw _raw { }; - int _active { 0 }; /* set to one when active */ - Alarm *_next { nullptr }; /* next alarm in alarm list */ - Alarm_scheduler *_scheduler { nullptr }; /* currently assigned scheduler */ - - void _assign(Time period, - Time deadline, - bool deadline_period, - Alarm_scheduler *scheduler) - { - _raw.period = period; - _raw.deadline_period = deadline_period; - _raw.deadline = deadline; - _scheduler = scheduler; - } - - void _reset() { - _assign(0, 0, false, 0), _active = 0, _next = 0; } - - /* - * Noncopyable - */ - Alarm(Alarm const &); - Alarm &operator = (Alarm const &); - - protected: - - /** - * Method to be called on when deadline is reached - * - * This method must be implemented by a derived class. If the - * return value is 'true' and the alarm is periodically scheduled, - * the alarm is scheduled again. - */ - virtual bool on_alarm(uint64_t) { return false; } - - public: - - Alarm() { _reset(); } - - virtual ~Alarm(); -}; - - -class Genode::Alarm_scheduler -{ - private: - - Mutex _mutex { }; /* protect alarm list */ - Alarm *_head { nullptr }; /* head of alarm list */ - Alarm::Time _now { 0UL }; /* recent time (updated by handle method) */ - bool _now_period { false }; - Alarm::Raw _min_handle_period { }; - - /** - * Enqueue alarm into alarm queue - * - * This is a helper for 'schedule' and 'handle'. - */ - void _unsynchronized_enqueue(Alarm *alarm); - - /** - * Dequeue alarm from alarm queue - */ - void _unsynchronized_dequeue(Alarm *alarm); - - /** - * Dequeue next pending alarm from alarm list - * - * \return dequeued pending alarm - * \retval 0 no alarm pending - */ - Alarm *_get_pending_alarm(); - - /** - * Assign timeout values to alarm object and add it to the schedule - */ - void _setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline); - - /* - * Noncopyable - */ - Alarm_scheduler(Alarm_scheduler const &); - Alarm_scheduler &operator = (Alarm_scheduler const &); - - public: - - Alarm_scheduler(Alarm::Time min_handle_period = 1) - { - Alarm::Time const deadline = _now + min_handle_period; - _min_handle_period.period = min_handle_period; - _min_handle_period.deadline = deadline; - _min_handle_period.deadline_period = _now > deadline ? - !_now_period : _now_period; - } - - ~Alarm_scheduler(); - - /** - * Schedule absolute timeout - * - * \param timeout absolute point in time for execution - */ - void schedule_absolute(Alarm *alarm, Alarm::Time timeout); - - /** - * Schedule alarm (periodic timeout) - * - * \param period alarm period - * - * The first deadline is overdue after this call, i.e. on_alarm() is - * called immediately. - */ - void schedule(Alarm *alarm, Alarm::Time period); - - /** - * Remove alarm from schedule - */ - void discard(Alarm *alarm); - - /** - * Handle alarms - * - * \param now current time - */ - void handle(Alarm::Time now); - - /** - * Determine next deadline (absolute) - * - * \param deadline out parameter for storing the next deadline - * \return true if an alarm is scheduled - */ - bool next_deadline(Alarm::Time *deadline); - - /** - * Determine if given alarm object is current head element - * - * \param alarm alarm object - * \return true if alarm is head element of timeout queue - */ - bool head_timeout(const Alarm * alarm) { return _head == alarm; } -}; - -#endif /* _INCLUDE__BASE__ALARM_H_ */ diff --git a/repos/dde_rump/src/include/rump/env.h b/repos/dde_rump/src/include/rump/env.h index 76cdf21591..bf2c86dd49 100644 --- a/repos/dde_rump/src/include/rump/env.h +++ b/repos/dde_rump/src/include/rump/env.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2016-2017 Genode Labs GmbH + * Copyright (C) 2016-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -19,6 +19,7 @@ #include #include #include +#include namespace Rump { class Env; @@ -32,19 +33,21 @@ class Rump::Env { private: - Genode::Env &_env; - Timeout_entrypoint _timeout_ep { _env }; - Genode::Heap _heap { _env.ram(), _env.rm() }; - Genode::Attached_rom_dataspace _config { _env, "config" }; + Genode::Env &_env; + Genode::Heap _heap { _env.ram(), _env.rm() }; + Genode::Attached_rom_dataspace _config { _env, "config" }; + Genode::Thread const *_ep_thread { Genode::Thread::myself() }; + Timer::Connection _timer { _env }; public: Env(Genode::Env &env); Genode::Env &env() { return _env; } - Timeout_entrypoint &timeout_ep() { return _timeout_ep; } Genode::Heap &heap() { return _heap; } Genode::Attached_rom_dataspace &config_rom() { return _config; } + Genode::Thread const *ep_thread() { return _ep_thread; } + Timer::Connection &timer() { return _timer; } }; /** diff --git a/repos/dde_rump/src/include/rump/timed_semaphore.h b/repos/dde_rump/src/include/rump/timed_semaphore.h index 00c45f9508..ecf27941d5 100644 --- a/repos/dde_rump/src/include/rump/timed_semaphore.h +++ b/repos/dde_rump/src/include/rump/timed_semaphore.h @@ -1,16 +1,15 @@ /* * \brief Semaphore implementation with timeout facility - * \author Stefan Kalkowski - * \date 2010-03-05 + * \author Christian Prochaska + * \date 2022-04-06 * * This semaphore implementation allows to block on a semaphore for a - * given time instead of blocking indefinetely. + * given time instead of blocking indefinitely. * - * For the timeout functionality the alarm framework is used. */ /* - * Copyright (C) 2010-2017 Genode Labs GmbH + * Copyright (C) 2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -19,242 +18,329 @@ #ifndef _INCLUDE__RUMP__TIMED_SEMAPHORE_H_ #define _INCLUDE__RUMP__TIMED_SEMAPHORE_H_ -#include -#include -#include +#include #include -using Genode::Exception; -using Genode::Entrypoint; -using Genode::Alarm; -using Genode::Alarm_scheduler; -using Genode::Semaphore; -using Genode::Signal_handler; - -/** - * Exception types - */ -class Timeout_exception : public Exception { }; -class Nonblocking_exception : public Exception { }; - - -/** - * Alarm thread, which counts jiffies and triggers timeout events. - */ -class Timeout_entrypoint : private Entrypoint +class Ep_blockade { private: - enum { JIFFIES_STEP_MS = 10 }; + Genode::Entrypoint &_ep; - Alarm_scheduler _alarm_scheduler { }; + Genode::Io_signal_handler _wakeup_handler + { _ep, *this, &Ep_blockade::_handle_wakeup }; - Timer::Connection _timer; + bool _signal_handler_called { false }; - Signal_handler _timer_handler; - - void _handle_timer() { _alarm_scheduler.handle(_timer.elapsed_ms()); } - - static Genode::size_t constexpr STACK_SIZE = 2048*sizeof(long); + void _handle_wakeup() + { + _signal_handler_called = true; + } public: - Timeout_entrypoint(Genode::Env &env) - : - Entrypoint(env, STACK_SIZE, "alarm-timer", Genode::Affinity::Location()), - _timer(env), - _timer_handler(*this, *this, &Timeout_entrypoint::_handle_timer) + Ep_blockade(Genode::Entrypoint &ep) : _ep(ep) { } + + void block() { - _timer.sigh(_timer_handler); - _timer.trigger_periodic(JIFFIES_STEP_MS*1000); + while (!_signal_handler_called) + _ep.wait_and_dispatch_one_io_signal(); + + _signal_handler_called = false; } - Alarm::Time time(void) { return _timer.elapsed_ms(); } - - void schedule_absolute(Alarm &alarm, Alarm::Time timeout) + void wakeup() { - _alarm_scheduler.schedule_absolute(&alarm, timeout); + _wakeup_handler.local_submit(); } - - void discard(Alarm &alarm) { _alarm_scheduler.discard(&alarm); } }; -/** - * Semaphore with timeout on down operation. - */ -class Timed_semaphore : public Semaphore +struct Timed_semaphore_blockade +{ + virtual void block() = 0; + virtual void wakeup() = 0; +}; + + +class Timed_semaphore_ep_blockade : public Timed_semaphore_blockade { private: - typedef Semaphore::Element Element; - - Timeout_entrypoint &_timeout_ep; - - /** - * Aborts blocking on the semaphore, raised when a timeout occured. - * - * \param element the waiting-queue element associated with a timeout. - * \return true if a thread was aborted/woken up - */ - bool _abort(Element &element) - { - Genode::Mutex::Guard lock_guard(Semaphore::_meta_lock); - - /* potentially, the queue is empty */ - if (++Semaphore::_cnt <= 0) { - - /* - * Iterate through the queue and find the thread, - * with the corresponding timeout. - */ - Element *first = nullptr; - Semaphore::_queue.dequeue([&first] (Element &e) { - first = &e; }); - Element *e = first; - - while (e) { - - /* - * Wakeup the thread. - */ - if (&element == e) { - e->blockade.wakeup(); - return true; - } - - /* - * Noninvolved threads are enqueued again. - */ - Semaphore::_queue.enqueue(*e); - e = nullptr; - Semaphore::_queue.dequeue([&e] (Element &next) { - e = &next; }); - - /* - * Maybe, the alarm was triggered just after the corresponding - * thread was already dequeued, that's why we have to track - * whether we processed the whole queue. - */ - if (e == first) - break; - } - } - - /* The right element was not found, so decrease counter again */ - --Semaphore::_cnt; - return false; - } - - - /** - * Represents a timeout associated with the blocking - * operation on a semaphore. - */ - class Timeout : public Alarm - { - private: - - Timed_semaphore &_sem; /* semaphore we block on */ - Element &_element; /* queue element timeout belongs to */ - bool _triggered { false }; - Time const _start; - - public: - - Timeout(Time start, Timed_semaphore &s, Element &e) - : _sem(s), _element(e), _triggered(false), _start(start) - { } - - bool triggered(void) { return _triggered; } - Time start() { return _start; } - - protected: - - bool on_alarm(Genode::uint64_t) override - { - _triggered = _sem._abort(_element); - return false; - } - }; + Ep_blockade _blockade; public: + Timed_semaphore_ep_blockade(Genode::Entrypoint &ep) + : _blockade(ep) { } + + void block() override + { + _blockade.block(); + } + + void wakeup() override + { + _blockade.wakeup(); + } +}; + + +class Timed_semaphore_thread_blockade : public Timed_semaphore_blockade +{ + private: + + Genode::Blockade _blockade; + + public: + + Timed_semaphore_thread_blockade() { } + + void block() override + { + _blockade.block(); + } + + void wakeup() override + { + _blockade.wakeup(); + } +}; + + +class Timed_semaphore +{ + public: + + struct Down_ok { }; + struct Down_timed_out { }; + using Down_result = Genode::Attempt; + + private: + + Genode::Env &_env; + Genode::Thread const *_ep_thread_ptr; + Timer::Connection &_timer; + + int _cnt; + Genode::Mutex _meta_mutex { }; + + struct Element : Genode::Fifo::Element + { + Timed_semaphore_blockade &blockade; + int &cnt; + Genode::Mutex &meta_mutex; + Genode::Fifo &queue; + + Genode::Mutex destruct_mutex { }; + Timer::One_shot_timeout timeout; + bool wakeup_called { false }; + + void handle_timeout(Genode::Duration) + { + { + Genode::Mutex::Guard guard(meta_mutex); + + /* + * If 'wakeup()' was called, 'Timed_semaphore::up()' + * has already taken care of this. + */ + + if (!wakeup_called) { + + cnt++; + + /* + * Remove element from queue so that a future 'up()' + * does not select it for wakeup. + */ + queue.remove(*this); + } + } + + /* + * Protect the 'blockade' member from destruction + * until 'blockade.wakeup()' has returned. + */ + Genode::Mutex::Guard guard(destruct_mutex); + + blockade.wakeup(); + } + + Element(Timed_semaphore_blockade &blockade, + int &cnt, + Genode::Mutex &meta_mutex, + Genode::Fifo &queue, + Timer::Connection &timer, + bool use_timeout = false, + Genode::Microseconds timeout_us = Genode::Microseconds(0)) + : blockade(blockade), + cnt(cnt), + meta_mutex(meta_mutex), + queue(queue), + timeout(timer, *this, &Element::handle_timeout) + { + if (use_timeout) + timeout.schedule(timeout_us); + } + + ~Element() + { + /* + * Synchronize destruction with unfinished + * 'handle_timeout()' or 'wakeup()' + */ + Genode::Mutex::Guard guard(destruct_mutex); + } + + Down_result block() + { + blockade.block(); + + if (wakeup_called) + return Down_ok(); + else + return Down_timed_out(); + } + + /* meta_mutex must be acquired when calling and is released */ + void wakeup() + { + /* + * It is possible that 'handle_timeout()' is already being + * called and waiting for the meta_mutex, so in addition to + * discarding the timeout, the 'wakeup_called' variable is + * set for 'handle_timeout()' (and for 'block()'). + */ + + wakeup_called = true; + + meta_mutex.release(); + + /* + * 'timeout.discard()' waits until an ongoing signal + * handler execution is finished, so meta_mutex must + * be released at this point. + */ + timeout.discard(); + + /* + * Protect the 'blockade' member from destruction + * until 'blockade.wakeup()' has returned. + */ + Genode::Mutex::Guard guard(destruct_mutex); + + blockade.wakeup(); + } + }; + + Genode::Fifo _queue { }; + + /* _meta_mutex must be acquired when calling and is released */ + Down_result _down_internal(Timed_semaphore_blockade &blockade, + bool use_timeout, + Genode::Microseconds timeout_us) + { + /* + * Create semaphore queue element representing the thread + * in the wait queue and release _meta_mutex. + */ + Element queue_element { blockade, _cnt, _meta_mutex, _queue, + _timer, use_timeout, timeout_us }; + _queue.enqueue(queue_element); + _meta_mutex.release(); + + /* + * The thread is going to block now, + * waiting for getting woken up from another thread + * calling 'up()' or by the timeout handler. + */ + return queue_element.block(); + } + + public: + + /** * Constructor * - * \param n initial counter value of the semphore - */ - Timed_semaphore(Timeout_entrypoint &timeout_ep, int n = 0) - : Semaphore(n), _timeout_ep(timeout_ep) { } - - /** - * Decrements semaphore and blocks when it's already zero. + * \param env Genode environment + * \param timer timer connection + * \param n initial counter value of the semphore * - * \param t after t milliseconds of blocking a Timeout_exception is thrown. - * if t is zero do not block, instead raise an - * Nonblocking_exception. - * \return milliseconds the caller was blocked + * Note: currently it is assumed that the constructor is called + * by the ep thread. */ - Alarm::Time down(Alarm::Time t) + Timed_semaphore(Genode::Env &env, Genode::Thread const *ep_thread_ptr, + Timer::Connection &timer, int n = 0) + : _env(env), _ep_thread_ptr(ep_thread_ptr), + _timer(timer), _cnt(n) { } + + ~Timed_semaphore() { - Semaphore::_meta_lock.acquire(); - - if (--Semaphore::_cnt < 0) { - - /* If t==0 we shall not block */ - if (t == 0) { - ++_cnt; - Semaphore::_meta_lock.release(); - throw Nonblocking_exception(); - } - - /* - * Create semaphore queue element representing the thread - * in the wait queue. - */ - Element queue_element; - Semaphore::_queue.enqueue(queue_element); - Semaphore::_meta_lock.release(); - - /* Create the timeout */ - Alarm::Time const curr_time = _timeout_ep.time(); - Timeout timeout(curr_time, *this, queue_element); - _timeout_ep.schedule_absolute(timeout, curr_time + t); - - /* - * The thread is going to block on a local lock now, - * waiting for getting waked from another thread - * calling 'up()' - * */ - queue_element.blockade.block(); - - /* Deactivate timeout */ - _timeout_ep.discard(timeout); - - /* - * When we were only woken up, because of a timeout, - * throw an exception. - */ - if (timeout.triggered()) - throw Timeout_exception(); - - /* return blocking time */ - return _timeout_ep.time() - timeout.start(); - - } else { - Semaphore::_meta_lock.release(); - } - return 0; + /* synchronize destruction with unfinished 'up()' */ + try { _meta_mutex.acquire(); } catch (...) { } } + /** + * Increment semaphore counter + * + * This method may wake up another thread that currently blocks on + * a 'down' call at the same semaphore. + */ + void up() + { + Element * element = nullptr; - /******************************** - ** Base class implementations ** - ********************************/ + _meta_mutex.acquire(); - void down() { Semaphore::down(); } - void up() { Semaphore::up(); } + if (++_cnt > 0) { + _meta_mutex.release(); + return; + } + + /* + * Remove element from queue and wake up the corresponding + * blocking thread + */ + _queue.dequeue([&element] (Element &head) { + element = &head; }); + + if (element) { + /* 'element->wakeup()' releases the _meta_mutex */ + element->wakeup(); + } else + _meta_mutex.release(); + } + + /** + * Decrement semaphore counter, block if the counter reaches zero + */ + Down_result down(bool use_timeout = false, + Genode::Microseconds timeout_us = Genode::Microseconds(0)) + { + if (use_timeout && (timeout_us.value == 0)) + return Down_timed_out(); + + _meta_mutex.acquire(); + + if (--_cnt < 0) { + + /* _down_internal() releases _meta_mutex */ + + if (Genode::Thread::myself() == _ep_thread_ptr) { + Timed_semaphore_ep_blockade blockade { _env.ep() }; + return _down_internal(blockade, use_timeout, timeout_us); + } else { + Timed_semaphore_thread_blockade blockade; + return _down_internal(blockade, use_timeout, timeout_us); + } + + } else { + _meta_mutex.release(); + return Down_ok(); + } + } }; #endif /* _INCLUDE__RUMP__TIMED_SEMAPHORE_H_ */ diff --git a/repos/dde_rump/src/lib/rump/alarm.cc b/repos/dde_rump/src/lib/rump/alarm.cc deleted file mode 100644 index 9885e03406..0000000000 --- a/repos/dde_rump/src/lib/rump/alarm.cc +++ /dev/null @@ -1,293 +0,0 @@ -/* - * \brief Timed event scheduler - * \date 2005-10-24 - * \author Norman Feske - */ - -/* - * Copyright (C) 2005-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include - -using namespace Genode; - - -void Alarm_scheduler::_unsynchronized_enqueue(Alarm *alarm) -{ - if (alarm->_active) { - error("trying to insert the same alarm twice!"); - return; - } - - alarm->_active++; - - /* if alarmlist is empty add first element */ - if (!_head) { - alarm->_next = 0; - _head = alarm; - return; - } - - /* if deadline is smaller than any other deadline, put it on the head */ - if (alarm->_raw.is_pending_at(_head->_raw.deadline, _head->_raw.deadline_period)) { - alarm->_next = _head; - _head = alarm; - return; - } - - /* find list element with a higher deadline */ - Alarm *curr = _head; - while (curr->_next && - curr->_next->_raw.is_pending_at(alarm->_raw.deadline, alarm->_raw.deadline_period)) - { - curr = curr->_next; - } - - /* if end of list is reached, append new element */ - if (curr->_next == 0) { - curr->_next = alarm; - return; - } - - /* insert element in middle of list */ - alarm->_next = curr->_next; - curr->_next = alarm; -} - - -void Alarm_scheduler::_unsynchronized_dequeue(Alarm *alarm) -{ - if (!_head) return; - - if (_head == alarm) { - _head = alarm->_next; - alarm->_reset(); - return; - } - - /* find predecessor in alarm queue */ - Alarm *curr; - for (curr = _head; curr && (curr->_next != alarm); curr = curr->_next); - - /* alarm is not enqueued */ - if (!curr) return; - - /* remove alarm from alarm queue */ - curr->_next = alarm->_next; - alarm->_reset(); -} - - -bool Alarm::Raw::is_pending_at(uint64_t time, bool time_period) const -{ - return (time_period == deadline_period && - time >= deadline) || - (time_period != deadline_period && - time < deadline); -} - - -Alarm *Alarm_scheduler::_get_pending_alarm() -{ - Mutex::Guard guard(_mutex); - - if (!_head || !_head->_raw.is_pending_at(_now, _now_period)) { - return nullptr; } - - /* remove alarm from head of the list */ - Alarm *pending_alarm = _head; - _head = _head->_next; - - /* - * Acquire dispatch mutex to defer destruction until the call of 'on_alarm' - * is finished - */ - pending_alarm->_dispatch_mutex.acquire(); - - /* reset alarm object */ - pending_alarm->_next = nullptr; - pending_alarm->_active--; - - return pending_alarm; -} - - -void Alarm_scheduler::handle(Alarm::Time curr_time) -{ - /* - * Raise the time counter and if it wraps, update also in which - * period of the time counter we are. - */ - if (_now > curr_time) { - _now_period = !_now_period; - } - _now = curr_time; - - if (!_min_handle_period.is_pending_at(_now, _now_period)) { - return; - } - Alarm::Time const deadline = _now + _min_handle_period.period; - _min_handle_period.deadline = deadline; - _min_handle_period.deadline_period = _now > deadline ? - !_now_period : _now_period; - - Alarm *curr; - while ((curr = _get_pending_alarm())) { - - uint64_t triggered = 1; - - if (curr->_raw.period) { - Alarm::Time deadline = curr->_raw.deadline; - - /* schedule next event */ - if (deadline == 0) - deadline = curr_time; - - triggered += (curr_time - deadline) / curr->_raw.period; - } - - /* do not reschedule if alarm function returns 0 */ - bool reschedule = curr->on_alarm(triggered); - - if (reschedule) { - - /* - * At this point, the alarm deadline normally is somewhere near - * the current time but If the alarm had no deadline by now, - * initialize it with the current time. - */ - if (curr->_raw.deadline == 0) { - curr->_raw.deadline = _now; - curr->_raw.deadline_period = _now_period; - } - /* - * Raise the deadline value by one period of the alarm and - * if the deadline value wraps thereby, update also in which - * period it is located. - */ - Alarm::Time const deadline = curr->_raw.deadline + - triggered * curr->_raw.period; - if (curr->_raw.deadline > deadline) { - curr->_raw.deadline_period = !curr->_raw.deadline_period; - } - curr->_raw.deadline = deadline; - - /* synchronize enqueue operation */ - Mutex::Guard guard(_mutex); - _unsynchronized_enqueue(curr); - } - - /* release alarm, resume concurrent destructor operation */ - curr->_dispatch_mutex.release(); - } -} - - -void Alarm_scheduler::_setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline) -{ - /* - * If the alarm is already present in the queue, re-consider its queue - * position because its deadline might have changed. I.e., if an alarm is - * rescheduled with a new timeout before the original timeout triggered. - */ - if (alarm._active) - _unsynchronized_dequeue(&alarm); - - alarm._assign(period, deadline, _now > deadline ? !_now_period : _now_period, this); - - _unsynchronized_enqueue(&alarm); -} - - -void Alarm_scheduler::schedule_absolute(Alarm *alarm, Alarm::Time timeout) -{ - Mutex::Guard alarm_list_guard(_mutex); - - _setup_alarm(*alarm, 0, timeout); -} - - -void Alarm_scheduler::schedule(Alarm *alarm, Alarm::Time period) -{ - Mutex::Guard alarm_list_guard(_mutex); - - /* - * Refuse to schedule a periodic timeout of 0 because it would trigger - * infinitely in the 'handle' function. To account for the case where the - * alarm object was already scheduled, we make sure to remove it from the - * queue. - */ - if (period == 0) { - _unsynchronized_dequeue(alarm); - return; - } - - /* first deadline is overdue */ - _setup_alarm(*alarm, period, _now); -} - - -void Alarm_scheduler::discard(Alarm *alarm) -{ - /* - * Make sure that nobody is inside the '_get_pending_alarm' when - * grabbing the '_dispatch_mutex'. This is important when this function - * is called from the 'Alarm' destructor. Without the '_dispatch_mutex', - * we could take the mutex and proceed with destruction just before - * '_get_pending_alarm' tries to grab the mutex. When the destructor is - * finished, '_get_pending_alarm' would proceed with operating on a - * dangling pointer. - */ - Mutex::Guard alarm_list_guard(_mutex); - - if (alarm) { - Mutex::Guard alarm_guard(alarm->_dispatch_mutex); - _unsynchronized_dequeue(alarm); - } -} - - -bool Alarm_scheduler::next_deadline(Alarm::Time *deadline) -{ - Mutex::Guard alarm_list_guard(_mutex); - - if (!_head) return false; - - if (deadline) - *deadline = _head->_raw.deadline; - - if (deadline && *deadline < _min_handle_period.deadline) { - *deadline = _min_handle_period.deadline; - } - return true; -} - - -Alarm_scheduler::~Alarm_scheduler() -{ - Mutex::Guard guard(_mutex); - - while (_head) { - - Alarm *next = _head->_next; - - /* reset alarm object */ - _head->_reset(); - - /* remove from list */ - _head = next; - } -} - - -Alarm::~Alarm() -{ - if (_scheduler) - _scheduler->discard(this); -} - diff --git a/repos/dde_rump/src/lib/rump/sync.cc b/repos/dde_rump/src/lib/rump/sync.cc index b85edb7ec9..7707614b79 100644 --- a/repos/dde_rump/src/lib/rump/sync.cc +++ b/repos/dde_rump/src/lib/rump/sync.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2014-2017 Genode Labs GmbH + * Copyright (C) 2014-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -18,6 +18,7 @@ extern "C" { #include #include #include +#include #include "sched.h" @@ -208,13 +209,14 @@ static uint64_t timeout_ms(struct timespec currtime, } - struct Cond { int num_waiters; int num_signallers; Genode::Mutex counter_mutex; - Timed_semaphore signal_sem { Rump::env().timeout_ep() }; + Timed_semaphore signal_sem { Rump::env().env(), + Rump::env().ep_thread(), + Rump::env().timer() }; Genode::Semaphore handshake_sem; Cond() : num_waiters(0), num_signallers(0) { } @@ -237,15 +239,13 @@ struct Cond struct timespec currtime; rumpuser_clock_gettime(0, &currtime.tv_sec, &currtime.tv_nsec); - Alarm::Time timeout = timeout_ms(currtime, *abstime); - try { - signal_sem.down(timeout); - } catch (Timeout_exception) { - result = -2; - } - catch (Nonblocking_exception) { - result = 0; - } + Genode::Microseconds timeout_us = + Genode::Microseconds(timeout_ms(currtime, *abstime) * 1000); + + signal_sem.down(true, timeout_us).with_result( + [&] (Timed_semaphore::Down_ok) { }, + [&] (Timed_semaphore::Down_timed_out) { result = -2; } + ); } counter_mutex.acquire();