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:
parent
05f5999e71
commit
b7c1404fbf
|
@ -22,11 +22,6 @@ namespace Genode {
|
||||||
template <typename QT>
|
template <typename QT>
|
||||||
class Fifo
|
class Fifo
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
|
|
||||||
QT *_head; /* oldest element */
|
|
||||||
QT *_tail; /* newest element */
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class Element
|
class Element
|
||||||
|
@ -46,8 +41,18 @@ namespace Genode {
|
||||||
* Return true is fifo element is enqueued in a fifo
|
* Return true is fifo element is enqueued in a fifo
|
||||||
*/
|
*/
|
||||||
bool is_enqueued() { return _is_enqueued; }
|
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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,6 +67,42 @@ namespace Genode {
|
||||||
*/
|
*/
|
||||||
Fifo(): _head(0), _tail(0) { }
|
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
|
* Attach element at the end of the queue
|
||||||
*/
|
*/
|
||||||
|
@ -89,9 +130,10 @@ namespace Genode {
|
||||||
QT *result = _head;
|
QT *result = _head;
|
||||||
|
|
||||||
/* check if queue has only one last element */
|
/* check if queue has only one last element */
|
||||||
if (_head == _tail)
|
if (_head == _tail) {
|
||||||
_head = _tail = 0;
|
_head = 0;
|
||||||
else
|
_tail = 0;
|
||||||
|
} else
|
||||||
_head = _head->Fifo::Element::_next;
|
_head = _head->Fifo::Element::_next;
|
||||||
|
|
||||||
/* mark fifo queue element as free */
|
/* mark fifo queue element as free */
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
#include <util/fifo.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
@ -101,7 +102,7 @@ namespace Genode {
|
||||||
* be able to handle faults by arbitrary clients (not only its own
|
* be able to handle faults by arbitrary clients (not only its own
|
||||||
* clients), it maintains the list head of faulters.
|
* 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:
|
private:
|
||||||
|
|
||||||
|
@ -268,7 +269,7 @@ namespace Genode {
|
||||||
detach, pagefaults */
|
detach, pagefaults */
|
||||||
List<Rm_region_ref> _regions; /* region list for destruction */
|
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
|
the region-manager session and wait
|
||||||
for fault resolution */
|
for fault resolution */
|
||||||
List<Rm_client> _clients; /* list of RM clients using this RM
|
List<Rm_client> _clients; /* list of RM clients using this RM
|
||||||
|
|
|
@ -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);
|
dsc, dsc->phys_addr(), dsc->size(), offset, (addr_t)r, (addr_t)r + size);
|
||||||
|
|
||||||
/* check if attach operation resolves any faulting region-manager clients */
|
/* 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();
|
Rm_faulter *next = faulter->next();
|
||||||
|
|
||||||
if (faulter->fault_in_addr_range((addr_t)r, size)) {
|
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));
|
faulter->fault(this, Rm_session::State(pf_type, pf_addr));
|
||||||
|
|
||||||
/* enqueue faulter */
|
/* enqueue faulter */
|
||||||
_faulters.insert(faulter);
|
_faulters.enqueue(faulter);
|
||||||
|
|
||||||
/* issue fault signal */
|
/* issue fault signal */
|
||||||
_fault_notifier.submit();
|
_fault_notifier.submit();
|
||||||
|
@ -671,7 +671,7 @@ Rm_session::State Rm_session_component::state()
|
||||||
Lock::Guard lock_guard(_lock);
|
Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
/* pick one of the currently faulted threads */
|
/* 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 */
|
/* return ready state if there are not current faulters */
|
||||||
if (!faulter)
|
if (!faulter)
|
||||||
|
@ -741,7 +741,7 @@ Rm_session_component::~Rm_session_component()
|
||||||
_ds_ep->dissolve(&_ds);
|
_ds_ep->dissolve(&_ds);
|
||||||
|
|
||||||
/* remove all faulters with pending page faults at this rm session */
|
/* 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();
|
_lock.unlock();
|
||||||
faulter->dissolve_from_faulting_rm_session();
|
faulter->dissolve_from_faulting_rm_session();
|
||||||
_lock.lock();
|
_lock.lock();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user