hw: communicate message type through UTCB

ref #874
This commit is contained in:
Martin Stein 2013-10-17 16:07:47 +02:00 committed by Norman Feske
parent 1e7eb4512e
commit 6f935af278
5 changed files with 85 additions and 60 deletions

View File

@ -85,22 +85,43 @@ namespace Genode
bool valid() const { return thread_id != 0; }
};
/**
* Types of synchronously communicated messages
*/
struct Msg_type
{
enum Id {
INVALID = 0,
IPC = 1,
};
};
/**
* Message that is communicated synchronously
*/
struct Msg
{
Msg_type::Id type;
uint8_t data[];
};
/**
* Message that is communicated between user threads
*/
struct Ipc_msg : Msg
{
size_t size;
uint8_t data[];
};
/**
* Describes a userland-thread-context region
*/
struct Native_utcb
{
/**
* Structure of an IPC message held by the UTCB
*/
struct Ipc_msg
{
size_t size;
uint8_t data[];
};
union {
uint8_t data[1 << MIN_MAPPING_SIZE_LOG2];
Msg msg;
Ipc_msg ipc_msg;
};

View File

@ -333,51 +333,42 @@ namespace Kernel
/**
* Send IPC request and wait for reply
* Send IPC request and await corresponding IPC reply
*
* \param id kernel name of the server thread
*
* \retval 0 successful
* \retval -1 failed
*
* If the call returns successful the callers UTCB provides
* a valid reply message and its metadata.
* As soon as call returns, callers UTCB provides received message.
*/
inline int request_and_wait(unsigned const id)
inline void request_and_wait(unsigned const id)
{
return (int)syscall(REQUEST_AND_WAIT, id);
syscall(REQUEST_AND_WAIT, id);
}
/**
* Wait for next IPC request, discard current request
* Await the receipt of a message
*
* \retval 0 succeeded
* \retval -1 failed
* \return type of received message
*
* If the call returns successful the callers UTCB provides
* a valid request message and its metadata.
* As soon as call returns, callers UTCB provides received message.
*/
inline int wait_for_request()
inline void wait_for_request()
{
return (int)syscall(WAIT_FOR_REQUEST);
syscall(WAIT_FOR_REQUEST);
}
/**
* Reply to last IPC request
* Reply to lastly received message
*
* \param await_request if the call shall await and fetch next request
* \param await_message wether the call shall await receipt of a message
*
* \retval 0 succeeded
* \retval -1 failed to receive request
*
* If await_request = 1 and the call returns successful the callers UTCB
* provides a valid request message and its metadata.
* If await_request = 1, callers UTCB provides received message
* as soon as call returns
*/
inline int reply(bool const await_request)
inline void reply(bool const await_message)
{
return (int)syscall(REPLY, await_request);
syscall(REPLY, await_message);
}

View File

@ -92,7 +92,7 @@ Ipc_ostream::Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg)
void Ipc_istream::_wait()
{
/* FIXME this shall be not supported */
/* FIXME: this shall be not supported */
Kernel::pause_thread();
}
@ -116,11 +116,17 @@ void Ipc_client::_call()
{
using namespace Kernel;
/* send request and receive reply */
/* send request */
unsigned const local_name = Ipc_ostream::_dst.local_name();
msgbuf_to_utcb(_snd_msg, _write_offset, local_name);
int error = request_and_wait(Ipc_ostream::_dst.dst());
if (error) { throw Blocking_canceled(); }
request_and_wait(Ipc_ostream::_dst.dst());
/* receive reply */
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive reply");
throw Blocking_canceled();
}
utcb_to_msgbuf(_rcv_msg);
/* reset unmarshaller */
@ -161,12 +167,14 @@ void Ipc_server::_prepare_next_reply_wait()
void Ipc_server::_wait()
{
/* receive next request */
int const error = Kernel::wait_for_request();
if (!error) { utcb_to_msgbuf(_rcv_msg); }
else {
Kernel::wait_for_request();
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive request");
throw Blocking_canceled();
}
utcb_to_msgbuf(_rcv_msg);
/* update server state */
_prepare_next_reply_wait();
}
@ -182,21 +190,24 @@ void Ipc_server::_reply()
void Ipc_server::_reply_wait()
{
/* if there is no reply simply do wait for request */
/* FIXME this shall be not supported */
/* if there is no reply, wait for request */
if (!_reply_needed) {
_wait();
return;
}
/* send reply and receive next request */
/* send reply an await request */
unsigned const local_name = Ipc_ostream::_dst.local_name();
msgbuf_to_utcb(_snd_msg, _write_offset, local_name);
int const error = Kernel::reply(1);
if (!error) { utcb_to_msgbuf(_rcv_msg); }
else {
Kernel::reply(1);
/* fetch request */
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive request");
throw Blocking_canceled();
}
utcb_to_msgbuf(_rcv_msg);
/* update server state */
_prepare_next_reply_wait();
}

View File

@ -95,8 +95,12 @@ Pager_capability Pager_entrypoint::manage(Pager_object * const o)
void Ipc_pager::wait_for_first_fault()
{
while (Kernel::wait_for_request()) { PERR("failed to receive fault"); }
Native_utcb * const utcb = Thread_base::myself()->utcb();
while (1) {
Kernel::wait_for_request();
if (utcb->msg.type == Msg_type::IPC) { break; }
PERR("failed to receive fault");
}
_wait_for_fault(utcb->ipc_msg.size);
}
@ -105,12 +109,10 @@ void Ipc_pager::wait_for_fault()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
utcb->ipc_msg.size = 0;
int err = Kernel::reply(1);
if (err) {
Kernel::reply(1);
while (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive fault");
while (Kernel::wait_for_request()) {
PERR("failed to receive fault");
}
Kernel::wait_for_request();
}
_wait_for_fault(utcb->ipc_msg.size);
}
@ -153,11 +155,10 @@ void Ipc_pager::_wait_for_fault(size_t s)
/* resume faulter, send ack to RM and get the next message */
Kernel::resume_thread(msg->pager_object->badge());
utcb->ipc_msg.size = 0;
if (Kernel::reply(1)) {
Kernel::reply(1);
while (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive fault");
while (Kernel::wait_for_request()) {
PERR("failed to receive fault");
}
Kernel::wait_for_request();
}
s = utcb->ipc_msg.size;
continue; }

View File

@ -24,6 +24,7 @@
using namespace Kernel;
typedef Genode::Thread_state Thread_state;
typedef Genode::Msg_type Msg_type;
bool Thread::_core() const
@ -90,8 +91,8 @@ void Thread::_received_ipc_request(size_t const s)
{
switch (_state) {
case SCHEDULED:
_phys_utcb->msg.type = Msg_type::IPC;
_phys_utcb->ipc_msg.size = s;
user_arg_0(0);
return;
default:
PERR("wrong thread state to receive IPC");
@ -121,8 +122,8 @@ void Thread::_await_ipc_succeeded(size_t const s)
{
switch (_state) {
case AWAITS_IPC:
_phys_utcb->msg.type = Msg_type::IPC;
_phys_utcb->ipc_msg.size = s;
user_arg_0(0);
_schedule();
return;
case AWAITS_PAGER_IPC:
@ -143,7 +144,7 @@ void Thread::_await_ipc_failed()
{
switch (_state) {
case AWAITS_IPC:
user_arg_0(-1);
_phys_utcb->msg.type = Msg_type::INVALID;
_schedule();
return;
case SCHEDULED:
@ -641,7 +642,7 @@ void Thread::_syscall_reply()
void * const buf_base = _phys_utcb->ipc_msg.data;
size_t const buf_size = _phys_utcb->ipc_msg_max_size();
Ipc_node::await_request(buf_base, buf_size);
} else { user_arg_0(0); }
} else { _phys_utcb->msg.type = Msg_type::INVALID; }
}