genode/base-nova/src/core/include/platform_thread.h

179 lines
3.7 KiB
C
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Thread facility
* \author Norman Feske
* \author Alexander Boettcher
2011-12-22 16:19:25 +01:00
* \date 2009-10-02
*/
/*
2013-01-10 21:44:47 +01:00
* Copyright (C) 2009-2013 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_THREAD_H_
#define _CORE__INCLUDE__PLATFORM_THREAD_H_
/* Genode includes */
#include <thread/capability.h>
#include <base/thread_state.h>
#include <base/native_types.h>
#include <base/thread.h>
#include <base/pager.h>
/* core includes */
#include <address_space.h>
2011-12-22 16:19:25 +01:00
namespace Genode {
class Platform_pd;
class Platform_thread
{
private:
Platform_pd *_pd;
Pager_object *_pager;
addr_t _id_base;
addr_t _sel_exc_base;
Affinity::Location _location;
bool _is_main_thread;
bool _is_vcpu;
char _name[Thread_base::Context::NAME_LEN];
addr_t _sel_ec() const { return _id_base; }
addr_t _sel_sc() const { return _id_base + 1; }
2011-12-22 16:19:25 +01:00
public:
/* invalid thread number */
enum { THREAD_INVALID = -1 };
2011-12-22 16:19:25 +01:00
/**
* Constructor
*/
Platform_thread(const char *name = 0,
unsigned priority = 0,
2012-08-08 17:12:10 +02:00
int thread_id = THREAD_INVALID);
2011-12-22 16:19:25 +01:00
/**
* Destructor
*/
~Platform_thread();
/**
* Start thread
*
* \param ip instruction pointer to start at
* \param sp stack pointer to use
2011-12-22 16:19:25 +01:00
*
* \retval 0 successful
* \retval -1 thread/vCPU could not be started
2011-12-22 16:19:25 +01:00
*/
int start(void *ip, void *sp);
2011-12-22 16:19:25 +01:00
/**
* Pause this thread
*/
NOVA: extend cpu_session with synchronous pause The kernel provides a "recall" feature issued on threads to force a thread into an exception. In the exception the current state of the thread can be obtained and its execution can be halted/paused. However, the recall exception is only delivered when the next time the thread would leave the kernel. That means the delivery is asynchronous and Genode has to wait until the exception triggered. Waiting for the exception can either be done in the cpu_session service or outside the service in the protection domain of the caller. It turned out that waiting inside the cpu_service is prone to deadlock the system. The cpu_session interface is one of many session interfaces handled by the same thread inside Core. Deadlock situation: * The caller (thread_c) to pause some thread_p manages to establish the call to the cpu_session thread_s of Core but get be interrupted before issuing the actual pause (recall) command. * Now the - to be recalled thread_p - is scheduled and tries to invoke another service of Core, like making log output. * Since the Core thread_s is handling the session request of thread_c, the kernel uses the timeslice of thread_p to help to finish the request handled by thread_s. * Thread_s issues the actual pause/recall on thread_p and blocks inside Core to wait for the recall exception to be issued. * thread_p will leave not the kernel before finishing it actual IPC with thread_s which is blocked waiting for thread_p. That is the reason why the waiting/blocking for the recall exception taking place must be done on NOVA in the context of the caller (thread_1). Introduce a pause_sync call to the cpu_session which returns a semaphore capability to the caller. The caller blocks on the semaphore and is woken up when the pager of thread_p receives the recall exception with the state of thread_p.
2012-08-24 09:29:54 +02:00
Native_capability pause();
2011-12-22 16:19:25 +01:00
/**
* Resume this thread
*/
void resume();
/**
* Cancel currently blocking operation
*/
void cancel_blocking();
/**
* Override thread state with 's'
2011-12-22 16:19:25 +01:00
*
* \throw Cpu_session::State_access_failed
*/
void state(Thread_state s);
/**
* Read thread state
2011-12-22 16:19:25 +01:00
*
* \throw Cpu_session::State_access_failed
2011-12-22 16:19:25 +01:00
*/
Thread_state state();
2011-12-22 16:19:25 +01:00
/**
* Return the address space to which the thread is bound
*/
Weak_ptr<Address_space> address_space();
2011-12-22 16:19:25 +01:00
/************************
** Accessor functions **
************************/
/**
* Set pager
*/
void pager(Pager_object *pager) { _pager = pager; }
/**
* Return pager object
*/
2011-12-22 16:19:25 +01:00
Pager_object *pager() { return _pager; }
/**
* Return identification of thread when faulting
*/
unsigned long pager_object_badge() const;
/**
* Set the executing CPU for this thread
2011-12-22 16:19:25 +01:00
*/
void affinity(Affinity::Location location);
2011-12-22 16:19:25 +01:00
/**
* Get the executing CPU for this thread
*/
Affinity::Location affinity();
2011-12-22 16:19:25 +01:00
/**
* Get thread name
*/
const char *name() const { return "noname"; }
/**
* Associate thread with protection domain
*/
void bind_to_pd(Platform_pd *pd, bool is_main_thread)
{
_pd = pd, _is_main_thread = is_main_thread;
}
2012-08-08 17:12:10 +02:00
/**
* Return native EC cap with specific rights mask set.
* If the cap is mapped the kernel will demote the
* rights of the EC as specified by the rights mask.
*
* The cap is supposed to be returned to clients,
* which they have to use as argument to identify
* the thread to which they want attach portals.
*
* The demotion by the kernel during the map operation
* takes care that the EC cap itself contains
* no usable rights for the clients.
*/
2012-08-08 17:12:10 +02:00
Native_capability native_cap()
{
using namespace Nova;
return Native_capability(
_sel_ec(), Obj_crd::RIGHT_EC_RECALL);
2012-08-08 17:12:10 +02:00
}
void single_step(bool on);
2011-12-22 16:19:25 +01:00
};
}
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */