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,