core: unify and simplify paging code (Fix #1641)

For most platforms except of NOVA a distinction between pager entrypoint
and pager activation is not needed, and only exists due to historical
reasons. Moreover, the pager thread's execution path is almost identical
between most platforms excluding NOVA, HW, and Fisco.OC. Therefore,
this commit unifies the pager loop for the other platforms, and removes
the pager activation class.
This commit is contained in:
Stefan Kalkowski
2015-07-29 10:58:17 +02:00
committed by Christian Helmuth
parent a574f73005
commit eafe5e81e3
31 changed files with 644 additions and 1238 deletions

View File

@ -2,11 +2,12 @@
* \brief Paging-server framework
* \author Norman Feske
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2006-04-28
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2015 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.
@ -16,31 +17,31 @@
#define _CORE__INCLUDE__PAGER_H_
#include <base/thread.h>
#include <base/thread_state.h>
#include <ipc_pager.h>
#include <base/printf.h>
#include <base/object_pool.h>
#include <base/signal.h>
#include <cap_session/cap_session.h>
#include <pager/capability.h>
#include <ipc_pager.h>
namespace Genode {
/**
* Special server object for paging
*
* A 'Pager_object' is very similar to a 'Rpc_object'. It is just a
* special implementation for page-fault handling, which does not allow to
* define a "badge" for pager capabilities.
*/
class Pager_object;
/**
* Paging entry point
*/
class Pager_entrypoint;
class Pager_activation_base;
template <int> class Pager_activation;
enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 };
}
/**
* Special server object for paging
*
* A 'Pager_object' is very similar to a 'Rpc_object'. It is just a
* special implementation for page-fault handling, which does not allow to
* define a "badge" for pager capabilities.
*/
class Genode::Pager_object : public Object_pool<Pager_object>::Entry
{
protected:
@ -125,69 +126,15 @@ class Genode::Pager_object : public Object_pool<Pager_object>::Entry
};
/**
* A 'Pager_activation' processes one page fault of a 'Pager_object' at a time.
*/
class Genode::Pager_activation_base: public Thread_base
class Genode::Pager_entrypoint : public Object_pool<Pager_object>,
public Thread<PAGER_EP_STACK_SIZE>
{
private:
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
Ipc_pager _pager;
Cap_session *_cap_session;
Native_capability _cap;
Pager_entrypoint *_ep; /* entry point to which the
activation belongs */
/**
* Lock used for blocking until '_cap' is initialized
*/
Lock _cap_valid;
public:
Pager_activation_base(const char *name, size_t stack_size)
: Thread_base(WEIGHT, name, stack_size), _cap(Native_capability()),
_ep(0), _cap_valid(Lock::LOCKED) { }
/**
* Set entry point, which the activation serves
*
* This method is only called by the 'Pager_entrypoint'
* constructor.
*/
void ep(Pager_entrypoint *ep) { _ep = ep; }
/**
* Thread interface
*/
void entry();
/**
* Return capability to this activation
*
* This method should only be called from 'Pager_entrypoint'
*/
Native_capability cap()
{
/* ensure that the initialization of our 'Ipc_pager' is done */
if (!_cap.valid())
_cap_valid.lock();
return _cap;
}
};
/**
* Paging entry point
*
* For a paging entry point can hold only one activation. So, paging is
* strictly serialized for one entry point.
*/
class Genode::Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Pager_activation_base *_activation;
Cap_session *_cap_session;
Untyped_capability _manage(Pager_object *obj);
public:
@ -197,9 +144,10 @@ class Genode::Pager_entrypoint : public Object_pool<Pager_object>
* \param cap_session Cap_session for creating capabilities
* for the pager objects managed by this
* entry point
* \param a initial activation
*/
Pager_entrypoint(Cap_session *cap_session, Pager_activation_base *a = 0);
Pager_entrypoint(Cap_session *cap_session)
: Thread<PAGER_EP_STACK_SIZE>("pager_ep"),
_cap_session(cap_session) { start(); }
/**
* Associate Pager_object with the entry point
@ -210,16 +158,13 @@ class Genode::Pager_entrypoint : public Object_pool<Pager_object>
* Dissolve Pager_object from entry point
*/
void dissolve(Pager_object *obj);
};
template <int STACK_SIZE>
class Genode::Pager_activation : public Pager_activation_base
{
public:
/**********************
** Thread interface **
**********************/
Pager_activation() : Pager_activation_base("pager", STACK_SIZE)
{ start(); }
void entry();
};
#endif /* _CORE__INCLUDE__PAGER_H_ */

View File

@ -29,12 +29,7 @@ namespace Genode {
Rpc_entrypoint *_ds_ep;
Rpc_entrypoint *_thread_ep;
Allocator *_md_alloc;
enum { PAGER_STACK_SIZE = 2*4096 };
Pager_activation<PAGER_STACK_SIZE> _pager_thread;
Pager_entrypoint _pager_ep;
addr_t _vm_start;
size_t _vm_size;
@ -105,8 +100,8 @@ namespace Genode {
:
Root_component<Rm_session_component>(session_ep, md_alloc),
_ds_ep(ds_ep), _thread_ep(thread_ep), _md_alloc(md_alloc),
_pager_thread(), _pager_ep(cap_session, &_pager_thread),
_vm_start(vm_start), _vm_size(vm_size) { }
_pager_ep(cap_session), _vm_start(vm_start), _vm_size(vm_size)
{ }
/**
* Return pager entrypoint

View File

@ -0,0 +1,103 @@
/*
* \brief Generic implmentation of pager entrypoint
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2009-03-31
*/
/*
* Copyright (C) 2009-2015 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.
*/
/* Core includes */
#include <pager.h>
using namespace Genode;
void Pager_entrypoint::entry()
{
bool reply_pending = false;
while (1) {
if (reply_pending)
_pager.reply_and_wait_for_fault();
else
_pager.wait_for_fault();
reply_pending = false;
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(lookup_and_lock(_pager.badge()));
Pager_object *obj = _obj;
/* handle request */
if (obj) {
if (_pager.is_exception()) {
obj->submit_exception_signal();
continue;
}
/* send reply if page-fault handling succeeded */
reply_pending = !obj->pager(_pager);
continue;
} else {
/*
* Prevent threads outside of core to mess with our wake-up
* interface. This condition can trigger if a process gets
* destroyed which triggered a page fault shortly before getting
* killed. In this case, 'wait_for_fault()' returns (because of
* the page fault delivery) but the pager-object lookup will fail
* (because core removed the process already).
*/
if (_pager.request_from_core()) {
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(_pager.fault_ip());
/* send reply to the calling region-manager session */
_pager.acknowledge_wakeup();
/* answer page fault of resolved pager object */
_pager.set_reply_dst(obj->cap());
_pager.acknowledge_wakeup();
}
}
};
}
void Pager_entrypoint::dissolve(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
Native_capability cap = _manage(obj);
/* add server object to object pool */
obj->cap(cap);
insert(obj);
/* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(cap);
}