mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-10 21:01:49 +00:00
parent
45d37e275d
commit
96bbca6191
@ -341,7 +341,7 @@ namespace Kernel
|
||||
* \retval -1 failed
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
@ -352,23 +352,33 @@ namespace Kernel
|
||||
/**
|
||||
* 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() {
|
||||
return (size_t)syscall(WAIT_FOR_REQUEST); }
|
||||
inline int wait_for_request()
|
||||
{
|
||||
return (int)syscall(WAIT_FOR_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
|
||||
*
|
||||
* \return request size (beginning with the callers UTCB base)
|
||||
* if await_request was set
|
||||
* \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.
|
||||
*/
|
||||
inline size_t reply(size_t const size, bool const await_request) {
|
||||
return (size_t)syscall(REPLY, size, await_request); }
|
||||
inline int reply(bool const await_request)
|
||||
{
|
||||
return (int)syscall(REPLY, await_request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
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)
|
||||
static void utcb_to_msgbuf(Msgbuf_base * const msgbuf)
|
||||
{
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
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";
|
||||
msg_size = utcb->max_ipc_msg_size();
|
||||
msg_size = msgbuf->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)
|
||||
{
|
||||
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();
|
||||
enum { NAME_SIZE = sizeof(local_name) };
|
||||
@ -161,10 +118,10 @@ void Ipc_client::_call()
|
||||
|
||||
/* send request and receive reply */
|
||||
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());
|
||||
if (error) { throw Blocking_canceled(); }
|
||||
sized_utcb_to_msgbuf(_rcv_msg);
|
||||
utcb_to_msgbuf(_rcv_msg);
|
||||
|
||||
/* reset unmarshaller */
|
||||
_write_offset = _read_offset = RPC_OBJECT_ID_SIZE;
|
||||
@ -204,14 +161,23 @@ void Ipc_server::_prepare_next_reply_wait()
|
||||
void Ipc_server::_wait()
|
||||
{
|
||||
/* 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 */
|
||||
_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()
|
||||
@ -223,9 +189,14 @@ void Ipc_server::_reply_wait()
|
||||
return;
|
||||
}
|
||||
/* send reply and receive next request */
|
||||
msgbuf_to_utcb(_snd_msg, _write_offset, Ipc_ostream::_dst.local_name());
|
||||
utcb_to_msgbuf(_rcv_msg, Kernel::reply(_write_offset, 1));
|
||||
|
||||
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 {
|
||||
PERR("failed to receive request");
|
||||
throw Blocking_canceled();
|
||||
}
|
||||
/* update server state */
|
||||
_prepare_next_reply_wait();
|
||||
}
|
||||
|
@ -95,17 +95,24 @@ Pager_capability Pager_entrypoint::manage(Pager_object * const o)
|
||||
|
||||
void Ipc_pager::wait_for_first_fault()
|
||||
{
|
||||
/* receive message */
|
||||
size_t const s = Kernel::wait_for_request();
|
||||
_wait_for_fault(s);
|
||||
while (Kernel::wait_for_request()) { PERR("failed to receive fault"); }
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
_wait_for_fault(utcb->ipc_msg_size());
|
||||
}
|
||||
|
||||
|
||||
void Ipc_pager::wait_for_fault()
|
||||
{
|
||||
/* receive first message */
|
||||
size_t const s = Kernel::reply(0, 1);
|
||||
_wait_for_fault(s);
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
utcb->ipc_msg_size(0);
|
||||
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 */
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
Pagefault * const pf = (Pagefault *)utcb;
|
||||
Pagefault * const pf = (Pagefault *)utcb->ipc_msg_base();
|
||||
if (pf->valid())
|
||||
{
|
||||
/* 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 */
|
||||
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 */
|
||||
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; }
|
||||
|
||||
default: {
|
||||
|
@ -102,7 +102,7 @@ class Kernel::Ipc_node
|
||||
/* update state */
|
||||
if (_state != PREPARE_AND_AWAIT_REPLY) { _state = INACTIVE; }
|
||||
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 */
|
||||
if (_state == AWAIT_REQUEST) {
|
||||
_receive_request(r);
|
||||
_await_ipc_succeeded(0, _inbuf.size);
|
||||
_await_ipc_succeeded(_inbuf.size);
|
||||
return;
|
||||
}
|
||||
/* cannot receive yet, so queue request */
|
||||
@ -175,7 +175,7 @@ class Kernel::Ipc_node
|
||||
_outbuf_dst = 0;
|
||||
if (!_inbuf.src) { _state = INACTIVE; }
|
||||
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
|
||||
*
|
||||
* \param s size of incoming message
|
||||
* \param reply wether the received message is a reply
|
||||
* \param s size of incoming message
|
||||
*/
|
||||
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
|
||||
*
|
||||
* \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:
|
||||
|
||||
@ -319,16 +316,16 @@ class Kernel::Ipc_node
|
||||
case AWAIT_REPLY:
|
||||
_cancel_outbuf_request();
|
||||
_state = INACTIVE;
|
||||
_await_ipc_failed(1);
|
||||
_await_ipc_failed();
|
||||
return;
|
||||
case AWAIT_REQUEST:
|
||||
_state = INACTIVE;
|
||||
_await_ipc_failed(0);
|
||||
_await_ipc_failed();
|
||||
return;
|
||||
case PREPARE_AND_AWAIT_REPLY:
|
||||
_cancel_outbuf_request();
|
||||
_state = PREPARE_REPLY;
|
||||
_await_ipc_failed(1);
|
||||
_await_ipc_failed();
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
|
@ -90,7 +90,8 @@ void Thread::_received_ipc_request(size_t const s)
|
||||
{
|
||||
switch (_state) {
|
||||
case SCHEDULED:
|
||||
user_arg_0(s);
|
||||
_phys_utcb->ipc_msg_size(s);
|
||||
user_arg_0(0);
|
||||
return;
|
||||
default:
|
||||
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) {
|
||||
case AWAITS_IPC:
|
||||
/* FIXME: return error codes on all IPC transfers */
|
||||
if (reply) {
|
||||
_phys_utcb->ipc_msg_size(s);
|
||||
user_arg_0(0);
|
||||
_schedule();
|
||||
} else {
|
||||
user_arg_0(s);
|
||||
_schedule();
|
||||
}
|
||||
_phys_utcb->ipc_msg_size(s);
|
||||
user_arg_0(0);
|
||||
_schedule();
|
||||
return;
|
||||
case AWAITS_PAGER_IPC:
|
||||
_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) {
|
||||
case AWAITS_IPC:
|
||||
/* FIXME: return error codes on all IPC transfers */
|
||||
if (reply) {
|
||||
user_arg_0(-1);
|
||||
_schedule();
|
||||
} else {
|
||||
PERR("failed to receive IPC");
|
||||
_stop();
|
||||
}
|
||||
user_arg_0(-1);
|
||||
_schedule();
|
||||
return;
|
||||
case SCHEDULED:
|
||||
PERR("failed to receive IPC");
|
||||
@ -615,7 +604,9 @@ void Thread::_syscall_get_thread()
|
||||
*/
|
||||
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()
|
||||
{
|
||||
size_t const msg_size = user_arg_1();
|
||||
bool const await_request = user_arg_2();
|
||||
bool const await_request = user_arg_1();
|
||||
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) {
|
||||
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); }
|
||||
}
|
||||
|
||||
|
@ -209,8 +209,8 @@ class Kernel::Thread
|
||||
|
||||
void _received_ipc_request(size_t const s);
|
||||
void _await_ipc();
|
||||
void _await_ipc_succeeded(bool const reply, size_t const s);
|
||||
void _await_ipc_failed(bool const reply);
|
||||
void _await_ipc_succeeded(size_t const s);
|
||||
void _await_ipc_failed();
|
||||
|
||||
|
||||
/***************
|
||||
|
Loading…
x
Reference in New Issue
Block a user