hw: send reply size & receive request size by UTCB

ref #874
This commit is contained in:
Martin Stein 2013-10-17 13:51:17 +02:00 committed by Norman Feske
parent 45d37e275d
commit 96bbca6191
6 changed files with 101 additions and 114 deletions

View File

@ -341,7 +341,7 @@ namespace Kernel
* \retval -1 failed * \retval -1 failed
* *
* If the call returns successful the callers UTCB provides * If the call returns successful the callers UTCB provides
* a valid reply message and its size. * a valid reply message and its metadata.
*/ */
inline int request_and_wait(unsigned const id) inline int request_and_wait(unsigned const id)
{ {
@ -352,23 +352,33 @@ namespace Kernel
/** /**
* Wait for next IPC request, discard current request * Wait for next IPC request, discard current request
* *
* \return size of received request (beginning with the callers UTCB base) * \retval 0 succeeded
* \retval -1 failed
*
* If the call returns successful the callers UTCB provides
* a valid request message and its metadata.
*/ */
inline size_t wait_for_request() { inline int wait_for_request()
return (size_t)syscall(WAIT_FOR_REQUEST); } {
return (int)syscall(WAIT_FOR_REQUEST);
}
/** /**
* Reply to last IPC request * Reply to last IPC request
* *
* \param size reply size (beginning with the callers UTCB base)
* \param await_request if the call shall await and fetch next request * \param await_request if the call shall await and fetch next request
* *
* \return request size (beginning with the callers UTCB base) * \retval 0 succeeded
* if await_request was set * \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.
*/ */
inline size_t reply(size_t const size, bool const await_request) { inline int reply(bool const await_request)
return (size_t)syscall(REPLY, size, await_request); } {
return (int)syscall(REPLY, await_request);
}
/** /**

View File

@ -38,68 +38,25 @@ enum
***************/ ***************/
/** /**
* Limit message size to the size of UTCB and message buffer * Copy message from the callers UTCB to message buffer
*/ */
void limit_msg_size(Msgbuf_base * const msgbuf, Native_utcb * const utcb, static void utcb_to_msgbuf(Msgbuf_base * const msgbuf)
size_t & size)
{
if (size > utcb->size() || size > msgbuf->size()) {
kernel_log() << __PRETTY_FUNCTION__ << ": truncate message\n";
size = utcb->size() < msgbuf->size() ? utcb->size() : msgbuf->size();
}
}
/**
* Copy message payload to message buffer
*/
static void utcb_to_msgbuf(Msgbuf_base * const msgbuf, size_t size)
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
limit_msg_size(msgbuf, utcb, size);
memcpy(msgbuf->buf, utcb->base(), size);
}
/**
* Copy message payload with size header to message buffer
*
* This function pioneers IPC messages with headers and will
* replace utcb_to_msgbuf sometime.
*/
static void sized_utcb_to_msgbuf(Msgbuf_base * const msgbuf)
{ {
Native_utcb * const utcb = Thread_base::myself()->utcb(); Native_utcb * const utcb = Thread_base::myself()->utcb();
size_t msg_size = utcb->ipc_msg_size(); size_t msg_size = utcb->ipc_msg_size();
if (msg_size > utcb->max_ipc_msg_size()) { if (msg_size > msgbuf->size()) {
kernel_log() << "oversized IPC message\n"; kernel_log() << "oversized IPC message\n";
msg_size = utcb->max_ipc_msg_size(); msg_size = msgbuf->size();
} }
memcpy(msgbuf->buf, utcb->ipc_msg_base(), msg_size); memcpy(msgbuf->buf, utcb->ipc_msg_base(), msg_size);
} }
/** /**
* Copy message payload to the UTCB * Copy message from message buffer to the callers UTCB
*/ */
static void msgbuf_to_utcb(Msgbuf_base * const msgbuf, size_t size, static void msgbuf_to_utcb(Msgbuf_base * const msg_buf, size_t msg_size,
unsigned const local_name) unsigned const local_name)
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
*(unsigned *)utcb->base() = local_name;
size += sizeof(local_name);
limit_msg_size(msgbuf, utcb, size);
memcpy((unsigned *)utcb->base() + 1, (unsigned *)msgbuf->buf + 1, size);
}
/**
* Copy message payload with size header to the UTCB
*
* This function pioneers IPC messages with headers and will
* replace msgbuf_to_utcb sometime.
*/
static void msgbuf_to_sized_utcb(Msgbuf_base * const msg_buf, size_t msg_size,
unsigned const local_name)
{ {
Native_utcb * const utcb = Thread_base::myself()->utcb(); Native_utcb * const utcb = Thread_base::myself()->utcb();
enum { NAME_SIZE = sizeof(local_name) }; enum { NAME_SIZE = sizeof(local_name) };
@ -161,10 +118,10 @@ void Ipc_client::_call()
/* send request and receive reply */ /* send request and receive reply */
unsigned const local_name = Ipc_ostream::_dst.local_name(); unsigned const local_name = Ipc_ostream::_dst.local_name();
msgbuf_to_sized_utcb(_snd_msg, _write_offset, local_name); msgbuf_to_utcb(_snd_msg, _write_offset, local_name);
int error = request_and_wait(Ipc_ostream::_dst.dst()); int error = request_and_wait(Ipc_ostream::_dst.dst());
if (error) { throw Blocking_canceled(); } if (error) { throw Blocking_canceled(); }
sized_utcb_to_msgbuf(_rcv_msg); utcb_to_msgbuf(_rcv_msg);
/* reset unmarshaller */ /* reset unmarshaller */
_write_offset = _read_offset = RPC_OBJECT_ID_SIZE; _write_offset = _read_offset = RPC_OBJECT_ID_SIZE;
@ -204,14 +161,23 @@ void Ipc_server::_prepare_next_reply_wait()
void Ipc_server::_wait() void Ipc_server::_wait()
{ {
/* receive next request */ /* receive next request */
utcb_to_msgbuf(_rcv_msg, Kernel::wait_for_request()); int const error = Kernel::wait_for_request();
if (!error) { utcb_to_msgbuf(_rcv_msg); }
else {
PERR("failed to receive request");
throw Blocking_canceled();
}
/* update server state */ /* update server state */
_prepare_next_reply_wait(); _prepare_next_reply_wait();
} }
void Ipc_server::_reply() { Kernel::reply(_write_offset, 0); } void Ipc_server::_reply()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
utcb->ipc_msg_size(_write_offset);
Kernel::reply(0);
}
void Ipc_server::_reply_wait() void Ipc_server::_reply_wait()
@ -223,9 +189,14 @@ void Ipc_server::_reply_wait()
return; return;
} }
/* send reply and receive next request */ /* send reply and receive next request */
msgbuf_to_utcb(_snd_msg, _write_offset, Ipc_ostream::_dst.local_name()); unsigned const local_name = Ipc_ostream::_dst.local_name();
utcb_to_msgbuf(_rcv_msg, Kernel::reply(_write_offset, 1)); msgbuf_to_utcb(_snd_msg, _write_offset, local_name);
int const error = Kernel::reply(1);
if (!error) { utcb_to_msgbuf(_rcv_msg); }
else {
PERR("failed to receive request");
throw Blocking_canceled();
}
/* update server state */ /* update server state */
_prepare_next_reply_wait(); _prepare_next_reply_wait();
} }

View File

@ -95,17 +95,24 @@ Pager_capability Pager_entrypoint::manage(Pager_object * const o)
void Ipc_pager::wait_for_first_fault() void Ipc_pager::wait_for_first_fault()
{ {
/* receive message */ while (Kernel::wait_for_request()) { PERR("failed to receive fault"); }
size_t const s = Kernel::wait_for_request(); Native_utcb * const utcb = Thread_base::myself()->utcb();
_wait_for_fault(s); _wait_for_fault(utcb->ipc_msg_size());
} }
void Ipc_pager::wait_for_fault() void Ipc_pager::wait_for_fault()
{ {
/* receive first message */ Native_utcb * const utcb = Thread_base::myself()->utcb();
size_t const s = Kernel::reply(0, 1); utcb->ipc_msg_size(0);
_wait_for_fault(s); int err = Kernel::reply(1);
if (err) {
PERR("failed to receive fault");
while (Kernel::wait_for_request()) {
PERR("failed to receive fault");
}
}
_wait_for_fault(utcb->ipc_msg_size());
} }
@ -122,7 +129,7 @@ void Ipc_pager::_wait_for_fault(size_t s)
/* message is a pagefault */ /* message is a pagefault */
Native_utcb * const utcb = Thread_base::myself()->utcb(); Native_utcb * const utcb = Thread_base::myself()->utcb();
Pagefault * const pf = (Pagefault *)utcb; Pagefault * const pf = (Pagefault *)utcb->ipc_msg_base();
if (pf->valid()) if (pf->valid())
{ {
/* give our caller the chance to handle the fault */ /* give our caller the chance to handle the fault */
@ -140,11 +147,19 @@ void Ipc_pager::_wait_for_fault(size_t s)
/* message is a release request from a RM session */ /* message is a release request from a RM session */
Native_utcb * const utcb = Thread_base::myself()->utcb(); Native_utcb * const utcb = Thread_base::myself()->utcb();
Pagefault_resolved * const msg = (Pagefault_resolved *)utcb; void * const msg_base = utcb->ipc_msg_base();
Pagefault_resolved * const msg = (Pagefault_resolved *)msg_base;
/* resume faulter, send ack to RM and get the next message */ /* resume faulter, send ack to RM and get the next message */
Kernel::resume_thread(msg->pager_object->badge()); Kernel::resume_thread(msg->pager_object->badge());
s = Kernel::reply(0, 1); utcb->ipc_msg_size(0);
if (Kernel::reply(1)) {
PERR("failed to receive fault");
while (Kernel::wait_for_request()) {
PERR("failed to receive fault");
}
}
s = utcb->ipc_msg_size();
continue; } continue; }
default: { default: {

View File

@ -102,7 +102,7 @@ class Kernel::Ipc_node
/* update state */ /* update state */
if (_state != PREPARE_AND_AWAIT_REPLY) { _state = INACTIVE; } if (_state != PREPARE_AND_AWAIT_REPLY) { _state = INACTIVE; }
else { _state = PREPARE_REPLY; } else { _state = PREPARE_REPLY; }
_await_ipc_succeeded(1, _inbuf.size); _await_ipc_succeeded(_inbuf.size);
} }
/** /**
@ -113,7 +113,7 @@ class Kernel::Ipc_node
/* directly receive request if we've awaited it */ /* directly receive request if we've awaited it */
if (_state == AWAIT_REQUEST) { if (_state == AWAIT_REQUEST) {
_receive_request(r); _receive_request(r);
_await_ipc_succeeded(0, _inbuf.size); _await_ipc_succeeded(_inbuf.size);
return; return;
} }
/* cannot receive yet, so queue request */ /* cannot receive yet, so queue request */
@ -175,7 +175,7 @@ class Kernel::Ipc_node
_outbuf_dst = 0; _outbuf_dst = 0;
if (!_inbuf.src) { _state = INACTIVE; } if (!_inbuf.src) { _state = INACTIVE; }
else { _state = PREPARE_REPLY; } else { _state = PREPARE_REPLY; }
_await_ipc_failed(1); _await_ipc_failed();
} }
} }
@ -192,17 +192,14 @@ class Kernel::Ipc_node
/** /**
* IPC node returned from waiting due to message receipt * IPC node returned from waiting due to message receipt
* *
* \param s size of incoming message * \param s size of incoming message
* \param reply wether the received message is a reply
*/ */
virtual void _await_ipc_succeeded(bool const reply, size_t const s) = 0; virtual void _await_ipc_succeeded(size_t const s) = 0;
/** /**
* IPC node returned from waiting due to cancellation * IPC node returned from waiting due to cancellation
*
* \param reply wether the received message is a reply
*/ */
virtual void _await_ipc_failed(bool const reply) = 0; virtual void _await_ipc_failed() = 0;
public: public:
@ -319,16 +316,16 @@ class Kernel::Ipc_node
case AWAIT_REPLY: case AWAIT_REPLY:
_cancel_outbuf_request(); _cancel_outbuf_request();
_state = INACTIVE; _state = INACTIVE;
_await_ipc_failed(1); _await_ipc_failed();
return; return;
case AWAIT_REQUEST: case AWAIT_REQUEST:
_state = INACTIVE; _state = INACTIVE;
_await_ipc_failed(0); _await_ipc_failed();
return; return;
case PREPARE_AND_AWAIT_REPLY: case PREPARE_AND_AWAIT_REPLY:
_cancel_outbuf_request(); _cancel_outbuf_request();
_state = PREPARE_REPLY; _state = PREPARE_REPLY;
_await_ipc_failed(1); _await_ipc_failed();
return; return;
default: return; default: return;
} }

View File

@ -90,7 +90,8 @@ void Thread::_received_ipc_request(size_t const s)
{ {
switch (_state) { switch (_state) {
case SCHEDULED: case SCHEDULED:
user_arg_0(s); _phys_utcb->ipc_msg_size(s);
user_arg_0(0);
return; return;
default: default:
PERR("wrong thread state to receive IPC"); PERR("wrong thread state to receive IPC");
@ -116,19 +117,13 @@ void Thread::_await_ipc()
} }
void Thread::_await_ipc_succeeded(bool const reply, size_t const s) void Thread::_await_ipc_succeeded(size_t const s)
{ {
switch (_state) { switch (_state) {
case AWAITS_IPC: case AWAITS_IPC:
/* FIXME: return error codes on all IPC transfers */ _phys_utcb->ipc_msg_size(s);
if (reply) { user_arg_0(0);
_phys_utcb->ipc_msg_size(s); _schedule();
user_arg_0(0);
_schedule();
} else {
user_arg_0(s);
_schedule();
}
return; return;
case AWAITS_PAGER_IPC: case AWAITS_PAGER_IPC:
_schedule(); _schedule();
@ -144,18 +139,12 @@ void Thread::_await_ipc_succeeded(bool const reply, size_t const s)
} }
void Thread::_await_ipc_failed(bool const reply) void Thread::_await_ipc_failed()
{ {
switch (_state) { switch (_state) {
case AWAITS_IPC: case AWAITS_IPC:
/* FIXME: return error codes on all IPC transfers */ user_arg_0(-1);
if (reply) { _schedule();
user_arg_0(-1);
_schedule();
} else {
PERR("failed to receive IPC");
_stop();
}
return; return;
case SCHEDULED: case SCHEDULED:
PERR("failed to receive IPC"); PERR("failed to receive IPC");
@ -615,7 +604,9 @@ void Thread::_syscall_get_thread()
*/ */
void Thread::_syscall_wait_for_request() void Thread::_syscall_wait_for_request()
{ {
Ipc_node::await_request(_phys_utcb->base(), _phys_utcb->size()); void * const buf_base = _phys_utcb->ipc_msg_base();
size_t const buf_size = _phys_utcb->max_ipc_msg_size();
Ipc_node::await_request(buf_base, buf_size);
} }
@ -641,12 +632,15 @@ void Thread::_syscall_request_and_wait()
*/ */
void Thread::_syscall_reply() void Thread::_syscall_reply()
{ {
size_t const msg_size = user_arg_1(); bool const await_request = user_arg_1();
bool const await_request = user_arg_2(); void * const msg_base = _phys_utcb->ipc_msg_base();
size_t const msg_size = _phys_utcb->ipc_msg_size();
Ipc_node::send_reply(msg_base, msg_size);
Ipc_node::send_reply(_phys_utcb->base(), msg_size);
if (await_request) { if (await_request) {
Ipc_node::await_request(_phys_utcb->base(), _phys_utcb->size()); void * const buf_base = _phys_utcb->ipc_msg_base();
size_t const buf_size = _phys_utcb->max_ipc_msg_size();
Ipc_node::await_request(buf_base, buf_size);
} else { user_arg_0(0); } } else { user_arg_0(0); }
} }

View File

@ -209,8 +209,8 @@ class Kernel::Thread
void _received_ipc_request(size_t const s); void _received_ipc_request(size_t const s);
void _await_ipc(); void _await_ipc();
void _await_ipc_succeeded(bool const reply, size_t const s); void _await_ipc_succeeded(size_t const s);
void _await_ipc_failed(bool const reply); void _await_ipc_failed();
/*************** /***************