/* * \brief Codezero implementation of the IPC API * \author Norman Feske * \date 2009-10-02 */ /* * Copyright (C) 2009-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* Codezero includes */ #include /* Genode includes */ #include #include #include #include using namespace Genode; using namespace Codezero; enum { verbose_ipc = false }; /***************** ** Ipc_ostream ** *****************/ void Ipc_ostream::_send() { if (verbose_ipc) PDBG("thread %d sends IPC to %d, write_offset=%d", thread_myself(), _dst.dst(), _write_offset); umword_t snd_size = min(_write_offset, (unsigned)L4_IPC_EXTENDED_MAX_SIZE); *(umword_t *)_snd_msg->addr() = _dst.local_name(); int ret = l4_send_extended(_dst.dst(), L4_IPC_TAG_SYNC_EXTENDED, snd_size, _snd_msg->addr()); if (ret < 0) PERR("l4_send_extended (to thread %d) returned ret=%d", _dst.dst(), ret); _write_offset = sizeof(umword_t); } Ipc_ostream::Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg) : Ipc_marshaller((char *)snd_msg->addr(), snd_msg->size()), _snd_msg(snd_msg), _dst(dst) { _write_offset = sizeof(umword_t); } /***************** ** Ipc_istream ** *****************/ void Ipc_istream::_wait() { umword_t *rcv_buf = (umword_t *)_rcv_msg->addr(); umword_t rcv_size = min(_rcv_msg->size(), (unsigned)L4_IPC_EXTENDED_MAX_SIZE); if (verbose_ipc) PDBG("thread %d waits for IPC from %d, rcv_buf at %p, rcv_size=%d", dst(), _rcv_cs, rcv_buf, (int)rcv_size); int ret = l4_receive_extended(_rcv_cs, rcv_size, rcv_buf); if (ret < 0) PERR("l4_receive_extended (from any) returned ret=%d", ret); if (verbose_ipc) PDBG("thread %d received IPC from %d", dst(), l4_get_sender()); _read_offset = sizeof(umword_t); } Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg) : Ipc_unmarshaller((char *)rcv_msg->addr(), rcv_msg->size()), Native_capability(thread_myself(), 0), _rcv_msg(rcv_msg) { _rcv_cs = L4_ANYTHREAD; _read_offset = sizeof(umword_t); } Ipc_istream::~Ipc_istream() { } /**************** ** Ipc_client ** ****************/ void Ipc_client::_call() { #warning l4_sendrecv_extended is not yet implemented in l4lib/arch/syslib.h _send(); _rcv_cs = Ipc_ostream::_dst.dst(); _wait(); _rcv_cs = L4_ANYTHREAD; _write_offset = _read_offset = sizeof(umword_t); } Ipc_client::Ipc_client(Native_capability const &srv, Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg, unsigned short) : Ipc_istream(rcv_msg), Ipc_ostream(srv, snd_msg), _result(0) { } /**************** ** Ipc_server ** ****************/ void Ipc_server::_prepare_next_reply_wait() { /* now we have a request to reply */ _reply_needed = true; /* leave space for return value at the beginning of the msgbuf */ _write_offset = 2*sizeof(umword_t); /* receive buffer offset */ _read_offset = sizeof(umword_t); } void Ipc_server::_wait() { /* wait for new server request */ try { Ipc_istream::_wait(); } catch (Blocking_canceled) { } /* define destination of next reply */ Ipc_ostream::_dst = Native_capability(l4_get_sender(), badge()); _prepare_next_reply_wait(); } void Ipc_server::_reply() { try { _send(); } catch (Ipc_error) { } _prepare_next_reply_wait(); } void Ipc_server::_reply_wait() { if (_reply_needed) _reply(); _wait(); } Ipc_server::Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg) : Ipc_istream(rcv_msg), Ipc_ostream(Native_capability(), snd_msg), _reply_needed(false) { }