base & core: Use FIFO to queue RM faulters.

By now RM faulters are hold in a LIFO. Thus a starvation problem
occurs on managed dataspaces when multiple threads throw pagefaults
continuously.
This commit is contained in:
Martin Stein 2012-11-16 11:35:40 +01:00 committed by Norman Feske
parent 05f5999e71
commit b7c1404fbf
3 changed files with 58 additions and 15 deletions

View File

@ -22,11 +22,6 @@ namespace Genode {
template <typename QT>
class Fifo
{
private:
QT *_head; /* oldest element */
QT *_tail; /* newest element */
public:
class Element
@ -46,8 +41,18 @@ namespace Genode {
* Return true is fifo element is enqueued in a fifo
*/
bool is_enqueued() { return _is_enqueued; }
/**
* Return next element in queue
*/
QT *next() const { return _next; }
};
private:
QT *_head; /* oldest element */
Element *_tail; /* newest element */
public:
/**
@ -62,6 +67,42 @@ namespace Genode {
*/
Fifo(): _head(0), _tail(0) { }
/**
* Return first queue element
*/
QT *head() const { return _head; }
/**
* Remove element explicitely from queue
*/
void remove(QT *qe)
{
if (empty()) return;
/* if specified element is the first of the queue */
if (qe == _head) {
_head = qe->Element::_next;
if (!_head) _tail = 0;
}
else {
/* search specified element in the queue */
Element *e = _head;
while (e->_next && (e->_next != qe))
e = e->_next;
/* element is not member of the queue */
if (!e->_next) return;
/* e->_next is the element to remove, skip it in list */
e->Element::_next = e->Element::_next->Element::_next;
if (!e->Element::_next) _tail = e;
}
qe->Element::_next = 0;
qe->Element::_is_enqueued = 0;
}
/**
* Attach element at the end of the queue
*/
@ -89,9 +130,10 @@ namespace Genode {
QT *result = _head;
/* check if queue has only one last element */
if (_head == _tail)
_head = _tail = 0;
else
if (_head == _tail) {
_head = 0;
_tail = 0;
} else
_head = _head->Fifo::Element::_next;
/* mark fifo queue element as free */

View File

@ -26,6 +26,7 @@
#include <base/signal.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <util/fifo.h>
/* core includes */
#include <platform.h>
@ -101,7 +102,7 @@ namespace Genode {
* be able to handle faults by arbitrary clients (not only its own
* clients), it maintains the list head of faulters.
*/
class Rm_faulter : public List<Rm_faulter>::Element
class Rm_faulter : public Fifo<Rm_faulter>::Element
{
private:
@ -268,7 +269,7 @@ namespace Genode {
detach, pagefaults */
List<Rm_region_ref> _regions; /* region list for destruction */
List<Rm_faulter> _faulters; /* list of threads that faulted at
Fifo<Rm_faulter> _faulters; /* list of threads that faulted at
the region-manager session and wait
for fault resolution */
List<Rm_client> _clients; /* list of RM clients using this RM

View File

@ -413,9 +413,9 @@ Rm_session_component::attach(Dataspace_capability ds_cap, size_t size,
dsc, dsc->phys_addr(), dsc->size(), offset, (addr_t)r, (addr_t)r + size);
/* check if attach operation resolves any faulting region-manager clients */
for (Rm_faulter *faulter = _faulters.first(); faulter; ) {
for (Rm_faulter *faulter = _faulters.head(); faulter; ) {
/* remeber next pointer before possibly removing current list element */
/* remember next pointer before possibly removing current list element */
Rm_faulter *next = faulter->next();
if (faulter->fault_in_addr_range((addr_t)r, size)) {
@ -643,7 +643,7 @@ void Rm_session_component::fault(Rm_faulter *faulter, addr_t pf_addr,
faulter->fault(this, Rm_session::State(pf_type, pf_addr));
/* enqueue faulter */
_faulters.insert(faulter);
_faulters.enqueue(faulter);
/* issue fault signal */
_fault_notifier.submit();
@ -671,7 +671,7 @@ Rm_session::State Rm_session_component::state()
Lock::Guard lock_guard(_lock);
/* pick one of the currently faulted threads */
Rm_faulter *faulter = _faulters.first();
Rm_faulter *faulter = _faulters.head();
/* return ready state if there are not current faulters */
if (!faulter)
@ -741,7 +741,7 @@ Rm_session_component::~Rm_session_component()
_ds_ep->dissolve(&_ds);
/* remove all faulters with pending page faults at this rm session */
while (Rm_faulter *faulter = _faulters.first()) {
while (Rm_faulter *faulter = _faulters.head()) {
_lock.unlock();
faulter->dissolve_from_faulting_rm_session();
_lock.lock();