2012-11-30 14:08:42 +01:00
|
|
|
/*
|
|
|
|
* \brief Kernel representation of a user thread
|
|
|
|
* \author Martin Stein
|
|
|
|
* \date 2012-11-30
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-11-30 14:08:42 +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__KERNEL__THREAD_H_
|
|
|
|
#define _CORE__KERNEL__THREAD_H_
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <util/fifo.h>
|
|
|
|
|
|
|
|
/* core includes */
|
2012-12-10 13:55:19 +01:00
|
|
|
#include <cpu.h>
|
|
|
|
#include <tlb.h>
|
|
|
|
#include <timer.h>
|
2012-11-30 14:08:42 +01:00
|
|
|
#include <assert.h>
|
2013-09-02 13:37:55 +02:00
|
|
|
#include <kernel/configuration.h>
|
2013-09-03 14:20:43 +02:00
|
|
|
#include <kernel/scheduler.h>
|
2013-09-03 12:32:38 +02:00
|
|
|
#include <kernel/object.h>
|
2013-09-05 12:47:19 +02:00
|
|
|
#include <kernel/irq_receiver.h>
|
2013-05-14 22:40:30 +02:00
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
namespace Genode
|
|
|
|
{
|
|
|
|
class Platform_thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
2012-12-10 13:55:19 +01:00
|
|
|
typedef Genode::Cpu Cpu;
|
|
|
|
typedef Genode::Page_flags Page_flags;
|
|
|
|
typedef Genode::Core_tlb Core_tlb;
|
2012-11-30 14:08:42 +01:00
|
|
|
typedef Genode::Signal Signal;
|
|
|
|
typedef Genode::Pagefault Pagefault;
|
|
|
|
typedef Genode::Native_utcb Native_utcb;
|
|
|
|
|
|
|
|
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
|
|
|
|
|
|
|
class Schedule_context;
|
|
|
|
typedef Scheduler<Schedule_context> Cpu_scheduler;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kernel object that can be scheduled for the CPU
|
|
|
|
*/
|
2013-09-03 14:20:43 +02:00
|
|
|
class Schedule_context : public Cpu_scheduler::Item
|
2012-11-30 14:08:42 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual void handle_exception() = 0;
|
2013-08-23 00:18:58 +02:00
|
|
|
virtual void proceed() = 0;
|
2012-11-30 14:08:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends requests to other IPC nodes, accumulates request announcments,
|
|
|
|
* provides serial access to them and replies to them if expected.
|
|
|
|
* Synchronizes communication.
|
|
|
|
*
|
|
|
|
* IPC node states:
|
|
|
|
*
|
|
|
|
* +----------+ +---------------+ +---------------+
|
2013-05-22 14:41:47 +02:00
|
|
|
* --new-->| inactive |---send-request-await-reply--->| await reply | +--send-note--| prepare reply |
|
2012-11-30 14:08:42 +01:00
|
|
|
* | |<--receive-reply---------------| | | | |
|
2013-05-22 14:41:47 +02:00
|
|
|
* | |<--cancel-waiting--------------| | | | |
|
2012-11-30 14:08:42 +01:00
|
|
|
* | | +---------------+ +------------>| |
|
|
|
|
* | |<--request-is-a-note-------+---request-is-not-a-note------------------------>| |
|
2013-05-22 14:41:47 +02:00
|
|
|
* | |<--------------------------(---not-await-request---+ | |
|
|
|
|
* | | | +---------------+ | | |
|
|
|
|
* | |---await-request-----------+-->| await request |<--+--send-reply-------------| |
|
|
|
|
* | |<--cancel-waiting--------------| |------announce-request--+--->| |
|
|
|
|
* | |---send-reply---------+----+-->| | | | |
|
|
|
|
* | |---send-note--+ | | +---------------+ | | |
|
|
|
|
* | | | | | | | |
|
|
|
|
* | |<-------------+ | request available | | |
|
|
|
|
* | |<--not-await-request--+ | | | |
|
|
|
|
* | |<--request-is-a-note-------+-------------------request-is-not-a-note----(--->| |
|
|
|
|
* | |<--request-is-a-note----------------------------------------------------+ | |
|
2012-11-30 14:08:42 +01:00
|
|
|
* +----------+ +-------------------------+ | |
|
|
|
|
* | prepare and await reply |<--send-request-and-await-reply--| |
|
2013-05-22 14:41:47 +02:00
|
|
|
* | |---receive-reply---------------->| |
|
|
|
|
* | |---cancel-waiting--------------->| |
|
2012-11-30 14:08:42 +01:00
|
|
|
* +-------------------------+ +---------------+
|
|
|
|
*
|
|
|
|
* State model propagated to deriving classes:
|
|
|
|
*
|
|
|
|
* +--------------+ +----------------+
|
|
|
|
* --new-->| has received |--send-request-await-reply-------------------->| awaits receipt |
|
|
|
|
* | |--await-request----------------------------+-->| |
|
|
|
|
* | | | | |
|
|
|
|
* | |<--request-available-----------------------+ | |
|
|
|
|
* | |--send-reply-------------------------------+-->| |
|
|
|
|
* | |--send-note--+ | | |
|
|
|
|
* | | | | | |
|
|
|
|
* | |<------------+ | | |
|
|
|
|
* | |<--request-available-or-not-await-request--+ | |
|
|
|
|
* | |<--announce-request----------------------------| |
|
|
|
|
* | |<--receive-reply-------------------------------| |
|
2013-05-22 14:41:47 +02:00
|
|
|
* | |<--cancel-waiting------------------------------| |
|
2012-11-30 14:08:42 +01:00
|
|
|
* +--------------+ +----------------+
|
|
|
|
*/
|
|
|
|
class Ipc_node
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* IPC node states as depicted initially
|
|
|
|
*/
|
|
|
|
enum State
|
|
|
|
{
|
|
|
|
INACTIVE = 1,
|
|
|
|
AWAIT_REPLY = 2,
|
|
|
|
AWAIT_REQUEST = 3,
|
|
|
|
PREPARE_REPLY = 4,
|
|
|
|
PREPARE_AND_AWAIT_REPLY = 5,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Describes the buffer for incoming or outgoing messages
|
|
|
|
*/
|
|
|
|
struct Message_buf : public Fifo<Message_buf>::Element
|
|
|
|
{
|
|
|
|
void * base;
|
|
|
|
size_t size;
|
|
|
|
Ipc_node * origin;
|
|
|
|
};
|
|
|
|
|
|
|
|
Fifo<Message_buf> _request_queue; /* requests that waits to be
|
|
|
|
* received by us */
|
2013-05-22 14:41:47 +02:00
|
|
|
Message_buf _inbuf; /* buffers message we have received lastly */
|
2012-11-30 14:08:42 +01:00
|
|
|
Message_buf _outbuf; /* buffers the message we aim to send */
|
2013-05-22 14:41:47 +02:00
|
|
|
State _state; /* current node state */
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Buffer next request from request queue in 'r' to handle it
|
|
|
|
*/
|
|
|
|
void _receive_request(Message_buf * const r);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive a given reply if one is expected
|
|
|
|
*
|
|
|
|
* \param base base of the reply payload
|
|
|
|
* \param size size of the reply payload
|
|
|
|
*/
|
|
|
|
void _receive_reply(void * const base, size_t const size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Insert 'r' into request queue, buffer it if we were waiting for it
|
|
|
|
*/
|
|
|
|
void _announce_request(Message_buf * const r);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wether we expect to receive a reply message
|
|
|
|
*/
|
|
|
|
bool _awaits_reply();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IPC node waits for a message to receive to its inbuffer
|
|
|
|
*/
|
|
|
|
virtual void _awaits_receipt() = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IPC node has received a message in its inbuffer
|
|
|
|
*
|
|
|
|
* \param s size of the message
|
|
|
|
*/
|
|
|
|
virtual void _has_received(size_t const s) = 0;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct an initially inactive IPC node
|
|
|
|
*/
|
|
|
|
Ipc_node();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
virtual ~Ipc_node() { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a request and wait for the according reply
|
|
|
|
*
|
|
|
|
* \param dest targeted IPC node
|
|
|
|
* \param req_base base of the request payload
|
|
|
|
* \param req_size size of the request payload
|
|
|
|
* \param inbuf_base base of the reply buffer
|
|
|
|
* \param inbuf_size size of the reply buffer
|
|
|
|
*/
|
|
|
|
void send_request_await_reply(Ipc_node * const dest,
|
|
|
|
void * const req_base,
|
|
|
|
size_t const req_size,
|
|
|
|
void * const inbuf_base,
|
|
|
|
size_t const inbuf_size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wait until a request has arrived and load it for handling
|
|
|
|
*
|
|
|
|
* \param inbuf_base base of the request buffer
|
|
|
|
* \param inbuf_size size of the request buffer
|
|
|
|
*/
|
|
|
|
void await_request(void * const inbuf_base,
|
|
|
|
size_t const inbuf_size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reply to last request if there's any
|
|
|
|
*
|
|
|
|
* \param reply_base base of the reply payload
|
|
|
|
* \param reply_size size of the reply payload
|
|
|
|
*/
|
|
|
|
void send_reply(void * const reply_base,
|
|
|
|
size_t const reply_size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a notification and stay inactive
|
|
|
|
*
|
|
|
|
* \param dest targeted IPC node
|
|
|
|
* \param note_base base of the note payload
|
|
|
|
* \param note_size size of the note payload
|
|
|
|
*
|
|
|
|
* The caller must ensure that the note payload remains
|
|
|
|
* until it is buffered by the targeted node.
|
|
|
|
*/
|
|
|
|
void send_note(Ipc_node * const dest,
|
|
|
|
void * const note_base,
|
|
|
|
size_t const note_size);
|
2013-05-22 14:41:47 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop waiting for a receipt if in a waiting state
|
|
|
|
*/
|
|
|
|
void cancel_waiting();
|
2012-11-30 14:08:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kernel representation of a user thread
|
|
|
|
*/
|
|
|
|
class Thread : public Cpu::User_context,
|
|
|
|
public Object<Thread, MAX_THREADS>,
|
|
|
|
public Schedule_context,
|
|
|
|
public Fifo<Thread>::Element,
|
|
|
|
public Ipc_node,
|
2013-09-05 12:47:19 +02:00
|
|
|
public Irq_receiver
|
2012-11-30 14:08:42 +01:00
|
|
|
{
|
2013-05-22 14:41:47 +02:00
|
|
|
enum State
|
|
|
|
{
|
|
|
|
SCHEDULED,
|
|
|
|
AWAIT_START,
|
|
|
|
AWAIT_IPC,
|
|
|
|
AWAIT_RESUMPTION,
|
|
|
|
AWAIT_IRQ,
|
|
|
|
AWAIT_SIGNAL,
|
|
|
|
AWAIT_SIGNAL_CONTEXT_DESTRUCT,
|
2013-09-02 09:39:31 +02:00
|
|
|
CRASHED,
|
2013-05-22 14:41:47 +02:00
|
|
|
};
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
Platform_thread * const _platform_thread; /* userland object wich
|
|
|
|
* addresses this thread */
|
|
|
|
State _state; /* thread state, description given at the beginning */
|
|
|
|
Pagefault _pagefault; /* last pagefault triggered by this thread */
|
|
|
|
Thread * _pager; /* gets informed if thread throws a pagefault */
|
|
|
|
unsigned _pd_id; /* ID of the PD this thread runs on */
|
|
|
|
Native_utcb * _phys_utcb; /* physical UTCB base */
|
|
|
|
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
2013-05-22 14:41:47 +02:00
|
|
|
Signal_receiver * _signal_receiver; /* receiver we are currently
|
|
|
|
* listen to */
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume execution
|
|
|
|
*/
|
2013-05-22 14:41:47 +02:00
|
|
|
void _schedule();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**************
|
|
|
|
** Ipc_node **
|
|
|
|
**************/
|
|
|
|
|
|
|
|
void _has_received(size_t const s);
|
|
|
|
|
|
|
|
void _awaits_receipt();
|
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Irq_owner **
|
|
|
|
***************/
|
|
|
|
|
2013-05-22 14:41:47 +02:00
|
|
|
void _received_irq();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
void _awaits_irq();
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
void * operator new (size_t, void * p) { return p; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
|
|
|
Thread(Platform_thread * const platform_thread) :
|
|
|
|
_platform_thread(platform_thread),
|
2013-05-22 14:41:47 +02:00
|
|
|
_state(AWAIT_START), _pager(0), _pd_id(0),
|
|
|
|
_phys_utcb(0), _virt_utcb(0), _signal_receiver(0)
|
2012-11-30 14:08:42 +01:00
|
|
|
{ }
|
|
|
|
|
2013-09-02 09:39:31 +02:00
|
|
|
/**
|
|
|
|
* Suspend the thread due to unrecoverable misbehavior
|
|
|
|
*/
|
|
|
|
void crash();
|
|
|
|
|
2012-11-30 14:08:42 +01:00
|
|
|
/**
|
2013-06-06 14:18:36 +02:00
|
|
|
* Prepare thread to get scheduled the first time
|
2012-11-30 14:08:42 +01:00
|
|
|
*
|
2013-06-06 14:18:36 +02:00
|
|
|
* \param ip initial instruction pointer
|
|
|
|
* \param sp initial stack pointer
|
|
|
|
* \param cpu_id target cpu
|
|
|
|
* \param pd_id target protection-domain
|
|
|
|
* \param utcb_phys physical UTCB pointer
|
|
|
|
* \param utcb_virt virtual UTCB pointer
|
|
|
|
*/
|
|
|
|
void prepare_to_start(void * const ip,
|
|
|
|
void * const sp,
|
|
|
|
unsigned const cpu_id,
|
|
|
|
unsigned const pd_id,
|
|
|
|
Native_utcb * const utcb_phys,
|
|
|
|
Native_utcb * const utcb_virt);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start this thread
|
2012-11-30 14:08:42 +01:00
|
|
|
*
|
2013-06-06 14:18:36 +02:00
|
|
|
* \param ip initial instruction pointer
|
|
|
|
* \param sp initial stack pointer
|
|
|
|
* \param cpu_id target cpu
|
|
|
|
* \param pd_id target protection-domain
|
|
|
|
* \param utcb_phys physical UTCB pointer
|
|
|
|
* \param utcb_virt virtual UTCB pointer
|
2012-11-30 14:08:42 +01:00
|
|
|
*/
|
2013-06-06 14:18:36 +02:00
|
|
|
void start(void * const ip,
|
|
|
|
void * const sp,
|
|
|
|
unsigned const cpu_id,
|
|
|
|
unsigned const pd_id,
|
|
|
|
Native_utcb * const utcb_phys,
|
|
|
|
Native_utcb * const utcb_virt);
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Pause this thread
|
|
|
|
*/
|
|
|
|
void pause();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop this thread
|
|
|
|
*/
|
|
|
|
void stop();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume this thread
|
|
|
|
*/
|
|
|
|
int resume();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a request and await the reply
|
|
|
|
*/
|
|
|
|
void request_and_wait(Thread * const dest, size_t const size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wait for any request
|
|
|
|
*/
|
|
|
|
void wait_for_request();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reply to the last request
|
|
|
|
*/
|
|
|
|
void reply(size_t const size, bool const await_request);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a pagefault that originates from this thread
|
|
|
|
*
|
|
|
|
* \param va virtual fault address
|
|
|
|
* \param w if fault was caused by a write access
|
|
|
|
*/
|
|
|
|
void pagefault(addr_t const va, bool const w);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get unique thread ID, avoid method ambiguousness
|
|
|
|
*/
|
|
|
|
unsigned id() const { return Object::id(); }
|
|
|
|
|
|
|
|
/**
|
2013-05-22 14:41:47 +02:00
|
|
|
* Gets called when we await a signal at 'receiver'
|
2012-11-30 14:08:42 +01:00
|
|
|
*/
|
2013-05-22 14:41:47 +02:00
|
|
|
void await_signal(Kernel::Signal_receiver * receiver);
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets called when we have received a signal at a signal receiver
|
|
|
|
*/
|
2013-02-18 13:58:09 +01:00
|
|
|
void received_signal();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle the exception that currently blocks this thread
|
|
|
|
*/
|
|
|
|
void handle_exception();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Continue executing this thread in userland
|
|
|
|
*/
|
2013-08-23 00:18:58 +02:00
|
|
|
void proceed();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
2013-02-18 13:58:09 +01:00
|
|
|
void kill_signal_context_blocks();
|
|
|
|
|
|
|
|
void kill_signal_context_done();
|
2012-11-30 14:08:42 +01:00
|
|
|
|
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
Platform_thread * platform_thread() const {
|
|
|
|
return _platform_thread; }
|
|
|
|
|
|
|
|
void pager(Thread * const p) { _pager = p; }
|
|
|
|
|
|
|
|
unsigned pd_id() const { return _pd_id; }
|
|
|
|
|
|
|
|
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _CORE__KERNEL__THREAD_H_ */
|
|
|
|
|