Unify 'ipc.h' and 'ipc_generic.h' across platforms
The distinction between 'ipc.h' and 'ipc_generic.h' is no more. The only use case for platform-specific extensions of the IPC support was the marshalling of capabilities. However, this case is accommodated by a function interface ('_marshal_capability', '_unmarshal_capability'). By moving the implementation of these functions from the headers into the respective ipc libraries, we can abandon the platform-specific 'ipc.h' headers.
This commit is contained in:
parent
bbca9912e2
commit
bcdc706f42
|
@ -1,5 +1,6 @@
|
||||||
SRC_CC = ipc.cc pager.cc
|
SRC_CC = ipc.cc pager.cc ipc_marshal_cap.cc
|
||||||
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
||||||
LIBS = cap_copy
|
LIBS = cap_copy
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base/ipc
|
vpath %.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
SRC_CC = ipc.cc pager.cc
|
SRC_CC = ipc.cc pager.cc ipc_marshal_cap.cc
|
||||||
LIBS = cap_copy
|
LIBS = cap_copy
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base/ipc
|
vpath %.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Fiasco.OC-specific supplements to the IPC framework
|
|
||||||
* \author Norman Feske
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2010-01-27
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__IPC_H_
|
|
||||||
#define _INCLUDE__BASE__IPC_H_
|
|
||||||
|
|
||||||
#include <base/ipc_generic.h>
|
|
||||||
#include <util/assert.h>
|
|
||||||
|
|
||||||
|
|
||||||
inline void Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
|
|
||||||
{
|
|
||||||
using namespace Fiasco;
|
|
||||||
|
|
||||||
/* first transfer local capability value */
|
|
||||||
_write_to_buf(cap.local());
|
|
||||||
|
|
||||||
/* if it's a local capability we're done */
|
|
||||||
if (cap.local())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (cap.valid()) {
|
|
||||||
if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst()))) {
|
|
||||||
_write_to_buf(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* transfer capability id */
|
|
||||||
_write_to_buf(cap.local_name());
|
|
||||||
|
|
||||||
/* only transfer kernel-capability if it's a valid one */
|
|
||||||
if (cap.valid())
|
|
||||||
_snd_msg->snd_append_cap_sel(cap.dst());
|
|
||||||
|
|
||||||
ASSERT(!cap.valid() ||
|
|
||||||
l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())),
|
|
||||||
"Send invalid cap");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap)
|
|
||||||
{
|
|
||||||
using namespace Fiasco;
|
|
||||||
|
|
||||||
long value = 0;
|
|
||||||
|
|
||||||
/* get local capability pointer from message buffer */
|
|
||||||
_read_from_buf(value);
|
|
||||||
|
|
||||||
/* if it's a local capability, the pointer is marshalled in the id */
|
|
||||||
if (value) {
|
|
||||||
cap = Capability<Native_capability>::local_cap((Native_capability*)value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* extract capability id from message buffer */
|
|
||||||
_read_from_buf(value);
|
|
||||||
|
|
||||||
/* if id is zero an invalid capability was transfered */
|
|
||||||
if (!value) {
|
|
||||||
cap = Native_capability();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try to insert received capability in the map and return it */
|
|
||||||
cap = Native_capability(cap_map()->insert_map(value, _rcv_msg->rcv_cap_sel()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__IPC_H_ */
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <base/ipc.h>
|
#include <base/ipc.h>
|
||||||
#include <base/ipc_msgbuf.h>
|
#include <base/ipc_msgbuf.h>
|
||||||
#include <base/thread.h>
|
#include <base/thread.h>
|
||||||
|
#include <util/assert.h>
|
||||||
|
|
||||||
/* base-foc/src/base/lock */
|
/* base-foc/src/base/lock */
|
||||||
#include <lock_helper.h> /* for 'thread_get_my_native_id()' */
|
#include <lock_helper.h> /* for 'thread_get_my_native_id()' */
|
||||||
|
@ -42,6 +43,66 @@ using namespace Genode;
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
** IPC marshalling support **
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
void Ipc_ostream::_marshal_capability(Native_capability const &cap)
|
||||||
|
{
|
||||||
|
/* first transfer local capability value */
|
||||||
|
_write_to_buf(cap.local());
|
||||||
|
|
||||||
|
/* if it's a local capability we're done */
|
||||||
|
if (cap.local())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cap.valid()) {
|
||||||
|
if (!l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst()))) {
|
||||||
|
_write_to_buf(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* transfer capability id */
|
||||||
|
_write_to_buf(cap.local_name());
|
||||||
|
|
||||||
|
/* only transfer kernel-capability if it's a valid one */
|
||||||
|
if (cap.valid())
|
||||||
|
_snd_msg->snd_append_cap_sel(cap.dst());
|
||||||
|
|
||||||
|
ASSERT(!cap.valid() ||
|
||||||
|
l4_msgtag_label(l4_task_cap_valid(L4_BASE_TASK_CAP, cap.dst())),
|
||||||
|
"Send invalid cap");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_istream::_unmarshal_capability(Native_capability &cap)
|
||||||
|
{
|
||||||
|
long value = 0;
|
||||||
|
|
||||||
|
/* get local capability pointer from message buffer */
|
||||||
|
_read_from_buf(value);
|
||||||
|
|
||||||
|
/* if it's a local capability, the pointer is marshalled in the id */
|
||||||
|
if (value) {
|
||||||
|
cap = Capability<Native_capability>::local_cap((Native_capability*)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extract capability id from message buffer */
|
||||||
|
_read_from_buf(value);
|
||||||
|
|
||||||
|
/* if id is zero an invalid capability was transfered */
|
||||||
|
if (!value) {
|
||||||
|
cap = Native_capability();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to insert received capability in the map and return it */
|
||||||
|
cap = Native_capability(cap_map()->insert_map(value, _rcv_msg->rcv_cap_sel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Utilities **
|
** Utilities **
|
||||||
***************/
|
***************/
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
SRC_CC = ipc.cc
|
SRC_CC = ipc.cc ipc_marshal_cap.cc
|
||||||
LIBS = cap_copy
|
LIBS = cap_copy
|
||||||
|
|
||||||
vpath ipc.cc $(REP_DIR)/src/base/ipc
|
vpath ipc.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#
|
#
|
||||||
# \brief Interprocess communication without thread implementations
|
# \brief Inter-process communication without thread implementations
|
||||||
# \author Martin Stein
|
# \author Martin Stein
|
||||||
# \date 2012-04-16
|
# \date 2012-04-16
|
||||||
#
|
#
|
||||||
|
|
||||||
# add C++ source files
|
# add C++ source files
|
||||||
SRC_CC += ipc.cc
|
SRC_CC += ipc.cc ipc_marshal_cap.cc
|
||||||
|
|
||||||
# declare source paths
|
# declare source paths
|
||||||
vpath ipc.cc $(REP_DIR)/src/base
|
vpath ipc.cc $(REP_DIR)/src/base
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Linux-specific supplements to the IPC framework
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2012-07-26
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2012-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__IPC_H_
|
|
||||||
#define _INCLUDE__BASE__IPC_H_
|
|
||||||
|
|
||||||
#include <base/ipc_generic.h>
|
|
||||||
|
|
||||||
|
|
||||||
inline void Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
|
|
||||||
{
|
|
||||||
if (cap.valid()) {
|
|
||||||
_write_to_buf(cap.local_name());
|
|
||||||
|
|
||||||
_snd_msg->append_cap(cap.dst().socket);
|
|
||||||
} else {
|
|
||||||
_write_to_buf(-1L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap)
|
|
||||||
{
|
|
||||||
long local_name = 0;
|
|
||||||
_read_from_buf(local_name);
|
|
||||||
|
|
||||||
if (local_name == -1) {
|
|
||||||
|
|
||||||
/* construct invalid capability */
|
|
||||||
cap = Genode::Native_capability();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* construct valid capability */
|
|
||||||
int const socket = _rcv_msg->read_cap();
|
|
||||||
cap = Native_capability(Cap_dst_policy::Dst(socket), local_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__IPC_H_ */
|
|
|
@ -46,6 +46,41 @@
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
** IPC marshalling support **
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
void Ipc_ostream::_marshal_capability(Native_capability const &cap)
|
||||||
|
{
|
||||||
|
if (cap.valid()) {
|
||||||
|
_write_to_buf(cap.local_name());
|
||||||
|
|
||||||
|
_snd_msg->append_cap(cap.dst().socket);
|
||||||
|
} else {
|
||||||
|
_write_to_buf(-1L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_istream::_unmarshal_capability(Native_capability &cap)
|
||||||
|
{
|
||||||
|
long local_name = 0;
|
||||||
|
_read_from_buf(local_name);
|
||||||
|
|
||||||
|
if (local_name == -1) {
|
||||||
|
|
||||||
|
/* construct invalid capability */
|
||||||
|
cap = Genode::Native_capability();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* construct valid capability */
|
||||||
|
int const socket = _rcv_msg->read_cap();
|
||||||
|
cap = Native_capability(Cap_dst_policy::Dst(socket), local_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
SRC_CC = ipc.cc
|
SRC_CC = ipc.cc ipc_marshal_cap.cc
|
||||||
SRC_CC += pager.cc
|
SRC_CC += pager.cc
|
||||||
LIBS += thread_context cap_copy
|
LIBS += thread_context cap_copy
|
||||||
|
|
||||||
vpath ipc.cc $(REP_DIR)/src/base/ipc
|
vpath ipc.cc $(REP_DIR)/src/base/ipc
|
||||||
vpath pager.cc $(REP_DIR)/src/base/ipc
|
vpath pager.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief NOVA-specific supplements to the IPC framework
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2010-01-27
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__IPC_H_
|
|
||||||
#define _INCLUDE__BASE__IPC_H_
|
|
||||||
|
|
||||||
#include <base/ipc_generic.h>
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
|
|
||||||
{
|
|
||||||
if (cap.valid())
|
|
||||||
_snd_msg->snd_append_pt_sel(cap.local_name(),
|
|
||||||
cap.dst().rights(),
|
|
||||||
cap.trans_map());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap)
|
|
||||||
{
|
|
||||||
addr_t pt_sel = _rcv_msg->rcv_pt_sel();
|
|
||||||
cap = Native_capability(pt_sel);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__IPC_H_ */
|
|
|
@ -24,6 +24,26 @@ using namespace Genode;
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
** IPC marshalling support **
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
void Ipc_ostream::_marshal_capability(Native_capability const &cap)
|
||||||
|
{
|
||||||
|
if (cap.valid())
|
||||||
|
_snd_msg->snd_append_pt_sel(cap.local_name(),
|
||||||
|
cap.dst().rights(),
|
||||||
|
cap.trans_map());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_istream::_unmarshal_capability(Native_capability &cap)
|
||||||
|
{
|
||||||
|
addr_t pt_sel = _rcv_msg->rcv_pt_sel();
|
||||||
|
cap = Native_capability(pt_sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Utilities **
|
** Utilities **
|
||||||
***************/
|
***************/
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
SRC_CC = ipc.cc pager.cc
|
SRC_CC = ipc.cc pager.cc ipc_marshal_cap.cc
|
||||||
LIBS = cap_copy
|
LIBS = cap_copy
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base/ipc
|
vpath %.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
SRC_CC = ipc.cc pager.cc
|
SRC_CC = ipc.cc pager.cc ipc_marshal_cap.cc
|
||||||
LIBS = cap_copy
|
LIBS = cap_copy
|
||||||
|
|
||||||
# disable warning about array boundaries, caused by L4 headers
|
# disable warning about array boundaries, caused by L4 headers
|
||||||
CC_WARN = -Wall -Wno-array-bounds
|
CC_WARN = -Wall -Wno-array-bounds
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base/ipc
|
vpath %.cc $(REP_DIR)/src/base/ipc
|
||||||
|
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc
|
||||||
|
|
|
@ -1,41 +1,632 @@
|
||||||
/*
|
/*
|
||||||
* \brief Generic IPC infrastructure
|
* \brief Generic IPC infrastructure
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
* \date 2009-10-02
|
* \date 2006-06-12
|
||||||
*
|
*
|
||||||
* This file is used for platforms that only use the generic IPC API. A platform
|
* Most of the marshalling and unmarshallung code is generic for IPC
|
||||||
* may extend the generic API with platform-specific marshalling operators by
|
* implementations among different platforms. In addition to the generic
|
||||||
* providing a custom version of 'ipc.h' in its 'base-<platform>' repository.
|
* marshalling items, platform-specific marshalling items can be realized
|
||||||
|
* via specialized stream operators defined in the platform-specific
|
||||||
|
* 'base/ipc.h'. Hence, this header file is never to be included directly.
|
||||||
|
* It should only be included by a platform-specific 'base/ipc.h' file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__IPC_H_
|
#ifndef _INCLUDE__BASE__IPC_GENERIC_H_
|
||||||
#define _INCLUDE__BASE__IPC_H_
|
#define _INCLUDE__BASE__IPC_GENERIC_H_
|
||||||
|
|
||||||
#include <base/ipc_generic.h>
|
#include <util/misc_math.h>
|
||||||
|
#include <util/string.h>
|
||||||
|
#include <base/errno.h>
|
||||||
|
#include <base/exception.h>
|
||||||
|
#include <base/capability.h>
|
||||||
|
#include <base/ipc_msgbuf.h>
|
||||||
|
#include <base/rpc_args.h>
|
||||||
|
#include <base/printf.h>
|
||||||
|
|
||||||
/**
|
namespace Genode {
|
||||||
* Marshalling of capabilities as plain data representation
|
|
||||||
*/
|
enum Ipc_ostream_send { IPC_SEND };
|
||||||
inline void
|
enum Ipc_istream_wait { IPC_WAIT };
|
||||||
Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
|
enum Ipc_client_call { IPC_CALL };
|
||||||
{
|
enum Ipc_server_reply { IPC_REPLY };
|
||||||
_write_to_buf(cap);
|
enum Ipc_server_reply_wait { IPC_REPLY_WAIT };
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
** Exception types **
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
class Ipc_error : public Exception { };
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marshal arguments into send message buffer
|
||||||
|
*/
|
||||||
|
class Ipc_marshaller
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
char *_sndbuf;
|
||||||
|
size_t _sndbuf_size;
|
||||||
|
unsigned _write_offset;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write value to send buffer
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void _write_to_buf(T const &value)
|
||||||
|
{
|
||||||
|
/* check buffer range */
|
||||||
|
if (_write_offset + sizeof(T) >= _sndbuf_size) return;
|
||||||
|
|
||||||
|
/* write integer to buffer */
|
||||||
|
*reinterpret_cast<T *>(&_sndbuf[_write_offset]) = value;
|
||||||
|
|
||||||
|
/* increment write pointer to next dword-aligned value */
|
||||||
|
_write_offset += align_natural(sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write bytes to send buffer
|
||||||
|
*/
|
||||||
|
void _write_to_buf(char const *src_addr, unsigned num_bytes)
|
||||||
|
{
|
||||||
|
/* check buffer range */
|
||||||
|
if (_write_offset + num_bytes >= _sndbuf_size) return;
|
||||||
|
|
||||||
|
/* copy buffer */
|
||||||
|
memcpy(&_sndbuf[_write_offset], src_addr, num_bytes);
|
||||||
|
|
||||||
|
/* increment write pointer to next dword-aligned value */
|
||||||
|
_write_offset += align_natural(num_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 'Rpc_in_buffer' to send buffer
|
||||||
|
*/
|
||||||
|
void _write_buffer_to_buf(Rpc_in_buffer_base const &b)
|
||||||
|
{
|
||||||
|
size_t size = b.size();
|
||||||
|
_write_to_buf(size);
|
||||||
|
_write_to_buf(b.base(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write array to send buffer
|
||||||
|
*/
|
||||||
|
template <typename T, size_t N>
|
||||||
|
void _write_to_buf(T const (&array)[N])
|
||||||
|
{
|
||||||
|
/* check buffer range */
|
||||||
|
if (_write_offset + sizeof(array) >= _sndbuf_size)
|
||||||
|
PERR("send buffer overrun");
|
||||||
|
|
||||||
|
memcpy(&_sndbuf[_write_offset], array, sizeof(array));
|
||||||
|
_write_offset += align_natural(sizeof(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Ipc_marshaller(char *sndbuf, size_t sndbuf_size)
|
||||||
|
: _sndbuf(sndbuf), _sndbuf_size(sndbuf_size), _write_offset(0) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmarshal arguments from receive buffer
|
||||||
|
*/
|
||||||
|
class Ipc_unmarshaller
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
char *_rcvbuf;
|
||||||
|
size_t _rcvbuf_size;
|
||||||
|
unsigned _read_offset;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read value of type T from buffer
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void _read_from_buf(T &value)
|
||||||
|
{
|
||||||
|
/* check receive buffer range */
|
||||||
|
if (_read_offset + sizeof(T) >= _rcvbuf_size) return;
|
||||||
|
|
||||||
|
/* return value from receive buffer */
|
||||||
|
value = *reinterpret_cast<T *>(&_rcvbuf[_read_offset]);
|
||||||
|
|
||||||
|
/* increment read pointer to next dword-aligned value */
|
||||||
|
_read_offset += align_natural(sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read 'Rpc_in_buffer' from receive buffer
|
||||||
|
*/
|
||||||
|
void _read_bytebuf_from_buf(Rpc_in_buffer_base &b)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
_read_from_buf(size);
|
||||||
|
b = Rpc_in_buffer_base(0, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check receive buffer range
|
||||||
|
*
|
||||||
|
* Note: The addr of the Rpc_in_buffer_base is a null pointer when this
|
||||||
|
* condition triggers.
|
||||||
|
*/
|
||||||
|
if (_read_offset + size >= _rcvbuf_size) {
|
||||||
|
PERR("message buffer overrun");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = Rpc_in_buffer_base(&_rcvbuf[_read_offset], size);
|
||||||
|
_read_offset += align_natural(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read array from receive buffer
|
||||||
|
*/
|
||||||
|
template <typename T, size_t N>
|
||||||
|
void _read_from_buf(T (&array)[N])
|
||||||
|
{
|
||||||
|
if (_read_offset + sizeof(array) >= _rcvbuf_size) {
|
||||||
|
PERR("receive buffer overrun");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(array, &_rcvbuf[_read_offset], sizeof(array));
|
||||||
|
_read_offset += align_natural(sizeof(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read long value at specified byte index of receive buffer
|
||||||
|
*/
|
||||||
|
long _long_at_idx(int idx) { return *(long *)(&_rcvbuf[idx]); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Ipc_unmarshaller(char *rcvbuf, size_t rcvbuf_size)
|
||||||
|
: _rcvbuf(rcvbuf), _rcvbuf_size(rcvbuf_size), _read_offset(0) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream for sending information via a capability to an endpoint
|
||||||
|
*/
|
||||||
|
class Ipc_ostream : public Ipc_marshaller
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Msgbuf_base *_snd_msg; /* send message buffer */
|
||||||
|
Native_capability _dst;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset marshaller and write badge at the beginning of the message
|
||||||
|
*/
|
||||||
|
void _prepare_next_send();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send message in _snd_msg to _dst
|
||||||
|
*/
|
||||||
|
void _send();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert capability to message buffer
|
||||||
|
*/
|
||||||
|
void _marshal_capability(Native_capability const &cap);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if Ipc_ostream is ready for send
|
||||||
|
*/
|
||||||
|
bool ready_for_send() const { return _dst.valid(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert value into send buffer
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
Ipc_ostream &operator << (T const &value)
|
||||||
|
{
|
||||||
|
_write_to_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert byte buffer to send buffer
|
||||||
|
*/
|
||||||
|
Ipc_ostream &operator << (Rpc_in_buffer_base const &b)
|
||||||
|
{
|
||||||
|
_write_buffer_to_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert capability to send buffer
|
||||||
|
*/
|
||||||
|
Ipc_ostream &operator << (Native_capability const &cap)
|
||||||
|
{
|
||||||
|
_marshal_capability(cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert typed capability to send buffer
|
||||||
|
*/
|
||||||
|
template <typename IT>
|
||||||
|
Ipc_ostream &operator << (Capability<IT> const &typed_cap)
|
||||||
|
{
|
||||||
|
_marshal_capability(typed_cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue the sending of the message buffer
|
||||||
|
*/
|
||||||
|
Ipc_ostream &operator << (Ipc_ostream_send)
|
||||||
|
{
|
||||||
|
_send();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return current 'IPC_SEND' destination
|
||||||
|
*
|
||||||
|
* This function is typically needed by a server than sends replies
|
||||||
|
* in a different order as the incoming calls.
|
||||||
|
*/
|
||||||
|
Native_capability dst() const { return _dst; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set destination for the next 'IPC_SEND'
|
||||||
|
*/
|
||||||
|
void dst(Native_capability const &dst) { _dst = dst; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream for receiving information
|
||||||
|
*/
|
||||||
|
class Ipc_istream : public Ipc_unmarshaller, public Native_capability
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent 'Ipc_istream' objects from being copied
|
||||||
|
*
|
||||||
|
* Copying an 'Ipc_istream' object would result in a duplicated
|
||||||
|
* (and possibly inconsistent) connection state both the original
|
||||||
|
* and the copied object.
|
||||||
|
*/
|
||||||
|
Ipc_istream(const Ipc_istream &);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Msgbuf_base *_rcv_msg;
|
||||||
|
Native_connection_state _rcv_cs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain capability from message buffer
|
||||||
|
*/
|
||||||
|
void _unmarshal_capability(Native_capability &cap);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset unmarshaller
|
||||||
|
*/
|
||||||
|
void _prepare_next_receive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for incoming message to be received in _rcv_msg
|
||||||
|
*/
|
||||||
|
void _wait();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Ipc_istream(Msgbuf_base *rcv_msg);
|
||||||
|
|
||||||
|
~Ipc_istream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read badge that was supplied with the message
|
||||||
|
*/
|
||||||
|
long badge() { return _long_at_idx(0); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block for an incoming message filling the receive buffer
|
||||||
|
*/
|
||||||
|
Ipc_istream &operator >> (Ipc_istream_wait)
|
||||||
|
{
|
||||||
|
_wait();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read values from receive buffer
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
Ipc_istream &operator >> (T &value)
|
||||||
|
{
|
||||||
|
_read_from_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read byte buffer from receive buffer
|
||||||
|
*/
|
||||||
|
Ipc_istream &operator >> (Rpc_in_buffer_base &b)
|
||||||
|
{
|
||||||
|
_read_bytebuf_from_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read byte buffer from receive buffer
|
||||||
|
*/
|
||||||
|
template <size_t MAX_BUFFER_SIZE>
|
||||||
|
Ipc_istream &operator >> (Rpc_in_buffer<MAX_BUFFER_SIZE> &b)
|
||||||
|
{
|
||||||
|
_read_bytebuf_from_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read capability from receive buffer
|
||||||
|
*/
|
||||||
|
Ipc_istream &operator >> (Native_capability &cap)
|
||||||
|
{
|
||||||
|
_unmarshal_capability(cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read typed capability from receive buffer
|
||||||
|
*/
|
||||||
|
template <typename IT>
|
||||||
|
Ipc_istream &operator >> (Capability<IT> &typed_cap)
|
||||||
|
{
|
||||||
|
_unmarshal_capability(typed_cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Ipc_client: public Ipc_istream, public Ipc_ostream
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int _result; /* result of most recent call */
|
||||||
|
|
||||||
|
void _prepare_next_call();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send RPC message and wait for result
|
||||||
|
*/
|
||||||
|
void _call();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set return value if call to server failed
|
||||||
|
*/
|
||||||
|
void ret(int retval)
|
||||||
|
{
|
||||||
|
*reinterpret_cast<int *>(&_rcvbuf[sizeof(umword_t)]) = retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Ipc_client(Native_capability const &srv, Msgbuf_base *snd_msg,
|
||||||
|
Msgbuf_base *rcv_msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator that issues an IPC call
|
||||||
|
*
|
||||||
|
* \throw Ipc_error
|
||||||
|
* \throw Blocking_canceled
|
||||||
|
*/
|
||||||
|
Ipc_client &operator << (Ipc_client_call)
|
||||||
|
{
|
||||||
|
_call();
|
||||||
|
_read_from_buf(_result);
|
||||||
|
if (_result == ERR_INVALID_OBJECT) {
|
||||||
|
PERR("tried to call an invalid object");
|
||||||
|
throw Ipc_error();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Ipc_client &operator << (T const &value)
|
||||||
|
{
|
||||||
|
_write_to_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipc_client &operator << (Rpc_in_buffer_base const &b)
|
||||||
|
{
|
||||||
|
_write_buffer_to_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_BUFFER_SIZE>
|
||||||
|
Ipc_client &operator << (Rpc_in_buffer<MAX_BUFFER_SIZE> const &b)
|
||||||
|
{
|
||||||
|
_write_buffer_to_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipc_client &operator << (Native_capability const &cap)
|
||||||
|
{
|
||||||
|
_marshal_capability(cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IT>
|
||||||
|
Ipc_client &operator << (Capability<IT> const &typed_cap)
|
||||||
|
{
|
||||||
|
_marshal_capability(typed_cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipc_client &operator >> (Native_capability &cap)
|
||||||
|
{
|
||||||
|
_unmarshal_capability(cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IT>
|
||||||
|
Ipc_client &operator >> (Capability<IT> &typed_cap)
|
||||||
|
{
|
||||||
|
_unmarshal_capability(typed_cap);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Ipc_client &operator >> (T &value)
|
||||||
|
{
|
||||||
|
_read_from_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipc_client &operator >> (Rpc_in_buffer_base &b)
|
||||||
|
{
|
||||||
|
_read_bytebuf_from_buf(b);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result() const { return _result; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Ipc_server : public Ipc_istream, public Ipc_ostream
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool _reply_needed; /* false for the first reply_wait */
|
||||||
|
|
||||||
|
void _prepare_next_reply_wait();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for incoming call
|
||||||
|
*
|
||||||
|
* In constrast to 'Ipc_istream::_wait()', this function stores the
|
||||||
|
* next reply destination from into 'dst' of the 'Ipc_ostream'.
|
||||||
|
*/
|
||||||
|
void _wait();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send reply to destination
|
||||||
|
*
|
||||||
|
* In contrast to 'Ipc_ostream::_send()', this function prepares
|
||||||
|
* the 'Ipc_server' to send another subsequent reply without the
|
||||||
|
* calling '_wait()' in between. This is needed when a server
|
||||||
|
* answers calls out of order.
|
||||||
|
*/
|
||||||
|
void _reply();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send result of previous RPC request and wait for new one
|
||||||
|
*/
|
||||||
|
void _reply_wait();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set return value of server call
|
||||||
|
*/
|
||||||
|
void ret(int retval)
|
||||||
|
{
|
||||||
|
*reinterpret_cast<int *>(&_sndbuf[sizeof(umword_t)]) = retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set reply destination
|
||||||
|
*/
|
||||||
|
void dst(Native_capability const &reply_dst)
|
||||||
|
{
|
||||||
|
Ipc_ostream::dst(reply_dst);
|
||||||
|
_reply_needed = reply_dst.valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
using Ipc_ostream::dst;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block for an incoming message filling the receive buffer
|
||||||
|
*/
|
||||||
|
Ipc_server &operator >> (Ipc_istream_wait)
|
||||||
|
{
|
||||||
|
_wait();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue the sending of the message buffer
|
||||||
|
*/
|
||||||
|
Ipc_server &operator << (Ipc_server_reply)
|
||||||
|
{
|
||||||
|
_reply();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply current request and wait for a new one
|
||||||
|
*/
|
||||||
|
Ipc_server &operator >> (Ipc_server_reply_wait)
|
||||||
|
{
|
||||||
|
_reply_wait();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write value to send buffer
|
||||||
|
*
|
||||||
|
* This operator is only used by test programs
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
Ipc_server &operator << (T const &value)
|
||||||
|
{
|
||||||
|
_write_to_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read value from receive buffer
|
||||||
|
*
|
||||||
|
* This operator should only be used by the server framework for
|
||||||
|
* reading the function offset. The server-side processing of the
|
||||||
|
* payload is done using 'Ipc_istream' and 'Ipc_ostream'.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
Ipc_server &operator >> (T &value)
|
||||||
|
{
|
||||||
|
_read_from_buf(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#endif /* _INCLUDE__BASE__IPC_GENERIC_H_ */
|
||||||
* Unmarshalling of capabilities as plain data representation
|
|
||||||
*/
|
|
||||||
inline void
|
|
||||||
Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap)
|
|
||||||
{
|
|
||||||
_read_from_buf(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__IPC_H_ */
|
|
||||||
|
|
|
@ -1,632 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Generic IPC infrastructure
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2006-06-12
|
|
||||||
*
|
|
||||||
* Most of the marshalling and unmarshallung code is generic for IPC
|
|
||||||
* implementations among different platforms. In addition to the generic
|
|
||||||
* marshalling items, platform-specific marshalling items can be realized
|
|
||||||
* via specialized stream operators defined in the platform-specific
|
|
||||||
* 'base/ipc.h'. Hence, this header file is never to be included directly.
|
|
||||||
* It should only be included by a platform-specific 'base/ipc.h' file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2006-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__IPC_GENERIC_H_
|
|
||||||
#define _INCLUDE__BASE__IPC_GENERIC_H_
|
|
||||||
|
|
||||||
#include <util/misc_math.h>
|
|
||||||
#include <util/string.h>
|
|
||||||
#include <base/errno.h>
|
|
||||||
#include <base/exception.h>
|
|
||||||
#include <base/capability.h>
|
|
||||||
#include <base/ipc_msgbuf.h>
|
|
||||||
#include <base/rpc_args.h>
|
|
||||||
#include <base/printf.h>
|
|
||||||
|
|
||||||
namespace Genode {
|
|
||||||
|
|
||||||
enum Ipc_ostream_send { IPC_SEND };
|
|
||||||
enum Ipc_istream_wait { IPC_WAIT };
|
|
||||||
enum Ipc_client_call { IPC_CALL };
|
|
||||||
enum Ipc_server_reply { IPC_REPLY };
|
|
||||||
enum Ipc_server_reply_wait { IPC_REPLY_WAIT };
|
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
** Exception types **
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
class Ipc_error : public Exception { };
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marshal arguments into send message buffer
|
|
||||||
*/
|
|
||||||
class Ipc_marshaller
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
char *_sndbuf;
|
|
||||||
size_t _sndbuf_size;
|
|
||||||
unsigned _write_offset;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write value to send buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
void _write_to_buf(T const &value)
|
|
||||||
{
|
|
||||||
/* check buffer range */
|
|
||||||
if (_write_offset + sizeof(T) >= _sndbuf_size) return;
|
|
||||||
|
|
||||||
/* write integer to buffer */
|
|
||||||
*reinterpret_cast<T *>(&_sndbuf[_write_offset]) = value;
|
|
||||||
|
|
||||||
/* increment write pointer to next dword-aligned value */
|
|
||||||
_write_offset += align_natural(sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write bytes to send buffer
|
|
||||||
*/
|
|
||||||
void _write_to_buf(char const *src_addr, unsigned num_bytes)
|
|
||||||
{
|
|
||||||
/* check buffer range */
|
|
||||||
if (_write_offset + num_bytes >= _sndbuf_size) return;
|
|
||||||
|
|
||||||
/* copy buffer */
|
|
||||||
memcpy(&_sndbuf[_write_offset], src_addr, num_bytes);
|
|
||||||
|
|
||||||
/* increment write pointer to next dword-aligned value */
|
|
||||||
_write_offset += align_natural(num_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write 'Rpc_in_buffer' to send buffer
|
|
||||||
*/
|
|
||||||
void _write_buffer_to_buf(Rpc_in_buffer_base const &b)
|
|
||||||
{
|
|
||||||
size_t size = b.size();
|
|
||||||
_write_to_buf(size);
|
|
||||||
_write_to_buf(b.base(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write array to send buffer
|
|
||||||
*/
|
|
||||||
template <typename T, size_t N>
|
|
||||||
void _write_to_buf(T const (&array)[N])
|
|
||||||
{
|
|
||||||
/* check buffer range */
|
|
||||||
if (_write_offset + sizeof(array) >= _sndbuf_size)
|
|
||||||
PERR("send buffer overrun");
|
|
||||||
|
|
||||||
memcpy(&_sndbuf[_write_offset], array, sizeof(array));
|
|
||||||
_write_offset += align_natural(sizeof(array));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Ipc_marshaller(char *sndbuf, size_t sndbuf_size)
|
|
||||||
: _sndbuf(sndbuf), _sndbuf_size(sndbuf_size), _write_offset(0) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unmarshal arguments from receive buffer
|
|
||||||
*/
|
|
||||||
class Ipc_unmarshaller
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
char *_rcvbuf;
|
|
||||||
size_t _rcvbuf_size;
|
|
||||||
unsigned _read_offset;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read value of type T from buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
void _read_from_buf(T &value)
|
|
||||||
{
|
|
||||||
/* check receive buffer range */
|
|
||||||
if (_read_offset + sizeof(T) >= _rcvbuf_size) return;
|
|
||||||
|
|
||||||
/* return value from receive buffer */
|
|
||||||
value = *reinterpret_cast<T *>(&_rcvbuf[_read_offset]);
|
|
||||||
|
|
||||||
/* increment read pointer to next dword-aligned value */
|
|
||||||
_read_offset += align_natural(sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read 'Rpc_in_buffer' from receive buffer
|
|
||||||
*/
|
|
||||||
void _read_bytebuf_from_buf(Rpc_in_buffer_base &b)
|
|
||||||
{
|
|
||||||
size_t size = 0;
|
|
||||||
_read_from_buf(size);
|
|
||||||
b = Rpc_in_buffer_base(0, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check receive buffer range
|
|
||||||
*
|
|
||||||
* Note: The addr of the Rpc_in_buffer_base is a null pointer when this
|
|
||||||
* condition triggers.
|
|
||||||
*/
|
|
||||||
if (_read_offset + size >= _rcvbuf_size) {
|
|
||||||
PERR("message buffer overrun");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
b = Rpc_in_buffer_base(&_rcvbuf[_read_offset], size);
|
|
||||||
_read_offset += align_natural(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read array from receive buffer
|
|
||||||
*/
|
|
||||||
template <typename T, size_t N>
|
|
||||||
void _read_from_buf(T (&array)[N])
|
|
||||||
{
|
|
||||||
if (_read_offset + sizeof(array) >= _rcvbuf_size) {
|
|
||||||
PERR("receive buffer overrun");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(array, &_rcvbuf[_read_offset], sizeof(array));
|
|
||||||
_read_offset += align_natural(sizeof(array));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read long value at specified byte index of receive buffer
|
|
||||||
*/
|
|
||||||
long _long_at_idx(int idx) { return *(long *)(&_rcvbuf[idx]); }
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Ipc_unmarshaller(char *rcvbuf, size_t rcvbuf_size)
|
|
||||||
: _rcvbuf(rcvbuf), _rcvbuf_size(rcvbuf_size), _read_offset(0) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream for sending information via a capability to an endpoint
|
|
||||||
*/
|
|
||||||
class Ipc_ostream : public Ipc_marshaller
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Msgbuf_base *_snd_msg; /* send message buffer */
|
|
||||||
Native_capability _dst;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset marshaller and write badge at the beginning of the message
|
|
||||||
*/
|
|
||||||
void _prepare_next_send();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send message in _snd_msg to _dst
|
|
||||||
*/
|
|
||||||
void _send();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert capability to message buffer
|
|
||||||
*/
|
|
||||||
void _marshal_capability(Native_capability const &cap);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if Ipc_ostream is ready for send
|
|
||||||
*/
|
|
||||||
bool ready_for_send() const { return _dst.valid(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert value into send buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
Ipc_ostream &operator << (T const &value)
|
|
||||||
{
|
|
||||||
_write_to_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert byte buffer to send buffer
|
|
||||||
*/
|
|
||||||
Ipc_ostream &operator << (Rpc_in_buffer_base const &b)
|
|
||||||
{
|
|
||||||
_write_buffer_to_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert capability to send buffer
|
|
||||||
*/
|
|
||||||
Ipc_ostream &operator << (Native_capability const &cap)
|
|
||||||
{
|
|
||||||
_marshal_capability(cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert typed capability to send buffer
|
|
||||||
*/
|
|
||||||
template <typename IT>
|
|
||||||
Ipc_ostream &operator << (Capability<IT> const &typed_cap)
|
|
||||||
{
|
|
||||||
_marshal_capability(typed_cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Issue the sending of the message buffer
|
|
||||||
*/
|
|
||||||
Ipc_ostream &operator << (Ipc_ostream_send)
|
|
||||||
{
|
|
||||||
_send();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return current 'IPC_SEND' destination
|
|
||||||
*
|
|
||||||
* This function is typically needed by a server than sends replies
|
|
||||||
* in a different order as the incoming calls.
|
|
||||||
*/
|
|
||||||
Native_capability dst() const { return _dst; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set destination for the next 'IPC_SEND'
|
|
||||||
*/
|
|
||||||
void dst(Native_capability const &dst) { _dst = dst; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream for receiving information
|
|
||||||
*/
|
|
||||||
class Ipc_istream : public Ipc_unmarshaller, public Native_capability
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent 'Ipc_istream' objects from being copied
|
|
||||||
*
|
|
||||||
* Copying an 'Ipc_istream' object would result in a duplicated
|
|
||||||
* (and possibly inconsistent) connection state both the original
|
|
||||||
* and the copied object.
|
|
||||||
*/
|
|
||||||
Ipc_istream(const Ipc_istream &);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Msgbuf_base *_rcv_msg;
|
|
||||||
Native_connection_state _rcv_cs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain capability from message buffer
|
|
||||||
*/
|
|
||||||
void _unmarshal_capability(Native_capability &cap);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset unmarshaller
|
|
||||||
*/
|
|
||||||
void _prepare_next_receive();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for incoming message to be received in _rcv_msg
|
|
||||||
*/
|
|
||||||
void _wait();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit Ipc_istream(Msgbuf_base *rcv_msg);
|
|
||||||
|
|
||||||
~Ipc_istream();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read badge that was supplied with the message
|
|
||||||
*/
|
|
||||||
long badge() { return _long_at_idx(0); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block for an incoming message filling the receive buffer
|
|
||||||
*/
|
|
||||||
Ipc_istream &operator >> (Ipc_istream_wait)
|
|
||||||
{
|
|
||||||
_wait();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read values from receive buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
Ipc_istream &operator >> (T &value)
|
|
||||||
{
|
|
||||||
_read_from_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read byte buffer from receive buffer
|
|
||||||
*/
|
|
||||||
Ipc_istream &operator >> (Rpc_in_buffer_base &b)
|
|
||||||
{
|
|
||||||
_read_bytebuf_from_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read byte buffer from receive buffer
|
|
||||||
*/
|
|
||||||
template <size_t MAX_BUFFER_SIZE>
|
|
||||||
Ipc_istream &operator >> (Rpc_in_buffer<MAX_BUFFER_SIZE> &b)
|
|
||||||
{
|
|
||||||
_read_bytebuf_from_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read capability from receive buffer
|
|
||||||
*/
|
|
||||||
Ipc_istream &operator >> (Native_capability &cap)
|
|
||||||
{
|
|
||||||
_unmarshal_capability(cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read typed capability from receive buffer
|
|
||||||
*/
|
|
||||||
template <typename IT>
|
|
||||||
Ipc_istream &operator >> (Capability<IT> &typed_cap)
|
|
||||||
{
|
|
||||||
_unmarshal_capability(typed_cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Ipc_client: public Ipc_istream, public Ipc_ostream
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
int _result; /* result of most recent call */
|
|
||||||
|
|
||||||
void _prepare_next_call();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send RPC message and wait for result
|
|
||||||
*/
|
|
||||||
void _call();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set return value if call to server failed
|
|
||||||
*/
|
|
||||||
void ret(int retval)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<int *>(&_rcvbuf[sizeof(umword_t)]) = retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Ipc_client(Native_capability const &srv, Msgbuf_base *snd_msg,
|
|
||||||
Msgbuf_base *rcv_msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operator that issues an IPC call
|
|
||||||
*
|
|
||||||
* \throw Ipc_error
|
|
||||||
* \throw Blocking_canceled
|
|
||||||
*/
|
|
||||||
Ipc_client &operator << (Ipc_client_call)
|
|
||||||
{
|
|
||||||
_call();
|
|
||||||
_read_from_buf(_result);
|
|
||||||
if (_result == ERR_INVALID_OBJECT) {
|
|
||||||
PERR("tried to call an invalid object");
|
|
||||||
throw Ipc_error();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ipc_client &operator << (T const &value)
|
|
||||||
{
|
|
||||||
_write_to_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipc_client &operator << (Rpc_in_buffer_base const &b)
|
|
||||||
{
|
|
||||||
_write_buffer_to_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t MAX_BUFFER_SIZE>
|
|
||||||
Ipc_client &operator << (Rpc_in_buffer<MAX_BUFFER_SIZE> const &b)
|
|
||||||
{
|
|
||||||
_write_buffer_to_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipc_client &operator << (Native_capability const &cap)
|
|
||||||
{
|
|
||||||
_marshal_capability(cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename IT>
|
|
||||||
Ipc_client &operator << (Capability<IT> const &typed_cap)
|
|
||||||
{
|
|
||||||
_marshal_capability(typed_cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipc_client &operator >> (Native_capability &cap)
|
|
||||||
{
|
|
||||||
_unmarshal_capability(cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename IT>
|
|
||||||
Ipc_client &operator >> (Capability<IT> &typed_cap)
|
|
||||||
{
|
|
||||||
_unmarshal_capability(typed_cap);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ipc_client &operator >> (T &value)
|
|
||||||
{
|
|
||||||
_read_from_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipc_client &operator >> (Rpc_in_buffer_base &b)
|
|
||||||
{
|
|
||||||
_read_bytebuf_from_buf(b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result() const { return _result; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Ipc_server : public Ipc_istream, public Ipc_ostream
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
bool _reply_needed; /* false for the first reply_wait */
|
|
||||||
|
|
||||||
void _prepare_next_reply_wait();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for incoming call
|
|
||||||
*
|
|
||||||
* In constrast to 'Ipc_istream::_wait()', this function stores the
|
|
||||||
* next reply destination from into 'dst' of the 'Ipc_ostream'.
|
|
||||||
*/
|
|
||||||
void _wait();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send reply to destination
|
|
||||||
*
|
|
||||||
* In contrast to 'Ipc_ostream::_send()', this function prepares
|
|
||||||
* the 'Ipc_server' to send another subsequent reply without the
|
|
||||||
* calling '_wait()' in between. This is needed when a server
|
|
||||||
* answers calls out of order.
|
|
||||||
*/
|
|
||||||
void _reply();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send result of previous RPC request and wait for new one
|
|
||||||
*/
|
|
||||||
void _reply_wait();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set return value of server call
|
|
||||||
*/
|
|
||||||
void ret(int retval)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<int *>(&_sndbuf[sizeof(umword_t)]) = retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set reply destination
|
|
||||||
*/
|
|
||||||
void dst(Native_capability const &reply_dst)
|
|
||||||
{
|
|
||||||
Ipc_ostream::dst(reply_dst);
|
|
||||||
_reply_needed = reply_dst.valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
using Ipc_ostream::dst;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block for an incoming message filling the receive buffer
|
|
||||||
*/
|
|
||||||
Ipc_server &operator >> (Ipc_istream_wait)
|
|
||||||
{
|
|
||||||
_wait();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Issue the sending of the message buffer
|
|
||||||
*/
|
|
||||||
Ipc_server &operator << (Ipc_server_reply)
|
|
||||||
{
|
|
||||||
_reply();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reply current request and wait for a new one
|
|
||||||
*/
|
|
||||||
Ipc_server &operator >> (Ipc_server_reply_wait)
|
|
||||||
{
|
|
||||||
_reply_wait();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write value to send buffer
|
|
||||||
*
|
|
||||||
* This operator is only used by test programs
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
Ipc_server &operator << (T const &value)
|
|
||||||
{
|
|
||||||
_write_to_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read value from receive buffer
|
|
||||||
*
|
|
||||||
* This operator should only be used by the server framework for
|
|
||||||
* reading the function offset. The server-side processing of the
|
|
||||||
* payload is done using 'Ipc_istream' and 'Ipc_ostream'.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
Ipc_server &operator >> (T &value)
|
|
||||||
{
|
|
||||||
_read_from_buf(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__IPC_GENERIC_H_ */
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* \brief Marshalling/unmarshalling of plain-data capabilities
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-02-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/ipc.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marshalling of capabilities as plain data representation
|
||||||
|
*/
|
||||||
|
void Ipc_ostream::_marshal_capability(Native_capability const &cap)
|
||||||
|
{
|
||||||
|
_write_to_buf(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmarshalling of capabilities as plain data representation
|
||||||
|
*/
|
||||||
|
void Ipc_istream::_unmarshal_capability(Native_capability &cap)
|
||||||
|
{
|
||||||
|
_read_from_buf(cap);
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
* \date 2010-08-26
|
* \date 2010-08-26
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <base/ipc_generic.h>
|
#include <base/ipc.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue