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();