diff --git a/repos/base-linux/lib/mk/base-linux-common.mk b/repos/base-linux/lib/mk/base-linux-common.mk
index 28571da7a..2a84b880c 100644
--- a/repos/base-linux/lib/mk/base-linux-common.mk
+++ b/repos/base-linux/lib/mk/base-linux-common.mk
@@ -13,5 +13,5 @@ SRC_CC += rpc_dispatch_loop.cc
SRC_CC += rpc_entrypoint_manage.cc
SRC_CC += thread_env.cc
SRC_CC += capability.cc
-SRC_CC += platform.cc
SRC_CC += rpc_entry.cc
+SRC_CC += native_thread.cc
diff --git a/repos/base-linux/lib/mk/base-linux.mk b/repos/base-linux/lib/mk/base-linux.mk
index 60e26542e..e9529685b 100644
--- a/repos/base-linux/lib/mk/base-linux.mk
+++ b/repos/base-linux/lib/mk/base-linux.mk
@@ -11,3 +11,4 @@ SRC_CC += thread.cc thread_myself.cc thread_linux.cc
SRC_CC += capability_space.cc capability_raw.cc
SRC_CC += attach_stack_area.cc
SRC_CC += signal_transmitter.cc signal.cc
+SRC_CC += platform.cc
diff --git a/repos/base-linux/src/core/core_rpc_cap_alloc.cc b/repos/base-linux/src/core/core_rpc_cap_alloc.cc
new file mode 100644
index 000000000..ea3359ea5
--- /dev/null
+++ b/repos/base-linux/src/core/core_rpc_cap_alloc.cc
@@ -0,0 +1,33 @@
+/*
+ * \brief Core-specific back end of the RPC entrypoint
+ * \author Norman Feske
+ * \date 2020-04-07
+ */
+
+/*
+ * Copyright (C) 2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+
+/* base-internal includes */
+#include
+
+using namespace Genode;
+
+
+Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &, Native_capability,
+ addr_t)
+{
+ return Thread::native_thread().epoll.alloc_rpc_cap();
+}
+
+
+void Rpc_entrypoint::_free_rpc_cap(Pd_session &, Native_capability cap)
+{
+ Thread::native_thread().epoll.free_rpc_cap(cap);
+}
diff --git a/repos/base-linux/src/core/include/core_linux_syscalls.h b/repos/base-linux/src/core/include/core_linux_syscalls.h
index a18e77d44..f2e7d44bb 100644
--- a/repos/base-linux/src/core/include/core_linux_syscalls.h
+++ b/repos/base-linux/src/core/include/core_linux_syscalls.h
@@ -48,12 +48,6 @@ inline int lx_unlink(const char *fname)
}
-inline int lx_dup(int fd)
-{
- return lx_syscall(SYS_dup, fd);
-}
-
-
/*******************************************************
** Functions used by core's rom-session support code **
*******************************************************/
diff --git a/repos/base-linux/src/core/include/dataspace_component.h b/repos/base-linux/src/core/include/dataspace_component.h
index eafb044f1..dba193a67 100644
--- a/repos/base-linux/src/core/include/dataspace_component.h
+++ b/repos/base-linux/src/core/include/dataspace_component.h
@@ -38,11 +38,11 @@ namespace Genode {
{
private:
- Filename _fname { }; /* filename for mmap */
- size_t const _size; /* size of dataspace in bytes */
- addr_t const _addr; /* meaningless on linux */
- int _fd { -1 }; /* file descriptor */
- bool const _writable; /* false if read-only */
+ Filename _fname { }; /* filename for mmap */
+ size_t const _size; /* size of dataspace in bytes */
+ addr_t const _addr; /* meaningless on linux */
+ Native_capability _cap; /* capability / file descriptor */
+ bool const _writable; /* false if read-only */
/* Holds the dataspace owner if a distinction between owner and
* others is necessary on the dataspace, otherwise it is 0 */
@@ -57,6 +57,11 @@ namespace Genode {
Dataspace_component(Dataspace_component const &);
Dataspace_component &operator = (Dataspace_component const &);
+ static Native_capability _fd_to_cap(int const fd)
+ {
+ return Capability_space::import(Rpc_destination(Lx_sd{fd}), Rpc_obj_key());
+ }
+
public:
/**
@@ -65,14 +70,14 @@ namespace Genode {
Dataspace_component(size_t size, addr_t addr,
Cache_attribute, bool writable,
Dataspace_owner * owner)
- : _size(size), _addr(addr), _fd(-1), _writable(writable),
+ : _size(size), _addr(addr), _cap(), _writable(writable),
_owner(owner) { }
/**
* Default constructor returns invalid dataspace
*/
Dataspace_component()
- : _size(0), _addr(0), _fd(-1), _writable(false), _owner(nullptr) { }
+ : _size(0), _addr(0), _cap(), _writable(false), _owner(nullptr) { }
/**
* This constructor is only provided for compatibility
@@ -94,7 +99,7 @@ namespace Genode {
* The file descriptor assigned to the dataspace will be enable
* processes outside of core to mmap the dataspace.
*/
- void fd(int fd) { _fd = fd; }
+ void fd(int fd) { _cap = _fd_to_cap(fd); }
/**
* Check if dataspace is owned by a specified object
@@ -122,13 +127,7 @@ namespace Genode {
Filename fname() override { return _fname; }
- Untyped_capability fd() override
- {
- Untyped_capability fd_cap =
- Capability_space::import(Rpc_destination(_fd), Rpc_obj_key());
-
- return fd_cap;
- }
+ Untyped_capability fd() override { return _cap; }
};
}
diff --git a/repos/base-linux/src/core/include/native_cpu_component.h b/repos/base-linux/src/core/include/native_cpu_component.h
index e425f9971..63e0fd075 100644
--- a/repos/base-linux/src/core/include/native_cpu_component.h
+++ b/repos/base-linux/src/core/include/native_cpu_component.h
@@ -40,8 +40,6 @@ class Genode::Native_cpu_component : public Rpc_object
#include
-/* base-internal includes */
-#include
-
/* core includes */
#include
@@ -67,11 +64,6 @@ namespace Genode {
unsigned long _pid = -1;
char _name[32] { };
- /**
- * Unix-domain socket pair bound to the thread
- */
- Socket_pair _socket_pair { };
-
/*
* Dummy pager object that is solely used for storing the
* 'Signal_context_capability' for the thread's exception handler.
@@ -147,19 +139,6 @@ namespace Genode {
*/
void thread_id(int pid, int tid) { _pid = pid, _tid = tid; }
- /**
- * Return client-side socket descriptor
- *
- * For more information, please refer to the comments in
- * 'linux_cpu_session/linux_cpu_session.h'.
- */
- int client_sd();
-
- /**
- * Return server-side socket descriptor
- */
- int server_sd();
-
/**
* Notify Genode::Signal handler about sigchld
*/
diff --git a/repos/base-linux/src/core/include/server_socket_pair.h b/repos/base-linux/src/core/include/server_socket_pair.h
deleted file mode 100644
index 9d5c8109d..000000000
--- a/repos/base-linux/src/core/include/server_socket_pair.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * \brief Support for communication over Unix domain sockets
- * \author Norman Feske
- * \date 2012-08-10
- */
-
-/*
- * Copyright (C) 2011-2017 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
-#define _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
-
-/* Linux syscall bindings */
-#include
-#include
-#include
-
-/* base-internal includes */
-#include
-#include
-
-/* core-local includes */
-#include
-
-
-/**
- * Utility: Create socket address for server entrypoint at thread ID
- */
-struct Uds_addr : sockaddr_un
-{
- Uds_addr(long thread_id)
- :
- sockaddr_un({.sun_family = AF_UNIX, .sun_path = { }})
- {
- Genode::snprintf(sun_path, sizeof(sun_path), "%s/ep-%ld",
- resource_path(), thread_id);
- }
-};
-
-
-/**
- * Utility: Create named socket pair for given unique ID
- */
-static inline Genode::Socket_pair create_server_socket_pair(long id)
-{
- Genode::Socket_pair socket_pair;
-
- using Genode::raw;
-
- /*
- * Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for
- * binding.
- */
- if (id == -1)
- return socket_pair;
-
- Uds_addr addr(id);
-
- /*
- * Create server-side socket
- */
- socket_pair.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (socket_pair.server_sd < 0) {
- raw("Error: Could not create server-side socket (ret=", socket_pair.server_sd, ")");
- class Server_socket_failed { };
- throw Server_socket_failed();
- }
-
- /* make sure bind succeeds */
- lx_unlink(addr.sun_path);
-
- int const bind_ret = lx_bind(socket_pair.server_sd, (sockaddr *)&addr, sizeof(addr));
- if (bind_ret < 0) {
- raw("Error: Could not bind server socket (ret=", bind_ret, ")");
- class Bind_failed { };
- throw Bind_failed();
- }
-
- /*
- * Create client-side socket
- */
- socket_pair.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (socket_pair.client_sd < 0) {
- raw("Error: Could not create client-side socket (ret=", socket_pair.client_sd, ")");
- class Client_socket_failed { };
- throw Client_socket_failed();
- }
-
- int const conn_ret = lx_connect(socket_pair.client_sd, (sockaddr *)&addr, sizeof(addr));
- if (conn_ret < 0) {
- raw("Error: Could not connect client-side socket (ret=", conn_ret, ")");
- class Connect_failed { };
- throw Connect_failed();
- }
-
- socket_pair.client_sd = Genode::ep_sd_registry().try_associate(socket_pair.client_sd, id);
-
- /*
- * Wipe Unix domain socket from the file system. It will live as long as
- * there exist references to it in the form of file descriptors.
- */
- lx_unlink(addr.sun_path);
-
- return socket_pair;
-}
-
-#endif /* _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_ */
diff --git a/repos/base-linux/src/core/linux/target.mk b/repos/base-linux/src/core/linux/target.mk
index 40958b81b..cd5a59b3f 100644
--- a/repos/base-linux/src/core/linux/target.mk
+++ b/repos/base-linux/src/core/linux/target.mk
@@ -21,7 +21,7 @@ SRC_CC = main.cc \
native_pd_component.cc \
native_cpu_component.cc \
capability_space.cc \
- rpc_cap_factory_l4.cc \
+ rpc_cap_factory_linux.cc \
ram_dataspace_factory.cc \
core_rpc_cap_alloc.cc \
io_mem_session_component.cc \
@@ -63,13 +63,11 @@ vpath cpu_thread_component.cc $(GEN_CORE_DIR)
vpath pd_upgrade_ram_quota.cc $(GEN_CORE_DIR)
vpath pd_session_support.cc $(GEN_CORE_DIR)
vpath capability_space.cc $(GEN_CORE_DIR)
-vpath rpc_cap_factory_l4.cc $(GEN_CORE_DIR)
vpath ram_dataspace_factory.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath signal_transmitter_proxy.cc $(GEN_CORE_DIR)
vpath signal_receiver.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
-vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath default_log.cc $(GEN_CORE_DIR)
vpath heartbeat.cc $(GEN_CORE_DIR)
vpath io_port_session_support.cc $(GEN_CORE_DIR)/spec/x86
diff --git a/repos/base-linux/src/core/native_cpu_component.cc b/repos/base-linux/src/core/native_cpu_component.cc
index 20b1275b9..08910d953 100644
--- a/repos/base-linux/src/core/native_cpu_component.cc
+++ b/repos/base-linux/src/core/native_cpu_component.cc
@@ -28,30 +28,6 @@ void Native_cpu_component::thread_id(Thread_capability thread_cap, int pid, int
}
-Untyped_capability Native_cpu_component::server_sd(Thread_capability thread_cap)
-{
- auto lambda = [] (Cpu_thread_component *thread) {
- if (!thread) return Untyped_capability();
-
- return Capability_space::import(Rpc_destination(thread->platform_thread().server_sd()),
- Rpc_obj_key());
- };
- return _thread_ep.apply(thread_cap, lambda);
-}
-
-
-Untyped_capability Native_cpu_component::client_sd(Thread_capability thread_cap)
-{
- auto lambda = [] (Cpu_thread_component *thread) {
- if (!thread) return Untyped_capability();
-
- return Capability_space::import(Rpc_destination(thread->platform_thread().client_sd()),
- Rpc_obj_key());
- };
- return _thread_ep.apply(thread_cap, lambda);
-}
-
-
Native_cpu_component::Native_cpu_component(Cpu_session_component &cpu_session, char const *)
:
_cpu_session(cpu_session), _thread_ep(_cpu_session._thread_ep)
diff --git a/repos/base-linux/src/core/native_pd_component.cc b/repos/base-linux/src/core/native_pd_component.cc
index 937a91f41..76b337183 100644
--- a/repos/base-linux/src/core/native_pd_component.cc
+++ b/repos/base-linux/src/core/native_pd_component.cc
@@ -42,12 +42,12 @@ struct Execve_args
char const *filename;
char * const *argv;
char * const *envp;
- int const parent_sd;
+ Lx_sd const parent_sd;
Execve_args(char const *filename,
char * const *argv,
char * const *envp,
- int parent_sd)
+ Lx_sd parent_sd)
:
filename(filename), argv(argv), envp(envp), parent_sd(parent_sd)
{ }
@@ -59,7 +59,7 @@ struct Execve_args
*/
static int _exec_child(Execve_args *arg)
{
- lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE);
+ lx_dup2(arg->parent_sd.value, PARENT_SOCKET_HANDLE);
return lx_execve(arg->filename, arg->argv, arg->envp);
}
@@ -118,7 +118,7 @@ void Native_pd_component::_start(Dataspace_component &ds)
char buf[4096];
int num_bytes = 0;
- int const fd_socket = Capability_space::ipc_cap_data(ds.fd()).dst.socket;
+ int const fd_socket = Capability_space::ipc_cap_data(ds.fd()).dst.socket.value;
while ((num_bytes = lx_read(fd_socket, buf, sizeof(buf))) != 0)
lx_write(tmp_binary_fd, buf, num_bytes);
diff --git a/repos/base-linux/src/core/platform.cc b/repos/base-linux/src/core/platform.cc
index d4ff1d7fb..f9d041494 100644
--- a/repos/base-linux/src/core/platform.cc
+++ b/repos/base-linux/src/core/platform.cc
@@ -23,7 +23,7 @@
/* local includes */
#include "platform.h"
#include "core_env.h"
-#include "server_socket_pair.h"
+#include "resource_path.h"
/* Linux includes */
#include
@@ -155,30 +155,6 @@ void Platform::wait_for_exit()
}
-/*****************************
- ** Support for IPC library **
- *****************************/
-
-namespace Genode {
-
- Socket_pair server_socket_pair()
- {
- return create_server_socket_pair(Thread::myself()->native_thread().tid);
- }
-
- void destroy_server_socket_pair(Socket_pair socket_pair)
- {
- /*
- * As entrypoints in core are never destructed, this function is only
- * called on IPC-client destruction. In this case, it's a no-op in core
- * as well as in Genode processes.
- */
- if (socket_pair.server_sd != -1 || socket_pair.client_sd != -1)
- error(__func__, " called for IPC server which should never happen");
- }
-}
-
-
/****************************************************
** Support for Platform_env_base::Region_map_mmap **
****************************************************/
@@ -208,7 +184,7 @@ int Region_map_mmap::_dataspace_fd(Capability ds_cap)
* dataspace, the descriptor would unexpectedly be closed again.
*/
return core_env().entrypoint().apply(lx_ds_cap, [] (Linux_dataspace *ds) {
- return ds ? lx_dup(Capability_space::ipc_cap_data(ds->fd()).dst.socket) : -1; });
+ return ds ? lx_dup(Capability_space::ipc_cap_data(ds->fd()).dst.socket.value) : -1; });
}
diff --git a/repos/base-linux/src/core/platform_thread.cc b/repos/base-linux/src/core/platform_thread.cc
index 08bf2ffb5..efc7e2b9f 100644
--- a/repos/base-linux/src/core/platform_thread.cc
+++ b/repos/base-linux/src/core/platform_thread.cc
@@ -18,7 +18,7 @@
/* local includes */
#include "platform_thread.h"
-#include "server_socket_pair.h"
+#include
using namespace Genode;
@@ -85,14 +85,6 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned,
Platform_thread::~Platform_thread()
{
- ep_sd_registry().disassociate(_socket_pair.client_sd);
-
- if (_socket_pair.client_sd)
- lx_close(_socket_pair.client_sd);
-
- if (_socket_pair.server_sd)
- lx_close(_socket_pair.server_sd);
-
_registry().remove(this);
}
@@ -114,19 +106,3 @@ void Platform_thread::resume()
warning(__func__, "not implemented");
}
-
-int Platform_thread::client_sd()
-{
- /* construct socket pair on first call */
- if (_socket_pair.client_sd == -1)
- _socket_pair = create_server_socket_pair(_tid);
-
- return _socket_pair.client_sd;
-}
-
-
-int Platform_thread::server_sd()
-{
- client_sd();
- return _socket_pair.server_sd;
-}
diff --git a/repos/base-linux/src/core/ram_dataspace_support.cc b/repos/base-linux/src/core/ram_dataspace_support.cc
index 1fe478bda..f4f3126b0 100644
--- a/repos/base-linux/src/core/ram_dataspace_support.cc
+++ b/repos/base-linux/src/core/ram_dataspace_support.cc
@@ -56,12 +56,7 @@ void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &ds)
}
-void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component &ds)
-{
- int const fd = Capability_space::ipc_cap_data(ds.fd()).dst.socket;
- if (fd != -1)
- lx_close(fd);
-}
+void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component &) { }
void Ram_dataspace_factory::_clear_ds(Dataspace_component &) { }
diff --git a/repos/base-linux/src/core/rom_session_component.cc b/repos/base-linux/src/core/rom_session_component.cc
index 46f704521..fad600f1a 100644
--- a/repos/base-linux/src/core/rom_session_component.cc
+++ b/repos/base-linux/src/core/rom_session_component.cc
@@ -56,8 +56,4 @@ Rom_session_component::Rom_session_component(Rom_fs &,
Rom_session_component::~Rom_session_component()
{
_ds_ep.dissolve(&_ds);
-
- int const fd = Capability_space::ipc_cap_data(_ds.fd()).dst.socket;
- if (fd != -1)
- lx_close(fd);
}
diff --git a/repos/base-linux/src/core/rpc_cap_factory_linux.cc b/repos/base-linux/src/core/rpc_cap_factory_linux.cc
new file mode 100644
index 000000000..09bf63fe6
--- /dev/null
+++ b/repos/base-linux/src/core/rpc_cap_factory_linux.cc
@@ -0,0 +1,27 @@
+/*
+ * \brief RPC capability factory
+ * \author Norman Feske
+ * \date 2016-01-19
+ */
+
+/*
+ * Copyright (C) 2016-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* core includes */
+#include
+
+using namespace Genode;
+
+
+Native_capability Rpc_cap_factory::alloc(Native_capability)
+{
+ return Native_capability();
+}
+
+
+void Rpc_cap_factory::free(Native_capability) { }
+
diff --git a/repos/base-linux/src/core/spec/linux/dataspace_component.cc b/repos/base-linux/src/core/spec/linux/dataspace_component.cc
index 90f4df660..1575f2250 100644
--- a/repos/base-linux/src/core/spec/linux/dataspace_component.cc
+++ b/repos/base-linux/src/core/spec/linux/dataspace_component.cc
@@ -64,13 +64,13 @@ Dataspace_component::Dataspace_component(const char *args)
: _fname(_file_name(args)),
_size(_file_size()),
_addr(0),
- _fd(lx_open(_fname.buf, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR)),
+ _cap(_fd_to_cap(lx_open(_fname.buf, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR))),
_writable(false),
_owner(0) { }
Dataspace_component::Dataspace_component(size_t size, addr_t, addr_t phys_addr,
Cache_attribute, bool, Dataspace_owner *_owner) :
- _size(size), _addr(phys_addr), _fd(-1), _writable(false), _owner(_owner)
+ _size(size), _addr(phys_addr), _cap(), _writable(false), _owner(_owner)
{
warning("Should only be used for IOMEM and not within Linux.");
_fname.buf[0] = 0;
diff --git a/repos/base-linux/src/include/base/internal/capability_space_tpl.h b/repos/base-linux/src/include/base/internal/capability_space_tpl.h
new file mode 100644
index 000000000..e856d848e
--- /dev/null
+++ b/repos/base-linux/src/include/base/internal/capability_space_tpl.h
@@ -0,0 +1,281 @@
+/*
+ * \brief Capability-space management for base-linux
+ * \author Norman Feske
+ * \date 2016-06-15
+ *
+ * On Linux, a capability is represented by a socket descriptor and an RPC
+ * object key. The thread ID respectively socket descriptor refer to the
+ * recipient of an RPC call (RPC destination).
+ */
+
+/*
+ * Copyright (C) 2016-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _INCLUDE__BASE__INTERNAL__CAPABILITY_SPACE_TPL_H_
+#define _INCLUDE__BASE__INTERNAL__CAPABILITY_SPACE_TPL_H_
+
+/* base includes */
+#include
+#include
+#include
+#include
+#include
+
+/* base-internal includes */
+#include
+#include
+#include
+
+namespace Genode { template class Capability_space_tpl; }
+
+
+/**
+ * Platform-specific supplement to the generic 'Capability_space' interface
+ */
+namespace Genode { namespace Capability_space {
+
+ /**
+ * Information needed to transfer capability via the kernel's IPC mechanism
+ */
+ struct Ipc_cap_data
+ {
+ Rpc_destination dst;
+ Rpc_obj_key rpc_obj_key;
+
+ Ipc_cap_data(Rpc_destination dst, Rpc_obj_key rpc_obj_key)
+ : dst(dst), rpc_obj_key(rpc_obj_key) { }
+
+ void print(Output &out) const { Genode::print(out, dst, ",", rpc_obj_key); }
+ };
+
+ /**
+ * Retrieve IPC data for given capability
+ */
+ Ipc_cap_data ipc_cap_data(Native_capability const &cap);
+
+ Native_capability lookup(Rpc_obj_key);
+
+ Native_capability import(Rpc_destination, Rpc_obj_key);
+} }
+
+
+/**
+ * Capability space template
+ *
+ * The capability space of core and non-core components differ in two ways.
+ *
+ * First, core must keep track of all capabilities of the system. Hence, its
+ * capability space must be dimensioned larger.
+ *
+ * Second, core has to maintain the information about the PD session that
+ * was used to allocate the capability to prevent misbehaving clients from
+ * freeing capabilities allocated from another component. This information
+ * is part of the core-specific 'Native_capability::Data' structure.
+ */
+template
+class Genode::Capability_space_tpl : Noncopyable
+{
+ private:
+
+ typedef CAP_DATA Data;
+
+ /**
+ * Supplement Native_capability::Data with the meta data needed to
+ * manage it in an AVL tree
+ */
+ struct Tree_managed_data : Data, Avl_node
+ {
+ template
+ Tree_managed_data(ARGS... args) : Data(args...) { }
+
+ Tree_managed_data() { }
+
+ bool higher(Tree_managed_data *data)
+ {
+ return data->rpc_obj_key().value() > this->rpc_obj_key().value();
+ }
+
+ Tree_managed_data *find_by_key(Rpc_obj_key key)
+ {
+ if (key.value() == this->rpc_obj_key().value()) return this;
+
+ Tree_managed_data *data =
+ this->child(key.value() > this->rpc_obj_key().value());
+
+ return data ? data->find_by_key(key) : nullptr;
+ }
+ };
+
+ Tree_managed_data _caps_data[NUM_CAPS];
+ Bit_allocator _alloc { };
+ Avl_tree _tree { };
+ Mutex mutable _mutex { };
+
+ /**
+ * Calculate index into _caps_data for capability data object
+ */
+ unsigned _index(Data const &data) const
+ {
+ addr_t const offset = (addr_t)&data - (addr_t)_caps_data;
+ return offset / sizeof(_caps_data[0]);
+ }
+
+ Data *_lookup_unsynchronized(Rpc_obj_key key) const
+ {
+ /* omit lookup of reply capabilities as they are always foreign */
+ if (!key.valid())
+ return nullptr;
+
+ if (!_tree.first())
+ return nullptr;
+
+ return _tree.first()->find_by_key(key);
+ }
+
+ /**
+ * Create Genode capability
+ *
+ * The arguments are passed to the constructor of the
+ * 'Native_capability::Data' type.
+ */
+ template
+ Native_capability::Data &_create_capability_unsynchronized(ARGS &&... args)
+ {
+ addr_t const index = _alloc.alloc();
+
+ Tree_managed_data &data = _caps_data[index];
+
+ construct_at(&data, args...);
+
+ /*
+ * Register capability in the tree only if it refers to a valid
+ * object hosted locally within the component (not foreign).
+ */
+ if (data.rpc_obj_key().valid() && !data.dst.foreign)
+ _tree.insert(&data);
+
+ return data;
+ }
+
+ public:
+
+ void dec_ref(Data &data)
+ {
+ Mutex::Guard guard(_mutex);
+
+ if (data.dec_ref() > 0)
+ return;
+
+ /*
+ * Reference count reached zero. Release the socket descriptors
+ * of the capability-space entry and mark the entry as free.
+ */
+
+ if (data.rpc_obj_key().valid() && !data.dst.foreign)
+ _tree.remove(static_cast(&data));
+
+ if (data.dst.socket.valid()) {
+ lx_close(data.dst.socket.value);
+
+ /*
+ * Close local socketpair end of a locally-implemented RPC
+ * object.
+ */
+ if (!data.dst.foreign)
+ lx_close(data.rpc_obj_key().value());
+
+ }
+
+ int const index = _index(data);
+
+ _caps_data[index].dst = Rpc_destination::invalid();
+ _alloc.free(index);
+
+ data = Tree_managed_data();
+ }
+
+ void inc_ref(Data &data)
+ {
+ Mutex::Guard guard(_mutex);
+
+ if (data.inc_ref() == 255)
+ throw Native_capability::Reference_count_overflow();
+ }
+
+ Rpc_obj_key rpc_obj_key(Data const &data) const
+ {
+ return data.rpc_obj_key();
+ }
+
+ void print(Output &out, Data const &data) const
+ {
+ ipc_cap_data(data).print(out);
+ Genode::print(out, ",index=", _index(data));
+ }
+
+ Capability_space::Ipc_cap_data ipc_cap_data(Data const &data) const
+ {
+ return { data.dst, data.rpc_obj_key() };
+ }
+
+ Native_capability lookup(Rpc_obj_key)
+ {
+ /*
+ * This method is never called on base-linux. It merely exists
+ * for the compatiblity with the generic 'capability_space.cc'.
+ */
+ struct Unreachable { };
+ throw Unreachable();
+ }
+
+ Native_capability import(Rpc_destination dst, Rpc_obj_key key)
+ {
+ Data *data_ptr = nullptr;
+
+ {
+ Mutex::Guard guard(_mutex);
+
+ data_ptr = _lookup_unsynchronized(key);
+
+ if (data_ptr && !data_ptr->dst.foreign) {
+
+ /*
+ * Compare if existing and incoming sockets refer to the
+ * same inode. If yes, they refer to an RPC object hosted
+ * in the local component. In this case, discard the
+ * incoming socket and keep using the original one.
+ */
+ if (data_ptr->dst.socket.inode() == dst.socket.inode()) {
+ lx_close(dst.socket.value);
+
+ } else {
+
+ /* force occupation of new capability slot */
+ data_ptr = nullptr;
+ }
+ }
+
+ if (data_ptr == nullptr)
+ data_ptr = &_create_capability_unsynchronized(dst, key);
+ }
+
+ /* 'Native_capability' constructor aquires '_mutex' via 'inc_ref' */
+ return Native_capability(data_ptr);
+ }
+};
+
+
+namespace Genode { static inline Rpc_destination invalid_rpc_destination(); }
+
+
+/* for compatiblity with generic 'capability_space.cc' */
+static inline Genode::Rpc_destination Genode::invalid_rpc_destination()
+{
+ return Rpc_destination::invalid();
+}
+
+#endif /* _INCLUDE__BASE__INTERNAL__CAPABILITY_SPACE_TPL_H_ */
diff --git a/repos/base-linux/src/include/base/internal/local_capability.h b/repos/base-linux/src/include/base/internal/local_capability.h
index c144867d7..d3d388914 100644
--- a/repos/base-linux/src/include/base/internal/local_capability.h
+++ b/repos/base-linux/src/include/base/internal/local_capability.h
@@ -27,7 +27,7 @@ namespace Genode {
*/
static inline bool local(Untyped_capability const &cap)
{
- return Capability_space::ipc_cap_data(cap).dst.socket == -1;
+ return Capability_space::ipc_cap_data(cap).dst.socket.value == -1;
}
}
@@ -54,7 +54,7 @@ class Genode::Local_capability
*/
static Capability local_cap(RPC_INTERFACE* ptr) {
Untyped_capability cap =
- Capability_space::import(invalid_rpc_destination(),
+ Capability_space::import(Rpc_destination::invalid(),
Rpc_obj_key((long)ptr));
return reinterpret_cap_cast(cap); }
diff --git a/repos/base-linux/src/include/base/internal/native_thread.h b/repos/base-linux/src/include/base/internal/native_thread.h
index e3d8aec8c..120b4f36d 100644
--- a/repos/base-linux/src/include/base/internal/native_thread.h
+++ b/repos/base-linux/src/include/base/internal/native_thread.h
@@ -15,40 +15,99 @@
#define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_
#include
-#include
+#include
+
+#include
namespace Genode { struct Native_thread; }
-struct Genode::Native_thread
+class Genode::Native_thread
{
- /*
- * Unfortunately, both - PID and TID - are needed for lx_tgkill()
- */
- unsigned int tid = 0; /* Native thread ID type as returned by the
- 'clone' system call */
- unsigned int pid = 0; /* process ID (resp. thread-group ID) */
+ private:
- bool is_ipc_server = false;
+ /*
+ * Noncopyable
+ */
+ Native_thread(Native_thread const &);
+ Native_thread &operator = (Native_thread const &);
- /**
- * Natively aligned memory location used in the lock implementation
- */
- int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0;
+ public:
- struct Meta_data;
+ /*
+ * Unfortunately, both - PID and TID - are needed for lx_tgkill()
+ */
+ unsigned int tid = 0; /* Native thread ID type as returned by the
+ 'clone' system call */
+ unsigned int pid = 0; /* process ID (resp. thread-group ID) */
- /**
- * Opaque pointer to additional thread-specific meta data
- *
- * This pointer is used by hybrid Linux/Genode programs to maintain
- * POSIX-thread-related meta data. For non-hybrid Genode programs, it
- * remains unused.
- */
- Meta_data *meta_data = nullptr;
+ bool is_ipc_server = false;
- Socket_pair socket_pair { };
+ /**
+ * Natively aligned memory location used in the lock implementation
+ */
+ int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0;
- Native_thread() { }
+ struct Meta_data;
+
+ /**
+ * Opaque pointer to additional thread-specific meta data
+ *
+ * This pointer is used by hybrid Linux/Genode programs to maintain
+ * POSIX-thread-related meta data. For non-hybrid Genode programs, it
+ * remains unused.
+ */
+ Meta_data *meta_data = nullptr;
+
+ class Epoll
+ {
+ private:
+
+ Lx_socketpair _control { };
+
+ Lx_epoll_sd const _epoll;
+
+ void _add (Lx_sd);
+ void _remove(Lx_sd);
+
+ bool _rpc_ep_exited = false;
+
+ struct Control_function : Interface
+ {
+ virtual void execute() = 0;
+ };
+
+ /*
+ * Execute functor 'fn' in the context of the 'poll' method.
+ */
+ template
+ void _exec_control(FN const &);
+
+ public:
+
+ Epoll();
+
+ ~Epoll();
+
+ /**
+ * Wait for incoming RPC messages
+ *
+ * \return valid socket descriptor that matches the invoked
+ * RPC object
+ */
+ Lx_sd poll();
+
+ Native_capability alloc_rpc_cap();
+
+ void free_rpc_cap(Native_capability);
+
+ /**
+ * Flag RPC entrypoint as no longer in charge of dispatching
+ */
+ void rpc_ep_exited() { _rpc_ep_exited = true; }
+
+ } epoll { };
+
+ Native_thread() { }
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */
diff --git a/repos/base-linux/src/include/base/internal/rpc_destination.h b/repos/base-linux/src/include/base/internal/rpc_destination.h
index cf7724b98..46535427a 100644
--- a/repos/base-linux/src/include/base/internal/rpc_destination.h
+++ b/repos/base-linux/src/include/base/internal/rpc_destination.h
@@ -15,27 +15,35 @@
#define _INCLUDE__BASE__INTERNAL__RPC_DESTINATION_H_
#include
+#include
-namespace Genode {
+#include
- struct Rpc_destination
+
+namespace Genode { struct Rpc_destination; }
+
+
+struct Genode::Rpc_destination
+{
+ Lx_sd socket;
+
+ /*
+ * Distinction between a capability referring to a locally implemented
+ * RPC object and a capability referring to an RPC object hosted in
+ * a different component.
+ */
+ bool foreign = true;
+
+ Rpc_destination(Lx_sd socket) : socket(socket) { }
+
+ bool valid() const { return socket.valid(); }
+
+ static Rpc_destination invalid() { return Rpc_destination(Lx_sd::invalid()); }
+
+ void print(Output &out) const
{
- int socket = -1;
-
- explicit Rpc_destination(int socket) : socket(socket) { }
-
- Rpc_destination() { }
- };
-
- static inline Rpc_destination invalid_rpc_destination()
- {
- return Rpc_destination();
+ Genode::print(out, "socket=", socket, ",foreign=", foreign);
}
-
- static void print(Output &out, Rpc_destination const &dst)
- {
- Genode::print(out, "socket=", dst.socket);
- }
-}
+};
#endif /* _INCLUDE__BASE__INTERNAL__RPC_DESTINATION_H_ */
diff --git a/repos/base-linux/src/include/base/internal/server_socket_pair.h b/repos/base-linux/src/include/base/internal/server_socket_pair.h
deleted file mode 100644
index b4d60aa1e..000000000
--- a/repos/base-linux/src/include/base/internal/server_socket_pair.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * \brief Socket pair used by RPC entrypoint
- * \author Norman Feske
- * \date 2016-03-25
- */
-
-/*
- * Copyright (C) 2016-2017 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_
-#define _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_
-
-namespace Genode {
-
- struct Socket_pair
- {
- int client_sd = -1;
- int server_sd = -1;
- };
-
- /*
- * Helper for obtaining a bound and connected socket pair
- *
- * For core, the implementation is just a wrapper around
- * 'lx_server_socket_pair()'. For all other processes, the implementation
- * requests the socket pair from the Env::CPU session interface using a
- * Linux-specific interface extension.
- */
- Socket_pair server_socket_pair();
-
- /*
- * Helper to destroy the server socket pair
- *
- * For core, this is a no-op. For all other processes, the server and client
- * sockets are closed.
- */
- void destroy_server_socket_pair(Socket_pair);
-}
-
-#endif /* _INCLUDE__BASE__INTERNAL__SERVER_SOCKET_PAIR_H_ */
diff --git a/repos/base-linux/src/include/base/internal/socket_descriptor_registry.h b/repos/base-linux/src/include/base/internal/socket_descriptor_registry.h
deleted file mode 100644
index 189c6970a..000000000
--- a/repos/base-linux/src/include/base/internal/socket_descriptor_registry.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * \brief Linux-specific socket-descriptor registry
- * \author Norman Feske
- * \date 2012-07-26
- *
- * We use the names of Unix-domain sockets as keys to uniquely identify
- * entrypoints. When receiving a socket descriptor as IPC payload, we first
- * lookup the corresponding entrypoint ID. If we already possess a socket
- * descriptor pointing to the same entrypoint, we close the received one and
- * use the already known descriptor instead.
- */
-
-/*
- * Copyright (C) 2012-2017 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _INCLUDE__BASE__INTERNAL__SOCKET_DESCRIPTOR_REGISTRY_H_
-#define _INCLUDE__BASE__INTERNAL__SOCKET_DESCRIPTOR_REGISTRY_H_
-
-#include
-
-
-namespace Genode
-{
- template
- class Socket_descriptor_registry;
-
- typedef Socket_descriptor_registry<100> Ep_socket_descriptor_registry;
-
- /**
- * Return singleton instance of registry for tracking entrypoint sockets
- */
- Ep_socket_descriptor_registry &ep_sd_registry();
-}
-
-
-template
-class Genode::Socket_descriptor_registry
-{
- public:
-
- class Limit_reached { };
- class Aliased_global_id { };
-
- private:
-
- struct Entry
- {
- int fd;
- int global_id;
-
- /**
- * Default constructor creates empty entry
- */
- Entry() : fd(-1), global_id(-1) { }
-
- Entry(int fd, int global_id) : fd(fd), global_id(global_id) { }
-
- bool is_free() const { return fd == -1; }
-
- void mark_as_free() { fd = -1; }
- };
-
- Entry _entries[MAX_FDS];
-
- Genode::Lock mutable _lock { };
-
- Entry &_find_free_entry()
- {
- for (unsigned i = 0; i < MAX_FDS; i++)
- if (_entries[i].is_free())
- return _entries[i];
-
- throw Limit_reached();
- }
-
- Entry &_find_entry_by_fd(int fd)
- {
- for (unsigned i = 0; i < MAX_FDS; i++)
- if (_entries[i].fd == fd)
- return _entries[i];
-
- throw Limit_reached();
- }
-
- /**
- * Lookup file descriptor that belongs to specified global ID
- *
- * \return file descriptor or -1 if lookup failed
- */
- int _lookup_fd_by_global_id(int global_id) const
- {
- for (unsigned i = 0; i < MAX_FDS; i++)
- if (_entries[i].global_id == global_id)
- return _entries[i].fd;
-
- return -1;
- }
-
- public:
-
- void disassociate(int sd)
- {
- Genode::Lock::Guard guard(_lock);
-
- for (unsigned i = 0; i < MAX_FDS; i++)
- if (_entries[i].fd == sd) {
- _entries[i].mark_as_free();
- return;
- }
- }
-
- /**
- * Try to associate socket descriptor with corresponding ID
- *
- * \return socket descriptor associated with the ID
- * \throw Limit_reached
- *
- * If the ID was already associated, the return value is the originally
- * registered socket descriptor. In this case, the caller should drop
- * the new socket descriptor and use the one returned by this function.
- */
- int try_associate(int sd, int global_id)
- {
- /* ignore invalid capabilities */
- if (sd == -1)
- return sd;
-
- /* ignore invalid capabilities */
- if (sd == -1 || global_id == -1)
- return sd;
-
- Genode::Lock::Guard guard(_lock);
-
- int const existing_sd = _lookup_fd_by_global_id(global_id);
-
- if (existing_sd < 0) {
- Entry &entry = _find_free_entry();
- entry = Entry(sd, global_id);
- return sd;
- } else {
- return existing_sd;
- }
- }
-};
-
-#endif /* _INCLUDE__BASE__INTERNAL__SOCKET_DESCRIPTOR_REGISTRY_H_ */
diff --git a/repos/base-linux/src/include/linux_native_cpu/client.h b/repos/base-linux/src/include/linux_native_cpu/client.h
index af9cbaa66..92a102805 100644
--- a/repos/base-linux/src/include/linux_native_cpu/client.h
+++ b/repos/base-linux/src/include/linux_native_cpu/client.h
@@ -26,12 +26,6 @@ struct Genode::Linux_native_cpu_client : Rpc_client
void thread_id(Thread_capability thread, int pid, int tid) override {
call(thread, pid, tid); }
-
- Untyped_capability server_sd(Thread_capability thread) override {
- return call(thread); }
-
- Untyped_capability client_sd(Thread_capability thread) override {
- return call(thread); }
};
#endif /* _INCLUDE__LINUX_NATIVE_CPU__CLIENT_H_ */
diff --git a/repos/base-linux/src/include/linux_native_cpu/linux_native_cpu.h b/repos/base-linux/src/include/linux_native_cpu/linux_native_cpu.h
index a9fa0320a..5069408bc 100644
--- a/repos/base-linux/src/include/linux_native_cpu/linux_native_cpu.h
+++ b/repos/base-linux/src/include/linux_native_cpu/linux_native_cpu.h
@@ -27,42 +27,14 @@ struct Genode::Linux_native_cpu : Cpu_session::Native_cpu
*/
virtual void thread_id(Thread_capability, int pid, int tid) = 0;
- /*
- * If a thread plays the role of an entrypoint, core creates a bound
- * socket pair for the thread and passes both makes the socket
- * descriptors of both ends available to the owner of the thread's
- * CPU session via the 'server_sd' and 'client_sd' function.
- */
-
- /**
- * Request server-side socket descriptor
- *
- * The socket descriptor returned by this function is meant to be used
- * exclusively by the server for receiving incoming requests. It should
- * never leave the server process.
- */
- virtual Untyped_capability server_sd(Thread_capability thread) = 0;
-
- /**
- * Request client-side socket descriptor
- *
- * The returned socket descriptor enables a client to send messages to
- * the thread. It is already connected to the 'server_sd' descriptor.
- * In contrast to 'server_sd', the 'client_sd' is expected to be passed
- * around via capability delegations.
- */
- virtual Untyped_capability client_sd(Thread_capability thread) = 0;
-
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_thread_id, void, thread_id, Thread_capability, int, int);
- GENODE_RPC(Rpc_server_sd, Untyped_capability, server_sd, Thread_capability);
- GENODE_RPC(Rpc_client_sd, Untyped_capability, client_sd, Thread_capability);
- GENODE_RPC_INTERFACE(Rpc_thread_id, Rpc_server_sd, Rpc_client_sd);
+ GENODE_RPC_INTERFACE(Rpc_thread_id);
};
#endif /* _INCLUDE__LINUX_NATIVE_CPU__LINUX_NATIVE_CPU_H_ */
diff --git a/repos/base-linux/src/lib/base/ipc.cc b/repos/base-linux/src/lib/base/ipc.cc
index 7d58e7d00..6999cc961 100644
--- a/repos/base-linux/src/lib/base/ipc.cc
+++ b/repos/base-linux/src/lib/base/ipc.cc
@@ -2,11 +2,13 @@
* \brief Socket-based IPC implementation for Linux
* \author Norman Feske
* \author Christian Helmuth
+ * \author Stefan Thoeni
* \date 2011-10-11
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@@ -17,13 +19,12 @@
#include
#include
#include
+#include
#include
/* base-internal includes */
-#include
#include
#include
-#include
#include
/* Linux includes */
@@ -31,7 +32,6 @@
using namespace Genode;
-
namespace {
struct Pid
@@ -56,11 +56,11 @@ namespace {
* long exception code
* ...call results...
*
- * First data word of message, used to transfer the local name of the invoked
- * object (when a client calls a server) or the exception code (when the server
- * replies). This data word is never fetched from memory but transferred via
- * the first short-IPC register. The 'protocol_word' is needed as a spacer
- * between the header fields define above and the regular message payload..
+ * First data word of message, used to transfer the exception code (when the
+ * server replies). This data word is never fetched from memory but
+ * transferred via the first short-IPC register. The 'protocol_word' is needed
+ * as a spacer between the header fields defined above and the regular message
+ * payload.
*/
struct Protocol_header
{
@@ -87,86 +87,17 @@ static_assert((int)Protocol_header::INVALID_BADGE != (int)Rpc_obj_key::INVALID,
"ambigious INVALID_BADGE");
-/******************************
- ** File-descriptor registry **
- ******************************/
-
-Genode::Ep_socket_descriptor_registry &Genode::ep_sd_registry()
-{
- static Genode::Ep_socket_descriptor_registry registry;
- return registry;
-}
-
-
/********************************************
** Communication over Unix-domain sockets **
********************************************/
enum {
LX_EINTR = 4,
+ LX_EAGAIN = 11,
LX_ECONNREFUSED = 111
};
-/**
- * Utility: Return thread ID to which the given socket is directed to
- *
- * \return -1 if the socket is pointing to a valid entrypoint
- */
-static int lookup_tid_by_client_socket(int sd)
-{
- /*
- * Synchronize calls so that the large 'sockaddr_un' can be allocated
- * in the BSS rather than the stack.
- */
- static Lock lock;
- Lock::Guard guard(lock);
-
- static sockaddr_un name;
- socklen_t name_len = sizeof(name);
- int ret = lx_getpeername(sd, (sockaddr *)&name, &name_len);
- if (ret < 0)
- return -1;
-
- struct Prefix_len
- {
- typedef Genode::size_t size_t;
-
- size_t const len;
-
- static int _init_len(char const *s)
- {
- char const * const pattern = "/ep-";
- static size_t const pattern_len = Genode::strlen(pattern);
-
- for (size_t i = 0; Genode::strlen(s + i) >= pattern_len; i++)
- if (Genode::strcmp(s + i, pattern, pattern_len) == 0)
- return i + pattern_len;
-
- struct Unexpected_rpath_prefix { };
- throw Unexpected_rpath_prefix();
- }
-
- Prefix_len(char const *s) : len(_init_len(s)) { }
- };
-
- /*
- * The name of the Unix-domain socket has the form -/ep-.
- * We are only interested in the part. Hence, we determine the length
- * of the -/ep- portion only once and keep it in a static
- * variable.
- */
- static Prefix_len prefix_len(name.sun_path);
-
- unsigned tid = 0;
- if (Genode::ascii_to(name.sun_path + prefix_len.len, tid) == 0) {
- raw("Error: could not parse tid number");
- return -1;
- }
- return tid;
-}
-
-
namespace {
/**
@@ -217,9 +148,9 @@ namespace {
msghdr * msg() { return &_msg; }
- void marshal_socket(int sd)
+ void marshal_socket(Lx_sd sd)
{
- *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd;
+ *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd.value;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
if (cmsg) {
@@ -236,9 +167,9 @@ namespace {
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
}
- int socket_at_index(int index) const
+ Lx_sd socket_at_index(int index) const
{
- return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index);
+ return Lx_sd { *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index) };
}
unsigned num_sockets() const
@@ -263,12 +194,25 @@ static void insert_sds_into_message(Message &msg,
Native_capability const &cap = snd_msgbuf.cap(i);
- if (cap.valid()) {
+ auto remote_socket_of_capability = [] (Native_capability const &cap)
+ {
+ if (!cap.valid())
+ return Lx_sd::invalid();
+
Capability_space::Ipc_cap_data cap_data =
Capability_space::ipc_cap_data(cap);
- msg.marshal_socket(cap_data.dst.socket);
- header.badges[i] = cap_data.rpc_obj_key.value();
+ if (cap_data.dst.socket.value < 0)
+ return Lx_sd::invalid();
+
+ return cap_data.dst.socket;
+ };
+
+ Lx_sd const socket = remote_socket_of_capability(cap);
+
+ if (socket.valid()) {
+ msg.marshal_socket(socket);
+ header.badges[i] = Capability_space::ipc_cap_data(cap).rpc_obj_key.value();
} else {
header.badges[i] = Protocol_header::INVALID_BADGE;
}
@@ -297,34 +241,14 @@ static void extract_sds_from_message(unsigned start_index,
continue;
}
- int const sd = msg.socket_at_index(start_index + sd_cnt++);
- int const id = lookup_tid_by_client_socket(sd);
+ Lx_sd const sd = msg.socket_at_index(start_index + sd_cnt++);
- int const associated_sd = Genode::ep_sd_registry().try_associate(sd, id);
+ Rpc_destination const dst(sd);
- Native_capability arg_cap = Capability_space::lookup(Rpc_obj_key(badge));
-
- if (arg_cap.valid()) {
-
- /*
- * Discard the received selector and keep using the already
- * present one.
- */
-
- buf.insert(arg_cap);
- } else {
- buf.insert(Capability_space::import(Rpc_destination(associated_sd),
- Rpc_obj_key(badge)));
- }
-
- if ((associated_sd >= 0) && (associated_sd != sd)) {
-
- /*
- * The association already existed under a different name, use
- * already associated socket descriptor and and drop 'sd'.
- */
- lx_close(sd);
- }
+ if (dst.valid())
+ buf.insert(Capability_space::import(dst, Rpc_obj_key(badge)));
+ else
+ buf.insert(Native_capability());
}
}
@@ -332,7 +256,7 @@ static void extract_sds_from_message(unsigned start_index,
/**
* Send reply to client
*/
-static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
+static inline void lx_reply(Lx_sd reply_socket, Rpc_exception_code exception_code,
Genode::Msgbuf_base &snd_msgbuf)
{
@@ -348,13 +272,11 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
int const ret = lx_sendmsg(reply_socket, msg.msg(), 0);
/* ignore reply send error caused by disappearing client */
- if (ret >= 0 || ret == -LX_ECONNREFUSED) {
- lx_close(reply_socket);
+ if (ret >= 0 || ret == -LX_ECONNREFUSED)
return;
- }
if (ret < 0)
- raw("[", lx_gettid, "] lx_sendmsg failed with ", ret, " "
+ error(lx_getpid(), ":", lx_gettid(), " lx_sendmsg failed with ", ret, " "
"in lx_reply() reply_socket=", reply_socket);
}
@@ -367,8 +289,13 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msgbuf, Msgbuf_base &rcv_msgbuf,
size_t)
{
+ if (!dst.valid()) {
+ error("attempt to call invalid capability, blocking forever");
+ sleep_forever();
+ }
+
Protocol_header &snd_header = snd_msgbuf.header();
- snd_header.protocol_word = dst.local_name();
+ snd_header.protocol_word = 0;
Message snd_msg(snd_header.msg_start(),
sizeof(Protocol_header) + snd_msgbuf.data_size());
@@ -378,49 +305,30 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
*
* The reply channel will be closed when leaving the scope of 'lx_call'.
*/
- struct Reply_channel
+ struct Reply_channel : Lx_socketpair
{
- enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 };
- int sd[2];
-
- Reply_channel()
- {
- sd[LOCAL_SOCKET] = -1; sd[REMOTE_SOCKET] = -1;
-
- int ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, sd);
- if (ret < 0) {
- raw("[", lx_gettid(), "] lx_socketpair failed with ", ret);
- throw Genode::Ipc_error();
- }
- }
-
~Reply_channel()
{
- if (sd[LOCAL_SOCKET] != -1) lx_close(sd[LOCAL_SOCKET]);
- if (sd[REMOTE_SOCKET] != -1) lx_close(sd[REMOTE_SOCKET]);
+ if (local.value != -1) lx_close(local.value);
+ if (remote.value != -1) lx_close(remote.value);
}
-
- int local_socket() const { return sd[LOCAL_SOCKET]; }
- int remote_socket() const { return sd[REMOTE_SOCKET]; }
-
} reply_channel;
/* assemble message */
/* marshal reply capability */
- snd_msg.marshal_socket(reply_channel.remote_socket());
+ snd_msg.marshal_socket(reply_channel.remote);
/* marshal capabilities contained in 'snd_msgbuf' */
insert_sds_into_message(snd_msg, snd_header, snd_msgbuf);
- int const dst_socket = Capability_space::ipc_cap_data(dst).dst.socket;
+ Lx_sd const dst_socket = Capability_space::ipc_cap_data(dst).dst.socket;
int const send_ret = lx_sendmsg(dst_socket, snd_msg.msg(), 0);
if (send_ret < 0) {
- raw(Pid(), " lx_sendmsg to sd ", dst_socket,
+ error(lx_getpid(), ":", lx_gettid(), " lx_sendmsg to sd ", dst_socket,
" failed with ", send_ret, " in lx_call()");
- for (;;);
- throw Genode::Ipc_error();
+ sleep_forever();
}
/* receive reply */
@@ -432,15 +340,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
rcv_msgbuf.reset();
- int const recv_ret = lx_recvmsg(reply_channel.local_socket(), rcv_msg.msg(), 0);
+ int const recv_ret = lx_recvmsg(reply_channel.local, rcv_msg.msg(), 0);
/* system call got interrupted by a signal */
if (recv_ret == -LX_EINTR)
throw Genode::Blocking_canceled();
if (recv_ret < 0) {
- raw("[", lx_getpid(), "] lx_recvmsg failed with ", recv_ret, " in lx_call()");
- throw Genode::Ipc_error();
+ error(lx_getpid(), ":", lx_gettid(), " ipc_call failed to receive result (", recv_ret, ")");
+ sleep_forever();
}
extract_sds_from_message(0, rcv_msg, rcv_header, rcv_msgbuf);
@@ -456,17 +364,17 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
- int const reply_socket = Capability_space::ipc_cap_data(caller).dst.socket;
+ Lx_sd const reply_socket = Capability_space::ipc_cap_data(caller).dst.socket;
try { lx_reply(reply_socket, exc, snd_msg); } catch (Ipc_error) { }
}
-Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
- Rpc_exception_code exc,
- Msgbuf_base &reply_msg,
- Msgbuf_base &request_msg,
- Rpc_entrypoint::Native_context &)
+Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
+ Rpc_exception_code exc,
+ Msgbuf_base &reply_msg,
+ Msgbuf_base &request_msg,
+ Rpc_entrypoint::Native_context &)
{
/* when first called, there was no request yet */
if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT)
@@ -476,49 +384,48 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_
* Block infinitely if called from the main thread. This may happen if the
* main thread calls 'sleep_forever()'.
*/
- if (!Thread::myself()) {
+ Thread *myself_ptr = Thread::myself();
+ if (!myself_ptr) {
struct timespec ts = { 1000, 0 };
for (;;) lx_nanosleep(&ts, 0);
}
+ Native_thread::Epoll &epoll = myself_ptr->native_thread().epoll;
+
for (;;) {
+ Lx_sd const selected_sd = epoll.poll();
+
Protocol_header &header = request_msg.header();
Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity());
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
- Native_thread &native_thread = Thread::myself()->native_thread();
-
request_msg.reset();
- int const ret = lx_recvmsg(native_thread.socket_pair.server_sd, msg.msg(), 0);
+ int const ret = lx_recvmsg(selected_sd, msg.msg(), 0x40);
- /* system call got interrupted by a signal */
- if (ret == -LX_EINTR)
+ if (ret < 0)
continue;
- if (ret < 0) {
- raw("lx_recvmsg failed with ", ret, " in ipc_reply_wait, sd=",
- native_thread.socket_pair.server_sd);
+ if (msg.num_sockets() == 0 || !msg.socket_at_index(0).valid()) {
+ warning("ipc_reply_wait: failed to obtain reply socket");
continue;
}
- int const reply_socket = msg.socket_at_index(0);
- unsigned long const badge = header.protocol_word;
+ Lx_sd const reply_socket = msg.socket_at_index(0);
/* start at offset 1 to skip the reply channel */
extract_sds_from_message(1, msg, header, request_msg);
return Rpc_request(Capability_space::import(Rpc_destination(reply_socket),
- Rpc_obj_key()), badge);
+ Rpc_obj_key()), selected_sd.value);
}
}
-Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& _native_context)
+Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& native_context)
:
- Native_capability(Capability_space::import(Rpc_destination(), Rpc_obj_key())),
- _native_context(_native_context)
+ _native_context(native_context)
{
/*
* If 'thread' is 0, the constructor was called by the main thread. By
@@ -531,21 +438,13 @@ Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& _native_context)
Native_thread &native_thread = Thread::myself()->native_thread();
if (native_thread.is_ipc_server) {
- Genode::raw("[", lx_gettid(), "] "
+ Genode::raw(lx_getpid(), ":", lx_gettid(),
" unexpected multiple instantiation of Ipc_server by one thread");
struct Ipc_server_multiple_instance { };
throw Ipc_server_multiple_instance();
}
- Socket_pair const socket_pair = server_socket_pair();
-
- native_thread.socket_pair = socket_pair;
native_thread.is_ipc_server = true;
-
- /* override capability initialization */
- *static_cast(this) =
- Capability_space::import(Rpc_destination(socket_pair.client_sd),
- Rpc_obj_key());
}
@@ -560,9 +459,5 @@ Ipc_server::~Ipc_server()
*/
Native_thread &native_thread = Thread::myself()->native_thread();
- Genode::ep_sd_registry().disassociate(native_thread.socket_pair.client_sd);
native_thread.is_ipc_server = false;
-
- destroy_server_socket_pair(native_thread.socket_pair);
- native_thread.socket_pair = Socket_pair();
}
diff --git a/repos/base-linux/src/lib/base/native_thread.cc b/repos/base-linux/src/lib/base/native_thread.cc
new file mode 100644
index 000000000..8d54bcdad
--- /dev/null
+++ b/repos/base-linux/src/lib/base/native_thread.cc
@@ -0,0 +1,209 @@
+/*
+ * \brief Native thread implementation for using epoll on base-linux
+ * \author Stefan Thoeni
+ * \author Norman Feske
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2006-2020 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include
+#include
+#include
+
+using namespace Genode;
+
+
+struct Epoll_error : Exception { };
+
+
+Native_thread::Epoll::Epoll()
+:
+ _epoll(lx_epoll_create())
+{
+ _add(_control.local);
+}
+
+
+Native_thread::Epoll::~Epoll()
+{
+ _remove(_control.local);
+
+ lx_close(_control.local.value);
+ lx_close(_control.remote.value);
+
+ lx_close(_epoll.value);
+}
+
+
+void Native_thread::Epoll::_add(Lx_sd sd)
+{
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.fd = sd.value;
+ int ret = lx_epoll_ctl(_epoll, EPOLL_CTL_ADD, sd, &event);
+ if (ret < 0) {
+ warning(lx_getpid(), ":", lx_gettid(), " lx_epoll_ctl add failed with ", ret);
+ throw Epoll_error();
+ }
+}
+
+
+void Native_thread::Epoll::_remove(Lx_sd sd)
+{
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.fd = sd.value;
+ int ret = lx_epoll_ctl(_epoll, EPOLL_CTL_DEL, sd, &event);
+ if (ret == -2) {
+ /* ignore file already closed */
+ } else if (ret == -9) {
+ /* ignore file already closed */
+ } else if (ret < 0) {
+ warning(lx_getpid(), ":", lx_gettid(), " lx_epoll_ctl remove failed with ", ret);
+ throw Epoll_error();
+ }
+}
+
+
+Lx_sd Native_thread::Epoll::poll()
+{
+ for (;;) {
+ epoll_event events[1] { };
+
+ int const event_count = lx_epoll_wait(_epoll, events, 1, -1);
+
+ if ((event_count == 1) && (events[0].events == POLLIN)) {
+
+ Lx_sd const sd { events[0].data.fd };
+
+ if (!sd.valid())
+ continue;
+
+ /* dispatch control messages issued via '_exec_control' */
+ if (sd.value == _control.local.value) {
+
+ Control_function *control_function_ptr = nullptr;
+
+ struct iovec iovec { };
+ iovec.iov_base = &control_function_ptr;
+ iovec.iov_len = sizeof(control_function_ptr);
+
+ struct msghdr msg { };
+ msg.msg_iov = &iovec;
+ msg.msg_iovlen = 1;
+ int const ret = lx_recvmsg(sd, &msg, 0);
+
+ if (ret != sizeof(control_function_ptr) || !control_function_ptr) {
+ error("epoll interrupted by invalid control message");
+ continue;
+ }
+
+ control_function_ptr->execute();
+
+ struct msghdr ack { };
+ (void)lx_sendmsg(sd, &ack, 0);
+ continue;
+ }
+
+ return sd;
+ }
+
+ if (event_count > 1)
+ warning(lx_getpid(), ":", lx_gettid(), " too many events on epoll_wait");
+ }
+}
+
+
+template
+void Native_thread::Epoll::_exec_control(FN const &fn)
+{
+ Thread * const myself_ptr = Thread::myself();
+
+ /*
+ * If 'myself_ptr' is nullptr, the caller is the initial thread w/o
+ * a valid 'Thread' object associated yet. This thread is never polling.
+ */
+ bool const myself_is_polling = (myself_ptr != nullptr)
+ && (&myself_ptr->native_thread().epoll == this);
+
+ /*
+ * If caller runs in the context of the same thread that executes 'poll' we
+ * can perform the control function immediately because 'poll' cannot
+ * block at this time. If the RPC entrypoint has existed its dispatch
+ * loop, it also cannot poll anymore.
+ */
+ if (myself_is_polling || _rpc_ep_exited) {
+ fn();
+ return;
+ }
+
+ /*
+ * If caller is a different thread than the polling thread, interrupt the
+ * polling with a control message, prompting the polling thread to
+ * execute the control function, and resume polling afterwards.
+ */
+ struct Control_function_fn : Control_function
+ {
+ FN const &fn;
+ Control_function_fn(FN const &fn) : fn(fn) { }
+ void execute() override { fn(); }
+
+ } control_function_fn { fn };
+
+ /* send control message with pointer to control function as argument */
+ {
+ Control_function *control_function_ptr = &control_function_fn;
+
+ struct iovec iovec { };
+ iovec.iov_base = &control_function_ptr;
+ iovec.iov_len = sizeof(control_function_ptr);
+
+ struct msghdr msg { };
+ msg.msg_iov = &iovec;
+ msg.msg_iovlen = 1;
+
+ int const ret = lx_sendmsg(_control.remote, &msg, 0);
+ if (ret < 0) {
+ raw(lx_getpid(), ":", lx_gettid(), " _exec_control ",
+ _control.remote.value, " lx_sendmsg failed ", ret);
+ sleep_forever();
+ }
+ }
+
+ /* block for the completion of the control function */
+ {
+ struct msghdr ack { };
+ int const ret = lx_recvmsg(_control.remote, &ack, 0);
+ if (ret < 0)
+ warning("invalid acknowledgement for control message");
+ }
+}
+
+
+Native_capability Native_thread::Epoll::alloc_rpc_cap()
+{
+ Lx_socketpair socketpair;
+
+ Rpc_destination dst(socketpair.remote);
+
+ dst.foreign = false;
+
+ _exec_control([&] () { _add(socketpair.local); });
+
+ return Capability_space::import(dst, Rpc_obj_key(socketpair.local.value));
+}
+
+
+void Native_thread::Epoll::free_rpc_cap(Native_capability cap)
+{
+ int const local_socket = Capability_space::ipc_cap_data(cap).rpc_obj_key.value();
+
+ _exec_control([&] () { _remove(Lx_sd{local_socket}); });
+}
diff --git a/repos/base-linux/src/lib/base/platform.cc b/repos/base-linux/src/lib/base/platform.cc
new file mode 100644
index 000000000..d2482b0fd
--- /dev/null
+++ b/repos/base-linux/src/lib/base/platform.cc
@@ -0,0 +1,22 @@
+/*
+ * \brief Platform dependant hook after binary ready
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+
+/* base-internal includes */
+#include
+
+void binary_ready_hook_for_platform()
+{
+}
+
diff --git a/repos/base-linux/src/lib/base/platform_env.cc b/repos/base-linux/src/lib/base/platform_env.cc
index 6cc5bb00c..5e0223580 100644
--- a/repos/base-linux/src/lib/base/platform_env.cc
+++ b/repos/base-linux/src/lib/base/platform_env.cc
@@ -44,7 +44,7 @@ size_t Region_map_mmap::_dataspace_size(Dataspace_capability ds)
int Region_map_mmap::_dataspace_fd(Dataspace_capability ds)
{
Untyped_capability fd_cap = Linux_dataspace_client(ds).fd();
- return Capability_space::ipc_cap_data(fd_cap).dst.socket;
+ return lx_dup(Capability_space::ipc_cap_data(fd_cap).dst.socket.value);
}
@@ -138,7 +138,7 @@ static Parent_capability obtain_parent_cap()
long const local_name = get_env_ulong("parent_local_name");
Untyped_capability parent_cap =
- Capability_space::import(Rpc_destination(PARENT_SOCKET_HANDLE),
+ Capability_space::import(Rpc_destination(Lx_sd{PARENT_SOCKET_HANDLE}),
Rpc_obj_key(local_name));
return reinterpret_cap_cast(parent_cap);
@@ -169,34 +169,3 @@ Platform_env::Platform_env()
native_cpu.thread_id(parent()->main_thread_cap(), lx_getpid(), lx_gettid());
}
-
-/*****************************
- ** Support for IPC library **
- *****************************/
-
-namespace Genode {
-
- Socket_pair server_socket_pair()
- {
- Linux_native_cpu_client native_cpu(env_deprecated()->cpu_session()->native_cpu());
-
- Socket_pair socket_pair;
-
- Thread *thread = Thread::myself();
- if (thread) {
- Untyped_capability server_cap = native_cpu.server_sd(thread->cap());
- Untyped_capability client_cap = native_cpu.client_sd(thread->cap());
- socket_pair.server_sd = Capability_space::ipc_cap_data(server_cap).dst.socket;
- socket_pair.client_sd = Capability_space::ipc_cap_data(client_cap).dst.socket;
- thread->native_thread().socket_pair = socket_pair;
- }
- return socket_pair;
- }
-
- void destroy_server_socket_pair(Socket_pair socket_pair)
- {
- /* close local file descriptor if it is valid */
- if (socket_pair.server_sd != -1) lx_close(socket_pair.server_sd);
- if (socket_pair.client_sd != -1) lx_close(socket_pair.client_sd);
- }
-}
diff --git a/repos/base-linux/src/lib/base/rpc_cap_alloc.cc b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc
new file mode 100644
index 000000000..9645fd496
--- /dev/null
+++ b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc
@@ -0,0 +1,64 @@
+/*
+ * \brief Back end of the RPC entrypoint
+ * \author Norman Feske
+ * \date 2016-01-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+
+/* base-internal includes */
+#include
+
+using namespace Genode;
+
+
+Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session& pd, Native_capability,
+ addr_t)
+{
+ /* first we allocate a cap from core, to allow accounting of caps. */
+ for (;;) {
+ Ram_quota ram_upgrade { 0 };
+ Cap_quota cap_upgrade { 0 };
+
+ try { pd.alloc_rpc_cap(_cap); break; }
+ catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
+ catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
+
+ env_deprecated()->parent()->upgrade(Parent::Env::pd(),
+ String<100>("ram_quota=", ram_upgrade, ", "
+ "cap_quota=", cap_upgrade).string());
+ }
+
+ return Thread::native_thread().epoll.alloc_rpc_cap();
+}
+
+
+void Rpc_entrypoint::_free_rpc_cap(Pd_session& pd, Native_capability cap)
+{
+ Native_thread::Epoll &epoll = Thread::native_thread().epoll;
+
+ /*
+ * Flag RPC entrypoint as exited to prevent 'free_rpc_cap' from issuing
+ * a remote control request.
+ */
+ if (_exit_handler.exit)
+ epoll.rpc_ep_exited();
+
+ /*
+ * Perform the accounting of the PDs cap quota at core, to remain
+ * consistent with other kernel platforms.
+ */
+ pd.free_rpc_cap(Native_capability());
+
+ epoll.free_rpc_cap(cap);
+}
diff --git a/repos/base-linux/src/lib/syscall/linux_syscalls.h b/repos/base-linux/src/lib/syscall/linux_syscalls.h
index 5b5bafad1..6cac5d359 100644
--- a/repos/base-linux/src/lib/syscall/linux_syscalls.h
+++ b/repos/base-linux/src/lib/syscall/linux_syscalls.h
@@ -1,6 +1,7 @@
/*
* \brief Linux system-call bindings
* \author Norman Feske
+ * \author Stefan Thöni
* \date 2008-10-22
*
* This file is meant to be internally used by the framework. It is not public
@@ -20,6 +21,7 @@
/*
* Copyright (C) 2008-2017 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@@ -36,6 +38,8 @@
#include
#include
#include
+#include
+
/*
* Resolve ambiguity between 'Genode::size_t' and the host's header's 'size_t'.
@@ -51,7 +55,10 @@
#include
#include
#include
+#include
+#include
#include
+#include
#undef size_t
@@ -85,6 +92,12 @@ extern "C" int lx_clone(int (*fn)(void *), void *child_stack,
** General syscalls used by base-linux **
*****************************************/
+
+inline pid_t lx_getpid() { return lx_syscall(SYS_getpid); }
+inline pid_t lx_gettid() { return lx_syscall(SYS_gettid); }
+inline uid_t lx_getuid() { return lx_syscall(SYS_getuid); }
+
+
inline int lx_write(int fd, const void *buf, Genode::size_t count)
{
return lx_syscall(SYS_write, fd, buf, count);
@@ -97,6 +110,12 @@ inline int lx_close(int fd)
}
+inline int lx_dup(int fd)
+{
+ return lx_syscall(SYS_dup, fd);
+}
+
+
inline int lx_dup2(int fd, int to)
{
return lx_syscall(SYS_dup2, fd, to);
@@ -109,6 +128,39 @@ inline int lx_dup2(int fd, int to)
#include
+struct Lx_sd
+{
+ int value;
+
+ bool valid() const { return value >= 0; }
+
+ static Lx_sd invalid() { return Lx_sd{-1}; }
+
+ uint64_t inode() const
+ {
+#ifdef __NR_fstat64
+ struct stat64 statbuf { };
+ (void)lx_syscall(SYS_fstat64, value, &statbuf);
+#else
+ struct stat statbuf { };
+ (void)lx_syscall(SYS_fstat, value, &statbuf);
+#endif /* __NR_fstat64 */
+ return statbuf.st_ino;
+ }
+
+ void print(Genode::Output &out) const
+ {
+ Genode::print(out, "socket=", value);
+
+ if (value >= 0)
+ Genode::print(out, ",inode=", inode());
+ }
+};
+
+
+struct Lx_epoll_sd { int value; };
+
+
#ifdef SYS_socketcall
inline int lx_socketcall(int call, long *args)
@@ -124,26 +176,19 @@ inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
}
-inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags)
+inline int lx_sendmsg(Lx_sd sockfd, const struct msghdr *msg, int flags)
{
- long args[3] = { sockfd, (long)msg, flags };
+ long args[3] = { sockfd.value, (long)msg, flags };
return lx_socketcall(SYS_SENDMSG, args);
}
-inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags)
+inline int lx_recvmsg(Lx_sd sockfd, struct msghdr *msg, int flags)
{
- long args[3] = { sockfd, (long)msg, flags };
+ long args[3] = { sockfd.value, (long)msg, flags };
return lx_socketcall(SYS_RECVMSG, args);
}
-
-inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
-{
- long args[3] = { sockfd, (long)name, (long)namelen };
- return lx_socketcall(SYS_GETPEERNAME, args);
-}
-
#else
inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
@@ -152,21 +197,15 @@ inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
}
-inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags)
+inline int lx_sendmsg(Lx_sd sockfd, const struct msghdr *msg, int flags)
{
- return lx_syscall(SYS_sendmsg, sockfd, msg, flags);
+ return lx_syscall(SYS_sendmsg, sockfd.value, msg, flags);
}
-inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags)
+inline int lx_recvmsg(Lx_sd sockfd, struct msghdr *msg, int flags)
{
- return lx_syscall(SYS_recvmsg, sockfd, msg, flags);
-}
-
-
-inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
-{
- return lx_syscall(SYS_getpeername, sockfd, name, namelen);
+ return lx_syscall(SYS_recvmsg, sockfd.value, msg, flags);
}
/* TODO add missing socket system calls */
@@ -174,6 +213,56 @@ inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
#endif /* SYS_socketcall */
+struct Lx_socketpair
+{
+ Lx_sd local { -1 };
+ Lx_sd remote { -1 };
+
+ Lx_socketpair()
+ {
+ int sd[2];
+ sd[0] = -1; sd[1] = -1;
+
+ int const ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, sd);
+ if (ret < 0) {
+ Genode::raw(lx_getpid(), ":", lx_gettid(), " lx_socketpair failed with ", ret);
+ Genode::sleep_forever();
+ }
+
+ local = Lx_sd { sd[0] };
+ remote = Lx_sd { sd[1] };
+ }
+};
+
+
+inline Lx_epoll_sd lx_epoll_create()
+{
+ int const ret = lx_syscall(SYS_epoll_create, 1);
+ if (ret < 0) {
+ /*
+ * No recovery possible, just leave a diagnostic message and block
+ * forever.
+ */
+ Genode::raw(lx_getpid(), ":", lx_gettid(), " lx_epoll_create failed with ", ret);
+ Genode::sleep_forever();
+ }
+ return Lx_epoll_sd { ret };
+}
+
+
+inline int lx_epoll_ctl(Lx_epoll_sd epoll, int op, Lx_sd fd, epoll_event *event)
+{
+ return lx_syscall(SYS_epoll_ctl, epoll.value, op, fd.value, event);
+}
+
+
+inline int lx_epoll_wait(Lx_epoll_sd epoll, struct epoll_event *events,
+ int maxevents, int timeout)
+{
+ return lx_syscall(SYS_epoll_wait, epoll.value, events, maxevents, timeout);
+}
+
+
/*******************************************
** Functions used by the process library **
*******************************************/
@@ -254,6 +343,7 @@ inline int lx_sigemptyset(sigset_t *set)
extern "C" void lx_restore_rt (void);
#endif
+
/**
* Simplified binding for sigaction system call
*/
@@ -324,11 +414,6 @@ inline int lx_create_thread(void (*entry)(), void *stack, void *arg)
}
-inline pid_t lx_getpid() { return lx_syscall(SYS_getpid); }
-inline pid_t lx_gettid() { return lx_syscall(SYS_gettid); }
-inline uid_t lx_getuid() { return lx_syscall(SYS_getuid); }
-
-
/************************************
** Functions used by lock library **
************************************/
@@ -340,6 +425,7 @@ inline int lx_nanosleep(const struct timespec *req, struct timespec *rem)
return lx_syscall(SYS_nanosleep, req, rem);
}
+
enum {
LX_FUTEX_WAIT = FUTEX_WAIT,
LX_FUTEX_WAKE = FUTEX_WAKE,