From 82e6d7cf52662d93ee45d814afd52ea7cfc3ff32 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 6 Jan 2017 12:12:39 +0100 Subject: [PATCH] noux: API transition This patch removes the dependency of the deprecated Genode API, fixes the coding style, and removes the "random" file system (superseded by the VFS plugin mechanism). Ref #1987 --- repos/ports/include/noux_session/sysio.h | 769 +++++------ repos/ports/src/noux/args.h | 187 +-- repos/ports/src/noux/child.h | 931 +++++++------ repos/ports/src/noux/child_env.h | 268 ++-- repos/ports/src/noux/child_policy.h | 313 ++--- repos/ports/src/noux/cpu_session_component.h | 263 ++-- repos/ports/src/noux/dataspace_registry.h | 331 ++--- repos/ports/src/noux/destruct_dispatcher.h | 48 - repos/ports/src/noux/destruct_queue.h | 126 +- repos/ports/src/noux/dummy_input_io_channel.h | 28 - repos/ports/src/noux/environment.h | 66 +- repos/ports/src/noux/family_member.h | 269 ++-- .../ports/src/noux/file_descriptor_registry.h | 166 +-- repos/ports/src/noux/io_channel.h | 332 ++--- repos/ports/src/noux/io_channel_listener.h | 4 +- repos/ports/src/noux/io_receptor_registry.h | 113 +- repos/ports/src/noux/local_rom_service.h | 13 +- repos/ports/src/noux/main.cc | 1199 ++--------------- repos/ports/src/noux/minimal/target.mk | 3 +- repos/ports/src/noux/net/net.cc | 35 +- repos/ports/src/noux/net/socket_io_channel.h | 844 ++++++------ repos/ports/src/noux/net/target.mk | 8 +- repos/ports/src/noux/parent_execve.h | 17 +- repos/ports/src/noux/pd_session_component.h | 23 +- repos/ports/src/noux/pipe_io_channel.h | 668 +++++---- repos/ports/src/noux/ram_session_component.h | 305 ++--- repos/ports/src/noux/random_file_system.h | 281 ---- repos/ports/src/noux/range_checked_index.h | 45 +- repos/ports/src/noux/region_map_component.h | 21 +- repos/ports/src/noux/rom_session_component.h | 17 +- repos/ports/src/noux/shared_pointer.h | 258 ++-- repos/ports/src/noux/stdio_file_system.h | 111 -- repos/ports/src/noux/syscall.cc | 798 +++++++++++ repos/ports/src/noux/terminal_connection.h | 30 - repos/ports/src/noux/terminal_io_channel.h | 355 +++-- repos/ports/src/noux/timeout_scheduler.h | 102 ++ repos/ports/src/noux/user_info.h | 90 +- repos/ports/src/noux/verbose.h | 48 + repos/ports/src/noux/vfs_io_channel.h | 336 +++-- repos/ports/src/noux/wake_up_notifier.h | 19 +- 40 files changed, 4666 insertions(+), 5174 deletions(-) delete mode 100644 repos/ports/src/noux/destruct_dispatcher.h delete mode 100644 repos/ports/src/noux/dummy_input_io_channel.h delete mode 100644 repos/ports/src/noux/random_file_system.h delete mode 100644 repos/ports/src/noux/stdio_file_system.h create mode 100644 repos/ports/src/noux/syscall.cc delete mode 100644 repos/ports/src/noux/terminal_connection.h create mode 100644 repos/ports/src/noux/timeout_scheduler.h create mode 100644 repos/ports/src/noux/verbose.h diff --git a/repos/ports/include/noux_session/sysio.h b/repos/ports/include/noux_session/sysio.h index 249882955f..3c42ecb286 100644 --- a/repos/ports/include/noux_session/sysio.h +++ b/repos/ports/include/noux_session/sysio.h @@ -30,479 +30,480 @@ namespace Noux { - using namespace Genode; + struct Sysio; +} - struct Sysio + +struct Noux::Sysio +{ + /* signal numbers must match with libc signal numbers */ + enum Signal { + SIG_INT = 2, + SIG_CHLD = 20, + }; + + enum { SIGNAL_QUEUE_SIZE = 32 }; + Ring_buffer pending_signals; + + enum { MAX_PATH_LEN = 512 }; + typedef char Path[MAX_PATH_LEN]; + + enum { CHUNK_SIZE = 11*1024 }; + typedef char Chunk[CHUNK_SIZE]; + + enum { ARGS_MAX_LEN = 5*1024 }; + typedef char Args[ARGS_MAX_LEN]; + + enum { ENV_MAX_LEN = 6*1024 }; + typedef char Env[ENV_MAX_LEN]; + + typedef __SIZE_TYPE__ size_t; + typedef long int ssize_t; + + /** + * Flags of 'mode' argument of open syscall + */ + enum { + OPEN_MODE_RDONLY = 0, + OPEN_MODE_WRONLY = 1, + OPEN_MODE_RDWR = 2, + OPEN_MODE_ACCMODE = 3, + OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */ + }; + + /** + * These values are the same as in the FreeBSD libc + */ + enum { + STAT_MODE_SYMLINK = 0120000, + STAT_MODE_FILE = 0100000, + STAT_MODE_DIRECTORY = 0040000, + STAT_MODE_CHARDEV = 0020000, + STAT_MODE_BLOCKDEV = 0060000, + }; + + /* + * Must be POD (in contrast to the VFS type) because it's used in a union + */ + struct Stat { - /* signal numbers must match with libc signal numbers */ - enum Signal { - SIG_INT = 2, - SIG_CHLD = 20, - }; + Vfs::file_size size; + unsigned mode; + unsigned uid; + unsigned gid; + unsigned long inode; + unsigned long device; - enum { SIGNAL_QUEUE_SIZE = 32 }; - Ring_buffer pending_signals; - - enum { MAX_PATH_LEN = 512 }; - typedef char Path[MAX_PATH_LEN]; - - enum { CHUNK_SIZE = 11*1024 }; - typedef char Chunk[CHUNK_SIZE]; - - enum { ARGS_MAX_LEN = 5*1024 }; - typedef char Args[ARGS_MAX_LEN]; - - enum { ENV_MAX_LEN = 6*1024 }; - typedef char Env[ENV_MAX_LEN]; - - typedef __SIZE_TYPE__ size_t; - typedef long int ssize_t; - - /** - * Flags of 'mode' argument of open syscall - */ - enum { - OPEN_MODE_RDONLY = 0, - OPEN_MODE_WRONLY = 1, - OPEN_MODE_RDWR = 2, - OPEN_MODE_ACCMODE = 3, - OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */ - }; - - /** - * These values are the same as in the FreeBSD libc - */ - enum { - STAT_MODE_SYMLINK = 0120000, - STAT_MODE_FILE = 0100000, - STAT_MODE_DIRECTORY = 0040000, - STAT_MODE_CHARDEV = 0020000, - STAT_MODE_BLOCKDEV = 0060000, - }; - - /* - * Must be POD (in contrast to the VFS type) because it's used in a union - */ - struct Stat + Stat & operator= (Vfs::Directory_service::Stat const &stat) { - Vfs::file_size size; - unsigned mode; - unsigned uid; - unsigned gid; - unsigned long inode; - unsigned long device; + size = stat.size; + mode = stat.mode; + uid = stat.uid; + gid = stat.gid; + inode = stat.inode; + device = stat.device; - Stat & operator= (Vfs::Directory_service::Stat const &stat) - { - size = stat.size; - mode = stat.mode; - uid = stat.uid; - gid = stat.gid; - inode = stat.inode; - device = stat.device; + return *this; + } + }; - return *this; - } - }; + /** + * Argument structure used for ioctl syscall + */ + struct Ioctl_in + { + typedef Vfs::File_io_service::Ioctl_opcode Opcode; - /** - * Argument structure used for ioctl syscall - */ - struct Ioctl_in + typedef Vfs::File_io_service::Ioctl_value Value; + + Opcode request; + int argp; + }; + + /** + * Structure carrying the result values of 'ioctl' syscalls + */ + typedef Vfs::File_io_service::Ioctl_out Ioctl_out; + + enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END }; + + enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::DIRENT_MAX_NAME_LEN }; + + typedef Vfs::Directory_service::Dirent_type Dirent_type; + + /* + * Must be POD (in contrast to the VFS type) because it's used in a union + */ + struct Dirent + { + unsigned long fileno; + Dirent_type type; + char name[DIRENT_MAX_NAME_LEN]; + + Dirent & operator= (Vfs::Directory_service::Dirent const &dirent) { - typedef Vfs::File_io_service::Ioctl_opcode Opcode; + fileno = dirent.fileno; + type = dirent.type; + memcpy(name, dirent.name, DIRENT_MAX_NAME_LEN); - typedef Vfs::File_io_service::Ioctl_value Value; + return *this; + } + }; - Opcode request; - int argp; - }; + enum Fcntl_cmd { + FCNTL_CMD_GET_FILE_STATUS_FLAGS, + FCNTL_CMD_SET_FILE_STATUS_FLAGS, + FCNTL_CMD_SET_FD_FLAGS + }; + + /** + * Input and output argument type of select syscall + */ + struct Select_fds + { + /** + * Maximum number of file descriptors supported + */ + enum { MAX_FDS = 32U }; /** - * Structure carrying the result values of 'ioctl' syscalls + * Number of file descriptors to watch for read operations (rd), + * write operations (wr), or exceptions (ex). */ - typedef Vfs::File_io_service::Ioctl_out Ioctl_out; + size_t num_rd, + num_wr, + num_ex; - enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END }; - - enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::DIRENT_MAX_NAME_LEN }; - - typedef Vfs::Directory_service::Dirent_type Dirent_type; - - /* - * Must be POD (in contrast to the VFS type) because it's used in a union + /** + * Array containing the file descriptors, starting with those + * referring to rd, followed by wr, and finally ex */ - struct Dirent + int array[MAX_FDS]; + + /** + * Return total number of file descriptors contained in the array + */ + size_t total_fds() const { + return min(num_rd + num_wr + num_ex, (size_t)MAX_FDS); } + + /** + * Check for maximum population of fds array + */ + bool max_fds_exceeded() const { - unsigned long fileno; - Dirent_type type; - char name[DIRENT_MAX_NAME_LEN]; - - Dirent & operator= (Vfs::Directory_service::Dirent const &dirent) - { - fileno = dirent.fileno; - type = dirent.type; - memcpy(name, dirent.name, DIRENT_MAX_NAME_LEN); - - return *this; - } - }; - - enum Fcntl_cmd { - FCNTL_CMD_GET_FILE_STATUS_FLAGS, - FCNTL_CMD_SET_FILE_STATUS_FLAGS, - FCNTL_CMD_SET_FD_FLAGS - }; + /* + * Note that even though the corner case of num_rd + num_wr + + * num_ex == MAX_FDS is technically valid, this condition hints + * at a possible attempt to over popupate the array (see the + * implementation of 'select' in the Noux libc plugin). Hence, + * we regard this case as an error, too. + */ + return total_fds() >= MAX_FDS; + } /** - * Input and output argument type of select syscall + * Return true of fd set index should be watched for reading */ - struct Select_fds - { - /** - * Maximum number of file descriptors supported - */ - enum { MAX_FDS = 32U }; - - /** - * Number of file descriptors to watch for read operations (rd), - * write operations (wr), or exceptions (ex). - */ - size_t num_rd, - num_wr, - num_ex; - - /** - * Array containing the file descriptors, starting with those - * referring to rd, followed by wr, and finally ex - */ - int array[MAX_FDS]; - - /** - * Return total number of file descriptors contained in the array - */ - size_t total_fds() const { - return min(num_rd + num_wr + num_ex, (size_t)MAX_FDS); } - - /** - * Check for maximum population of fds array - */ - bool max_fds_exceeded() const - { - /* - * Note that even though the corner case of num_rd + num_wr + - * num_ex == MAX_FDS is technically valid, this condition hints - * at a possible attempt to over popupate the array (see the - * implementation of 'select' in the Noux libc plugin). Hence, - * we regard this case as an error, too. - */ - return total_fds() >= MAX_FDS; - } - - /** - * Return true of fd set index should be watched for reading - */ - bool watch_for_rd(unsigned i) const { return i < num_rd; } - - /** - * Return true if fd set index should be watched for writing - */ - bool watch_for_wr(unsigned i) const { - return (i >= num_rd) && (i < num_rd + num_wr); } - - /** - * Return true if fd set index should be watched for exceptions - */ - bool watch_for_ex(unsigned i) const { - return (i >= num_rd + num_wr) && (i < total_fds()); } - }; - - struct Select_timeout - { - long sec, usec; - - /** - * Set timeout to infinity - */ - void set_infinite() { sec = -1; usec = -1; } - - /** - * Return true if the timeout is infinite - */ - bool infinite() const { return (sec == -1) && (usec == -1); } - - /** - * Return true if the timeout is zero - */ - bool zero() const { return (sec == 0) && (usec == 0); } - }; + bool watch_for_rd(unsigned i) const { return i < num_rd; } /** - * Socket related structures + * Return true if fd set index should be watched for writing */ - enum { MAX_HOSTNAME_LEN = 255 }; - typedef char Hostname[MAX_HOSTNAME_LEN]; - - enum { MAX_SERVNAME_LEN = 255 }; - typedef char Servname[MAX_SERVNAME_LEN]; - - enum { MAX_ADDRINFO_RESULTS = 4 }; - - struct in_addr - { - unsigned int s_addr; - }; - - struct sockaddr - { - unsigned char sa_len; - unsigned char sa_family; - char sa_data[14]; - }; - - struct sockaddr_in { - unsigned char sin_len; - unsigned char sin_family; - unsigned short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; - }; - - typedef unsigned socklen_t; - - struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; - struct addrinfo *ai_next; - }; - - struct Addrinfo { - struct addrinfo addrinfo; - struct sockaddr ai_addr; - char ai_canonname[255]; - }; + bool watch_for_wr(unsigned i) const { + return (i >= num_rd) && (i < num_rd + num_wr); } /** - * user info defintions + * Return true if fd set index should be watched for exceptions */ - enum { USERINFO_GET_ALL = 0, USERINFO_GET_UID, USERINFO_GET_GID }; - enum { MAX_USERNAME_LEN = 32 }; - typedef char User[MAX_USERNAME_LEN]; - enum { MAX_SHELL_LEN = 16 }; - typedef char Shell[MAX_SHELL_LEN]; - enum { MAX_HOME_LEN = 128 }; - typedef char Home[MAX_HOME_LEN]; - typedef unsigned int Uid; + bool watch_for_ex(unsigned i) const { + return (i >= num_rd + num_wr) && (i < total_fds()); } + }; + + struct Select_timeout + { + long sec, usec; /** - * time/clock definitions + * Set timeout to infinity */ - enum Clock_Id { CLOCK_ID_SECOND }; - - enum Fcntl_error { FCNTL_ERR_CMD_INVALID = Vfs::Directory_service::NUM_GENERAL_ERRORS }; - enum Execve_error { EXECVE_NONEXISTENT = Vfs::Directory_service::NUM_GENERAL_ERRORS, EXECVE_NOMEM }; - enum Fork_error { FORK_NOMEM = Vfs::Directory_service::NUM_GENERAL_ERRORS }; - enum Select_error { SELECT_ERR_INTERRUPT }; + void set_infinite() { sec = -1; usec = -1; } /** - * Socket related errors + * Return true if the timeout is infinite */ - enum Accept_error { ACCEPT_ERR_AGAIN, ACCEPT_ERR_WOULD_BLOCK, - ACCEPT_ERR_INVALID, ACCEPT_ERR_NO_MEMORY, - ACCEPT_ERR_NOT_SUPPORTED }; + bool infinite() const { return (sec == -1) && (usec == -1); } - enum Bind_error { BIND_ERR_ACCESS, BIND_ERR_ADDR_IN_USE, - BIND_ERR_INVALID, BIND_ERR_NO_MEMORY }; + /** + * Return true if the timeout is zero + */ + bool zero() const { return (sec == 0) && (usec == 0); } + }; - enum Connect_error { CONNECT_ERR_ACCESS, CONNECT_ERR_AGAIN, - CONNECT_ERR_ALREADY, CONNECT_ERR_CONN_REFUSED, - CONNECT_ERR_NO_PERM, CONNECT_ERR_ADDR_IN_USE, - CONNECT_ERR_IN_PROGRESS, CONNECT_ERR_IS_CONNECTED, - CONNECT_ERR_RESET, CONNECT_ERR_ABORTED, - CONNECT_ERR_NO_ROUTE }; + /** + * Socket related structures + */ + enum { MAX_HOSTNAME_LEN = 255 }; + typedef char Hostname[MAX_HOSTNAME_LEN]; - enum Listen_error { LISTEN_ERR_ADDR_IN_USE, LISTEN_ERR_NOT_SUPPORTED }; + enum { MAX_SERVNAME_LEN = 255 }; + typedef char Servname[MAX_SERVNAME_LEN]; - enum Recv_error { RECV_ERR_AGAIN, RECV_ERR_WOULD_BLOCK, - RECV_ERR_CONN_REFUSED, RECV_ERR_INVALID, - RECV_ERR_NOT_CONNECTED, RECV_ERR_NO_MEMORY }; + enum { MAX_ADDRINFO_RESULTS = 4 }; - enum Send_error { SEND_ERR_AGAIN, SEND_ERR_WOULD_BLOCK, - SEND_ERR_CONNECTION_RESET, SEND_ERR_INVALID, - SEND_ERR_IS_CONNECTED, SEND_ERR_NO_MEMORY }; + struct in_addr + { + unsigned int s_addr; + }; - enum Shutdown_error { SHUTDOWN_ERR_NOT_CONNECTED }; + struct sockaddr + { + unsigned char sa_len; + unsigned char sa_family; + char sa_data[14]; + }; - enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT, - SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY }; + struct sockaddr_in { + unsigned char sin_len; + unsigned char sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; + }; - enum Clock_error { CLOCK_ERR_INVALID, CLOCK_ERR_FAULT, CLOCK_ERR_NO_PERM }; + typedef unsigned socklen_t; - enum Utimes_error { UTIMES_ERR_ACCESS, UTIMES_ERR_FAUL, UTIMES_ERR_EIO, - UTIMES_ERR_NAME_TOO_LONG, UTIMES_ERR_NO_ENTRY, - UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM, - UTIMES_ERR_READ_ONLY }; + struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; + }; - enum Wait4_error { WAIT4_ERR_INTERRUPT }; + struct Addrinfo { + struct addrinfo addrinfo; + struct sockaddr ai_addr; + char ai_canonname[255]; + }; - enum Kill_error { KILL_ERR_SRCH }; + /** + * user info defintions + */ + enum { USERINFO_GET_ALL = 0, USERINFO_GET_UID, USERINFO_GET_GID }; + enum { MAX_USERNAME_LEN = 32 }; + typedef char User[MAX_USERNAME_LEN]; + enum { MAX_SHELL_LEN = 16 }; + typedef char Shell[MAX_SHELL_LEN]; + enum { MAX_HOME_LEN = 128 }; + typedef char Home[MAX_HOME_LEN]; + typedef unsigned int Uid; - union { - Vfs::Directory_service::General_error general; - Vfs::Directory_service::Stat_result stat; - Vfs::File_io_service::Ftruncate_result ftruncate; - Vfs::Directory_service::Open_result open; - Vfs::Directory_service::Unlink_result unlink; - Vfs::Directory_service::Readlink_result readlink; - Vfs::Directory_service::Rename_result rename; - Vfs::Directory_service::Mkdir_result mkdir; - Vfs::Directory_service::Symlink_result symlink; - Vfs::File_io_service::Read_result read; - Vfs::File_io_service::Write_result write; - Vfs::File_io_service::Ioctl_result ioctl; + /** + * time/clock definitions + */ + enum Clock_Id { CLOCK_ID_SECOND }; - Fcntl_error fcntl; - Execve_error execve; - Select_error select; - Accept_error accept; - Bind_error bind; - Connect_error connect; - Listen_error listen; - Recv_error recv; - Send_error send; - Shutdown_error shutdown; - Socket_error socket; - Clock_error clock; - Utimes_error utimes; - Wait4_error wait4; - Kill_error kill; - Fork_error fork; + enum Fcntl_error { FCNTL_ERR_CMD_INVALID = Vfs::Directory_service::NUM_GENERAL_ERRORS }; + enum Execve_error { EXECVE_NONEXISTENT = Vfs::Directory_service::NUM_GENERAL_ERRORS, EXECVE_NOMEM }; + enum Fork_error { FORK_NOMEM = Vfs::Directory_service::NUM_GENERAL_ERRORS }; + enum Select_error { SELECT_ERR_INTERRUPT }; - } error; + /** + * Socket related errors + */ + enum Accept_error { ACCEPT_ERR_AGAIN, ACCEPT_ERR_WOULD_BLOCK, + ACCEPT_ERR_INVALID, ACCEPT_ERR_NO_MEMORY, + ACCEPT_ERR_NOT_SUPPORTED }; - union { + enum Bind_error { BIND_ERR_ACCESS, BIND_ERR_ADDR_IN_USE, + BIND_ERR_INVALID, BIND_ERR_NO_MEMORY }; - SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; }, - { size_t count; }); + enum Connect_error { CONNECT_ERR_ACCESS, CONNECT_ERR_AGAIN, + CONNECT_ERR_ALREADY, CONNECT_ERR_CONN_REFUSED, + CONNECT_ERR_NO_PERM, CONNECT_ERR_ADDR_IN_USE, + CONNECT_ERR_IN_PROGRESS, CONNECT_ERR_IS_CONNECTED, + CONNECT_ERR_RESET, CONNECT_ERR_ABORTED, + CONNECT_ERR_NO_ROUTE }; - SYSIO_DECL(stat, { Path path; }, { Stat st; }); + enum Listen_error { LISTEN_ERR_ADDR_IN_USE, LISTEN_ERR_NOT_SUPPORTED }; - SYSIO_DECL(symlink, { Path oldpath; Path newpath; }, { }); + enum Recv_error { RECV_ERR_AGAIN, RECV_ERR_WOULD_BLOCK, + RECV_ERR_CONN_REFUSED, RECV_ERR_INVALID, + RECV_ERR_NOT_CONNECTED, RECV_ERR_NO_MEMORY }; - SYSIO_DECL(fstat, { int fd; }, { Stat st; }); + enum Send_error { SEND_ERR_AGAIN, SEND_ERR_WOULD_BLOCK, + SEND_ERR_CONNECTION_RESET, SEND_ERR_INVALID, + SEND_ERR_IS_CONNECTED, SEND_ERR_NO_MEMORY }; - SYSIO_DECL(ftruncate, { int fd; off_t length; }, { }); + enum Shutdown_error { SHUTDOWN_ERR_NOT_CONNECTED }; - SYSIO_DECL(fcntl, { int fd; long long_arg; Fcntl_cmd cmd; }, - { int result; }); + enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT, + SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY }; - SYSIO_DECL(open, { Path path; int mode; }, { int fd; }); + enum Clock_error { CLOCK_ERR_INVALID, CLOCK_ERR_FAULT, CLOCK_ERR_NO_PERM }; - SYSIO_DECL(close, { int fd; }, { }); + enum Utimes_error { UTIMES_ERR_ACCESS, UTIMES_ERR_FAUL, UTIMES_ERR_EIO, + UTIMES_ERR_NAME_TOO_LONG, UTIMES_ERR_NO_ENTRY, + UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM, + UTIMES_ERR_READ_ONLY }; - SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { }); + enum Wait4_error { WAIT4_ERR_INTERRUPT }; - SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; }, - { off_t offset; }); + enum Kill_error { KILL_ERR_SRCH }; - SYSIO_DECL(dirent, { int fd; }, { Dirent entry; }); + union { + Vfs::Directory_service::General_error general; + Vfs::Directory_service::Stat_result stat; + Vfs::File_io_service::Ftruncate_result ftruncate; + Vfs::Directory_service::Open_result open; + Vfs::Directory_service::Unlink_result unlink; + Vfs::Directory_service::Readlink_result readlink; + Vfs::Directory_service::Rename_result rename; + Vfs::Directory_service::Mkdir_result mkdir; + Vfs::Directory_service::Symlink_result symlink; + Vfs::File_io_service::Read_result read; + Vfs::File_io_service::Write_result write; + Vfs::File_io_service::Ioctl_result ioctl; - SYSIO_DECL(read, { int fd; size_t count; }, - { Chunk chunk; size_t count; }); + Fcntl_error fcntl; + Execve_error execve; + Select_error select; + Accept_error accept; + Bind_error bind; + Connect_error connect; + Listen_error listen; + Recv_error recv; + Send_error send; + Shutdown_error shutdown; + Socket_error socket; + Clock_error clock; + Utimes_error utimes; + Wait4_error wait4; + Kill_error kill; + Fork_error fork; - SYSIO_DECL(readlink, { Path path; size_t bufsiz; }, - { Chunk chunk; size_t count; }); + } error; - SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { }); + union { - SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; }, - { Select_fds fds; }); + SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; }, + { size_t count; }); - SYSIO_DECL(fork, { addr_t ip; addr_t sp; - addr_t parent_cap_addr; }, - { int pid; }); + SYSIO_DECL(stat, { Path path; }, { Stat st; }); - SYSIO_DECL(getpid, { }, { int pid; }); + SYSIO_DECL(symlink, { Path oldpath; Path newpath; }, { }); - SYSIO_DECL(wait4, { int pid; bool nohang; }, - { int pid; int status; }); - SYSIO_DECL(pipe, { }, { int fd[2]; }); + SYSIO_DECL(fstat, { int fd; }, { Stat st; }); - SYSIO_DECL(dup2, { int fd; int to_fd; }, { int fd; }); + SYSIO_DECL(ftruncate, { int fd; off_t length; }, { }); - SYSIO_DECL(unlink, { Path path; }, { }); + SYSIO_DECL(fcntl, { int fd; long long_arg; Fcntl_cmd cmd; }, + { int result; }); - SYSIO_DECL(rename, { Path from_path; Path to_path; }, { }); + SYSIO_DECL(open, { Path path; int mode; }, { int fd; }); - SYSIO_DECL(mkdir, { Path path; int mode; }, { }); + SYSIO_DECL(close, { int fd; }, { }); - SYSIO_DECL(socket, { int domain; int type; int protocol; }, - { int fd; }); + SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { }); - /* XXX for now abuse Chunk for passing optval */ - SYSIO_DECL(getsockopt, { int fd; int level; int optname; Chunk optval; - socklen_t optlen; }, { int result; }); + SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; }, + { off_t offset; }); - SYSIO_DECL(setsockopt, { int fd; int level; - int optname; Chunk optval; - socklen_t optlen; }, { }); + SYSIO_DECL(dirent, { int fd; }, { Dirent entry; }); - SYSIO_DECL(accept, { int fd; struct sockaddr addr; socklen_t addrlen; }, - { int fd; }); + SYSIO_DECL(read, { int fd; size_t count; }, + { Chunk chunk; size_t count; }); - SYSIO_DECL(bind, { int fd; struct sockaddr addr; - socklen_t addrlen; }, { int result; }); + SYSIO_DECL(readlink, { Path path; size_t bufsiz; }, + { Chunk chunk; size_t count; }); - SYSIO_DECL(getpeername, { int fd; struct sockaddr addr; - socklen_t addrlen; }, { }); + SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { }); - SYSIO_DECL(listen, { int fd; int type; int backlog; }, - { int result; }); + SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; }, + { Select_fds fds; }); - SYSIO_DECL(send, { int fd; Chunk buf; size_t len; int flags; }, - { ssize_t len; }); + SYSIO_DECL(fork, { addr_t ip; addr_t sp; + addr_t parent_cap_addr; }, + { int pid; }); - SYSIO_DECL(sendto, { int fd; Chunk buf; size_t len; int flags; - struct sockaddr dest_addr; socklen_t addrlen; }, - { ssize_t len; }); + SYSIO_DECL(getpid, { }, { int pid; }); - SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; }, - { size_t len; }); + SYSIO_DECL(wait4, { int pid; bool nohang; }, + { int pid; int status; }); + SYSIO_DECL(pipe, { }, { int fd[2]; }); - SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags; - struct sockaddr src_addr; socklen_t addrlen; }, - { size_t len; }); + SYSIO_DECL(dup2, { int fd; int to_fd; }, { int fd; }); - SYSIO_DECL(shutdown, { int fd; int how; }, { }); + SYSIO_DECL(unlink, { Path path; }, { }); - SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; }, - { int result; }); + SYSIO_DECL(rename, { Path from_path; Path to_path; }, { }); - SYSIO_DECL(userinfo, { int request; Uid uid; }, - { User name; Uid uid; Uid gid; Shell shell; - Home home; }); + SYSIO_DECL(mkdir, { Path path; int mode; }, { }); - SYSIO_DECL(gettimeofday, { }, { unsigned long sec; unsigned int usec; }); + SYSIO_DECL(socket, { int domain; int type; int protocol; }, + { int fd; }); - SYSIO_DECL(clock_gettime, { Clock_Id clock_id; }, - { unsigned long sec; unsigned long nsec; }); + /* XXX for now abuse Chunk for passing optval */ + SYSIO_DECL(getsockopt, { int fd; int level; int optname; Chunk optval; + socklen_t optlen; }, { int result; }); - SYSIO_DECL(utimes, { Path path; unsigned long sec; unsigned long usec; }, - { }); + SYSIO_DECL(setsockopt, { int fd; int level; + int optname; Chunk optval; + socklen_t optlen; }, { }); - SYSIO_DECL(sync, { }, { }); + SYSIO_DECL(accept, { int fd; struct sockaddr addr; socklen_t addrlen; }, + { int fd; }); - SYSIO_DECL(kill, { int pid; Signal sig; }, { }); + SYSIO_DECL(bind, { int fd; struct sockaddr addr; + socklen_t addrlen; }, { int result; }); - SYSIO_DECL(getdtablesize, { }, { int n; }); - }; + SYSIO_DECL(getpeername, { int fd; struct sockaddr addr; + socklen_t addrlen; }, { }); + + SYSIO_DECL(listen, { int fd; int type; int backlog; }, + { int result; }); + + SYSIO_DECL(send, { int fd; Chunk buf; size_t len; int flags; }, + { ssize_t len; }); + + SYSIO_DECL(sendto, { int fd; Chunk buf; size_t len; int flags; + struct sockaddr dest_addr; socklen_t addrlen; }, + { ssize_t len; }); + + SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; }, + { size_t len; }); + + SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags; + struct sockaddr src_addr; socklen_t addrlen; }, + { size_t len; }); + + SYSIO_DECL(shutdown, { int fd; int how; }, { }); + + SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; }, + { int result; }); + + SYSIO_DECL(userinfo, { int request; Uid uid; }, + { User name; Uid uid; Uid gid; Shell shell; + Home home; }); + + SYSIO_DECL(gettimeofday, { }, { unsigned long sec; unsigned int usec; }); + + SYSIO_DECL(clock_gettime, { Clock_Id clock_id; }, + { unsigned long sec; unsigned long nsec; }); + + SYSIO_DECL(utimes, { Path path; unsigned long sec; unsigned long usec; }, + { }); + + SYSIO_DECL(sync, { }, { }); + + SYSIO_DECL(kill, { int pid; Signal sig; }, { }); + + SYSIO_DECL(getdtablesize, { }, { int n; }); }; }; diff --git a/repos/ports/src/noux/args.h b/repos/ports/src/noux/args.h index bf87b64cf6..203eaf4743 100644 --- a/repos/ports/src/noux/args.h +++ b/repos/ports/src/noux/args.h @@ -15,102 +15,105 @@ #define _NOUX__ARGS_H_ /* Genode includes */ -#include +#include #include #include namespace Noux { - - class Args - { - protected: - - char * const _buf; - size_t const _buf_size; - size_t _len; - - size_t _free_size() const - { - /* - * Keep space for two trailing zeros, indicating the end of the - * stream of strings. - */ - return _buf_size - _len - 2; - } - - public: - - class Overrun { }; - - /** - * Constructor - * - * \param buf argument buffer - * \param buf_size size of argument buffer in character, - * must be at least 2 - */ - Args(char *buf, size_t buf_size) - : _buf(buf), _buf_size(buf_size), _len(0) - { - if (buf_size <= 2) - throw Overrun(); - - /* search end of string stream (two subsequent zeros) */ - for (; (_buf[_len] || _buf[_len + 1]) && (_len < _buf_size - 2); _len++); - - /* ensure termination of argument buffer */ - _buf[_buf_size - 1] = 0; - _buf[_buf_size - 2] = 0; - } - - Args() : _buf(0), _buf_size(0), _len(0) { } - - bool valid() const { return _buf_size > 0; } - - size_t len() const { return _len; } - - char const * const base() const { return _buf; } - - void append(char const *arg) - { - size_t const arg_len = strlen(arg); - - if (arg_len > _free_size()) - throw Overrun(); - - strncpy(_buf + _len, arg, _buf_size - _len); - - _len += arg_len + 1; /* keep null termination between strings */ - - /* mark end of stream of strings */ - _buf[_len] = 0; - } - - void dump() - { - for (unsigned i = 0, j = 0; _buf[i] && (i < _buf_size - 2); - i += strlen(&_buf[i]) + 1, j++) - log("arg(", j, "): \"", Cstring(&_buf[i]), "\""); - } - }; - - class Args_dataspace : private Attached_ram_dataspace, public Args - { - public: - - Args_dataspace(size_t size, Args const &from = Args()) - : - Attached_ram_dataspace(env()->ram_session(), size), - Args(local_addr(), size) - { - if (from.len() > size - 2) - throw Overrun(); - - memcpy(_buf, from.base(), from.len() + 1); - } - - using Attached_ram_dataspace::cap; - }; + class Args; + class Args_dataspace; } + +class Noux::Args +{ + protected: + + char * const _buf; + size_t const _buf_size; + size_t _len; + + size_t _free_size() const + { + /* + * Keep space for two trailing zeros, indicating the end of the + * stream of strings. + */ + return _buf_size - _len - 2; + } + + public: + + class Overrun { }; + + /** + * Constructor + * + * \param buf argument buffer + * \param buf_size size of argument buffer in character, + * must be at least 2 + */ + Args(char *buf, size_t buf_size) + : _buf(buf), _buf_size(buf_size), _len(0) + { + if (buf_size <= 2) + throw Overrun(); + + /* search end of string stream (two subsequent zeros) */ + for (; (_buf[_len] || _buf[_len + 1]) && (_len < _buf_size - 2); _len++); + + /* ensure termination of argument buffer */ + _buf[_buf_size - 1] = 0; + _buf[_buf_size - 2] = 0; + } + + Args() : _buf(0), _buf_size(0), _len(0) { } + + bool valid() const { return _buf_size > 0; } + + size_t len() const { return _len; } + + char const * const base() const { return _buf; } + + void append(char const *arg) + { + size_t const arg_len = strlen(arg); + + if (arg_len > _free_size()) + throw Overrun(); + + strncpy(_buf + _len, arg, _buf_size - _len); + + _len += arg_len + 1; /* keep null termination between strings */ + + /* mark end of stream of strings */ + _buf[_len] = 0; + } + + void dump() + { + for (unsigned i = 0, j = 0; _buf[i] && (i < _buf_size - 2); + i += strlen(&_buf[i]) + 1, j++) + log("arg(", j, "): \"", Cstring(&_buf[i]), "\""); + } +}; + + +struct Noux::Args_dataspace : private Attached_ram_dataspace, Args +{ + Args_dataspace(Ram_session &ram, Region_map &rm, + size_t size, Args const &from = Args()) + : + Attached_ram_dataspace(ram, rm, size), + Args(local_addr(), size) + { + if (from.len() > size - 2) + throw Overrun(); + + memcpy(_buf, from.base(), from.len() + 1); + } + + using Attached_ram_dataspace::cap; +}; + #endif /* _NOUX__ARGS_H_ */ diff --git a/repos/ports/src/noux/child.h b/repos/ports/src/noux/child.h index 2d95217901..4eba9985aa 100644 --- a/repos/ports/src/noux/child.h +++ b/repos/ports/src/noux/child.h @@ -15,16 +15,12 @@ #define _NOUX__CHILD_H_ /* Genode includes */ -#include -#include -#include -#include -#include -#include +#include +#include +#include /* Noux includes */ #include -#include #include #include #include @@ -34,51 +30,17 @@ #include #include #include -#include #include #include #include #include +#include +#include +#include namespace Noux { - /** - * Allocator for process IDs - */ - class Pid_allocator - { - private: - - Lock _lock; - int _num_pids; - - public: - - Pid_allocator() : _num_pids(0) { } - - int alloc() - { - Lock::Guard guard(_lock); - return _num_pids++; - } - }; - - /** - * Return singleton instance of PID allocator - */ - Pid_allocator *pid_allocator(); - - /** - * Return singleton instance of timeout scheduler - */ - class Timeout_scheduler; - Timeout_scheduler *timeout_scheduler(); - - /** - * Return singleton instance of user information - */ - class User_info; - User_info *user_info(); + class Pid_allocator; /** * Return singleton instance of Io_receptor_registry @@ -90,6 +52,7 @@ namespace Noux { */ Genode::Lock &signal_lock(); + class Child_config; class Child; /** @@ -97,491 +60,519 @@ namespace Noux { */ bool init_process(Child *child); void init_process_exited(int); +} - struct Child_config : Attached_ram_dataspace - { - enum { CONFIG_DS_SIZE = 4096 }; - Child_config(Genode::Ram_session &ram) - : Attached_ram_dataspace(&ram, CONFIG_DS_SIZE) +/** + * Allocator for process IDs + */ +class Noux::Pid_allocator +{ + private: + + Lock _lock; + int _num_pids; + + public: + + Pid_allocator() : _num_pids(0) { } + + int alloc() { - Genode::strncpy(local_addr(), - "", - CONFIG_DS_SIZE); - - try { - Attached_rom_dataspace noux_config("config"); - - if (noux_config.xml().attribute_value("ld_verbose", false)) - Genode::strncpy(local_addr(), - "", - CONFIG_DS_SIZE); - } catch (Genode::Rom_connection::Rom_connection_failed) { } + Lock::Guard guard(_lock); + return _num_pids++; } - }; +}; - class Child : public Rpc_object, - public File_descriptor_registry, - public Family_member, - public Destruct_queue::Element, - public Interrupt_handler + +struct Noux::Child_config : Attached_ram_dataspace +{ + enum { CONFIG_DS_SIZE = 4096 }; + + Child_config(Ram_session &ram, Region_map &local_rm, Verbose const &verbose) + : + Attached_ram_dataspace(ram, local_rm, CONFIG_DS_SIZE) { - private: + Xml_generator xml(local_addr(), CONFIG_DS_SIZE, "config", [&] () + { + if (verbose.ld()) + xml.attribute("ld_verbose", "yes"); + }); + } +}; - Child_policy::Name const _name; - Parent_exit *_parent_exit; - Kill_broadcaster &_kill_broadcaster; - Parent_execve &_parent_execve; +class Noux::Child : public Rpc_object, + public File_descriptor_registry, + public Family_member, + public Destruct_queue::Element, + public Interrupt_handler +{ + private: - Signal_receiver &_sig_rec; + Child_policy::Name const _name; - Vfs::Dir_file_system &_root_dir; + Verbose const &_verbose; - Destruct_queue &_destruct_queue; - Destruct_dispatcher _destruct_dispatcher { _destruct_queue, this }; - Signal_context_capability _destruct_context_cap = - _sig_rec.manage(&_destruct_dispatcher); + User_info const &_user_info; - Pd_session &_env_pd_session; /* used for creating 'Rpc_entrypoint' */ + Parent_exit *_parent_exit; + Kill_broadcaster &_kill_broadcaster; + Timeout_scheduler &_timeout_scheduler; + Parent_execve &_parent_execve; + Pid_allocator &_pid_allocator; - /** - * Entrypoint used to serve the RPC interfaces of the - * locally-provided services - */ - enum { STACK_SIZE = 8*1024*sizeof(long) }; - Rpc_entrypoint _ep { &_env_pd_session, STACK_SIZE, "noux_process", false }; + Env &_env; - Ram_session &_ref_ram; - Ram_session_capability const _ref_ram_cap; + Vfs::Dir_file_system &_root_dir; - /** - * Registry of dataspaces owned by the Noux process - */ - Dataspace_registry _ds_registry; + Destruct_queue &_destruct_queue; - /** - * Locally-provided PD service - */ - typedef Local_service Pd_service; - Pd_session_component _pd { _ep, _name, _ds_registry }; - Pd_service::Single_session_factory _pd_factory { _pd }; - Pd_service _pd_service { _pd_factory }; + void _handle_destruct() { _destruct_queue.insert(this); } - /** - * Locally-provided RAM service - */ - typedef Local_service Ram_service; - Ram_session_component _ram { _ep, _ds_registry }; - Ram_service::Single_session_factory _ram_factory { _ram }; - Ram_service _ram_service { _ram_factory }; + Signal_handler _destruct_handler { + _env.ep(), *this, &Child::_handle_destruct }; - /** - * Locally-provided CPU service - */ - typedef Local_service Cpu_service; - Cpu_session_component _cpu { _ep, _name, false, _ds_registry }; - Cpu_service::Single_session_factory _cpu_factory { _cpu }; - Cpu_service _cpu_service { _cpu_factory }; + Allocator &_heap; - /* - * Locally-provided Noux service - */ - Session_capability const _noux_session_cap = - Session_capability(_ep.manage(this)); + /** + * Entrypoint used to serve the RPC interfaces of the + * locally-provided services + */ + enum { STACK_SIZE = 8*1024*sizeof(long) }; + Rpc_entrypoint _ep { &_env.pd(), STACK_SIZE, "noux_process", false }; - typedef Local_service > Noux_service; - Noux_service::Single_session_factory _noux_factory { *this }; - Noux_service _noux_service { _noux_factory }; + Ram_session &_ref_ram; + Ram_session_capability const _ref_ram_cap; - /* - * Locally-provided ROM service - */ - Local_rom_factory _rom_factory { _ep, _root_dir, _ds_registry }; - Local_rom_service _rom_service { _rom_factory }; + /** + * Registry of dataspaces owned by the Noux process + */ + Dataspace_registry _ds_registry { _heap }; - /** - * Command line arguments - */ - Args_dataspace _args; + /** + * Locally-provided PD service + */ + typedef Local_service Pd_service; + Pd_session_component _pd { _heap, _env, _ep, _name, _ds_registry }; + Pd_service::Single_session_factory _pd_factory { _pd }; + Pd_service _pd_service { _pd_factory }; - /** - * Environment variables - */ - Environment _env; + /** + * Locally-provided RAM service + */ + typedef Local_service Ram_service; + Ram_session_component _ram { _ref_ram, _heap, _ep, _ds_registry }; + Ram_service::Single_session_factory _ram_factory { _ram }; + Ram_service _ram_service { _ram_factory }; - /* - * Child configuration - */ - Child_config _config { *env()->ram_session() }; + /** + * Locally-provided CPU service + */ + typedef Local_service Cpu_service; + Cpu_session_component _cpu { _env, _ep, _name, false, _ds_registry }; + Cpu_service::Single_session_factory _cpu_factory { _cpu }; + Cpu_service _cpu_service { _cpu_factory }; - enum { PAGE_SIZE = 4096, PAGE_MASK = ~(PAGE_SIZE - 1) }; - enum { SYSIO_DS_SIZE = PAGE_MASK & (sizeof(Sysio) + PAGE_SIZE - 1) }; + /* + * Locally-provided Noux service + */ + Session_capability const _noux_session_cap = + Session_capability(_ep.manage(this)); - Attached_ram_dataspace _sysio_ds { env()->ram_session(), SYSIO_DS_SIZE }; - Sysio &_sysio = *_sysio_ds.local_addr(); + typedef Local_service > Noux_service; + Noux_service::Single_session_factory _noux_factory { *this }; + Noux_service _noux_service { _noux_factory }; - typedef Ring_buffer - Signal_queue; - Signal_queue _pending_signals; + /* + * Locally-provided ROM service + */ + Local_rom_factory _rom_factory { _heap, _env, _ep, _root_dir, _ds_registry }; + Local_rom_service _rom_service { _rom_factory }; - Parent_services &_parent_services; + /** + * Command line arguments + */ + Args_dataspace _args; - Static_dataspace_info _sysio_ds_info; - Static_dataspace_info _args_ds_info; - Static_dataspace_info _env_ds_info; - Static_dataspace_info _config_ds_info; + /** + * Environment variables + */ + Environment _sysio_env; - Child_policy _child_policy; + /* + * Child configuration + */ + Child_config _config { _ref_ram, _env.rm(), _verbose }; - Genode::Child _child; + enum { PAGE_SIZE = 4096, PAGE_MASK = ~(PAGE_SIZE - 1) }; + enum { SYSIO_DS_SIZE = PAGE_MASK & (sizeof(Sysio) + PAGE_SIZE - 1) }; - /** - * Exception type for failed file-descriptor lookup - */ - class Invalid_fd { }; + Attached_ram_dataspace _sysio_ds { _ref_ram, _env.rm(), SYSIO_DS_SIZE }; + Sysio &_sysio = *_sysio_ds.local_addr(); - Shared_pointer _lookup_channel(int fd) const - { - Shared_pointer channel = io_channel_by_fd(fd); + typedef Ring_buffer + Signal_queue; + Signal_queue _pending_signals; - if (channel) - return channel; + Parent_services &_parent_services; - throw Invalid_fd(); - } + Static_dataspace_info _sysio_ds_info; + Static_dataspace_info _args_ds_info; + Static_dataspace_info _sysio_env_ds_info; + Static_dataspace_info _config_ds_info; - enum { ARGS_DS_SIZE = 4096 }; + Child_policy _child_policy; - /** - * Let specified child inherit our file descriptors - */ - void _assign_io_channels_to(Child *child) - { - for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++) - if (fd_in_use(fd)) - child->add_io_channel(io_channel_by_fd(fd), fd); - } + Genode::Child _child; - /** - * Block until the IO channel is ready for reading or writing or an - * exception occured. - * - * \param io the IO channel - * \param rd check for data available for reading - * \param wr check for readiness for writing - * \param ex check for exceptions - */ - void _block_for_io_channel(Shared_pointer &io, - bool rd, bool wr, bool ex) - { - /* reset the blocker lock to the 'locked' state */ - _blocker.unlock(); + /** + * Exception type for failed file-descriptor lookup + */ + class Invalid_fd { }; + + Shared_pointer _lookup_channel(int fd) const + { + Shared_pointer channel = io_channel_by_fd(fd); + + if (channel) + return channel; + + throw Invalid_fd(); + } + + enum { ARGS_DS_SIZE = 4096 }; + + /** + * Let specified child inherit our file descriptors + */ + void _assign_io_channels_to(Child *child) + { + for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++) + if (fd_in_use(fd)) + child->add_io_channel(io_channel_by_fd(fd), fd); + } + + /** + * Block until the IO channel is ready for reading or writing or an + * exception occured. + * + * \param io the IO channel + * \param rd check for data available for reading + * \param wr check for readiness for writing + * \param ex check for exceptions + */ + void _block_for_io_channel(Shared_pointer &io, + bool rd, bool wr, bool ex) + { + /* reset the blocker lock to the 'locked' state */ + _blocker.unlock(); + _blocker.lock(); + + Wake_up_notifier notifier(&_blocker); + io->register_wake_up_notifier(¬ifier); + + for (;;) { + if (io->check_unblock(rd, wr, ex) || + !_pending_signals.empty()) + break; + + /* block (unless the lock got unlocked in the meantime) */ _blocker.lock(); - - Wake_up_notifier notifier(&_blocker); - io->register_wake_up_notifier(¬ifier); - - for (;;) { - if (io->check_unblock(rd, wr, ex) || - !_pending_signals.empty()) - break; - - /* block (unless the lock got unlocked in the meantime) */ - _blocker.lock(); - } - - io->unregister_wake_up_notifier(¬ifier); } - /** - * Method for handling noux network related system calls + io->unregister_wake_up_notifier(¬ifier); + } + + /** + * Method for handling noux network related system calls + */ + bool _syscall_net(Syscall sc); + + void _destruct() + { + _ep.dissolve(this); + + if (init_process(this)) + init_process_exited(_child_policy.exit_value()); + } + + public: + + struct Binary_does_not_exist : Exception { }; + struct Insufficient_memory : Exception { }; + + /** + * Constructor + * + * \param forked false if the child is spawned directly from + * an executable binary (i.e., the init process, + * or children created via execve, or + * true if the child is a fork from another child + * + * \throw Binary_does_not_exist if child is not a fork and the + * specified name could not be + * looked up at the virtual file + * system + * \throw Insufficent_memory if the child could not be started by + * the parent + */ + Child(Child_policy::Name const &name, + Verbose const &verbose, + User_info const &user_info, + Parent_exit *parent_exit, + Kill_broadcaster &kill_broadcaster, + Timeout_scheduler &timeout_scheduler, + Parent_execve &parent_execve, + Pid_allocator &pid_allocator, + int pid, + Env &env, + Vfs::Dir_file_system &root_dir, + Args const &args, + Sysio::Env const &sysio_env, + Allocator &heap, + Ram_session &ref_ram, + Ram_session_capability ref_ram_cap, + Parent_services &parent_services, + bool forked, + Destruct_queue &destruct_queue) + : + Family_member(pid), + Destruct_queue::Element(heap), + _name(name), + _verbose(verbose), + _user_info(user_info), + _parent_exit(parent_exit), + _kill_broadcaster(kill_broadcaster), + _timeout_scheduler(timeout_scheduler), + _parent_execve(parent_execve), + _pid_allocator(pid_allocator), + _env(env), + _root_dir(root_dir), + _destruct_queue(destruct_queue), + _heap(heap), + _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), + _args(ref_ram, _env.rm(), ARGS_DS_SIZE, args), + _sysio_env(_ref_ram, _env.rm(), sysio_env), + _parent_services(parent_services), + _sysio_ds_info(_ds_registry, _sysio_ds.cap()), + _args_ds_info(_ds_registry, _args.cap()), + _sysio_env_ds_info(_ds_registry, _sysio_env.cap()), + _config_ds_info(_ds_registry, _config.cap()), + _child_policy(name, + forked ? Rom_session_component::forked_magic_binary_name() + : name, + _args.cap(), _sysio_env.cap(), _config.cap(), + _ep, _pd_service, _ram_service, _cpu_service, + _noux_service, _rom_service, _parent_services, + *this, parent_exit, *this, _destruct_handler, + ref_ram, ref_ram_cap, _verbose.enabled()), + _child(_env.rm(), _ep, _child_policy) + { + if (_verbose.enabled()) + _args.dump(); + + if (!_child.main_thread_cap().valid()) { + _destruct(); + throw Insufficient_memory(); + } + } + + ~Child() { _destruct(); } + + void start() { _ep.activate(); } + + void start_forked_main_thread(addr_t ip, addr_t sp, addr_t parent_cap_addr) + { + /* poke parent_cap_addr into child's address space */ + Capability::Raw const raw = _child.parent_cap().raw(); + + _pd.poke(_env.rm(), parent_cap_addr, (char *)&raw, sizeof(raw)); + + /* start execution of new main thread at supplied trampoline */ + _cpu.start_main_thread(ip, sp); + } + + void submit_exit_signal() + { + if (init_process(this)) { + log("init process exited"); + + /* trigger exit of main event loop */ + init_process_exited(_child_policy.exit_value()); + } else { + Signal_transmitter(_destruct_handler).submit(); + } + } + + Ram_session_component &ram() { return _ram; } + Pd_session_component &pd() { return _pd; } + + Dataspace_registry &ds_registry() { return _ds_registry; } + + + /**************************** + ** Noux session interface ** + ****************************/ + + Dataspace_capability sysio_dataspace() + { + return _sysio_ds.cap(); + } + + Capability lookup_region_map(addr_t const addr) + { + return _pd.lookup_region_map(addr); + } + + bool syscall(Syscall sc); + + int next_open_fd(int start_fd) + { + if (start_fd >= 0) + for (int fd = start_fd; fd < MAX_FILE_DESCRIPTORS; fd++) + if (fd_in_use(fd)) + return fd; + return -1; + } + + + /**************************************** + ** File_descriptor_registry overrides ** + ****************************************/ + + /** + * Find out if the IO channel associated with 'fd' has more file + * descriptors associated with it + */ + bool _is_the_only_fd_for_io_channel(int fd, + Shared_pointer io_channel) + { + for (int f = 0; f < MAX_FILE_DESCRIPTORS; f++) { + if ((f != fd) && + fd_in_use(f) && + (io_channel_by_fd(f) == io_channel)) + return false; + } + + return true; + } + + int add_io_channel(Shared_pointer io_channel, int fd = -1) + { + fd = File_descriptor_registry::add_io_channel(io_channel, fd); + + /* Register the interrupt handler only once per IO channel */ + if (_is_the_only_fd_for_io_channel(fd, io_channel)) { + Io_channel_listener *l = new (_heap) Io_channel_listener(this); + io_channel->register_interrupt_handler(l); + } + + return fd; + } + + void remove_io_channel(int fd) + { + Shared_pointer io_channel = _lookup_channel(fd); + + /* + * Unregister the interrupt handler only if there are no other + * file descriptors associated with the IO channel. */ - bool _syscall_net(Syscall sc); - - void _destruct() { - - _sig_rec.dissolve(&_destruct_dispatcher); - - _ep.dissolve(this); - - if (init_process(this)) - init_process_exited(_child_policy.exit_value()); + if (_is_the_only_fd_for_io_channel(fd, io_channel)) { + Io_channel_listener *l = io_channel->lookup_io_channel_listener(this); + io_channel->unregister_interrupt_handler(l); + Genode::destroy(_heap, l); } - public: + File_descriptor_registry::remove_io_channel(fd); + } - struct Binary_does_not_exist : Exception { }; - struct Insufficient_memory : Exception { }; - - /** - * Constructor - * - * \param forked false if the child is spawned directly from - * an executable binary (i.e., the init process, - * or children created via execve, or - * true if the child is a fork from another child - * - * \throw Binary_does_not_exist if child is not a fork and the - * specified name could not be - * looked up at the virtual file - * system - * \throw Insufficent_memory if the child could not be started by - * the parent - */ - Child(Child_policy::Name const &name, - Parent_exit *parent_exit, - Kill_broadcaster &kill_broadcaster, - Parent_execve &parent_execve, - int pid, - Signal_receiver &sig_rec, - Vfs::Dir_file_system &root_dir, - Args const &args, - Sysio::Env const &env, - Pd_session &env_pd_session, - Ram_session &ref_ram, - Ram_session_capability ref_ram_cap, - Parent_services &parent_services, - Rpc_entrypoint &resources_ep, - bool forked, - Allocator &destruct_alloc, - Destruct_queue &destruct_queue, - bool verbose) - : - Family_member(pid), - Destruct_queue::Element(&destruct_alloc), - _name(name), - _parent_exit(parent_exit), - _kill_broadcaster(kill_broadcaster), - _parent_execve(parent_execve), - _sig_rec(sig_rec), - _root_dir(root_dir), - _destruct_queue(destruct_queue), - _env_pd_session(env_pd_session), - _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), - _args(ARGS_DS_SIZE, args), - _env(env), - _parent_services(parent_services), - _sysio_ds_info(_ds_registry, _sysio_ds.cap()), - _args_ds_info(_ds_registry, _args.cap()), - _env_ds_info(_ds_registry, _env.cap()), - _config_ds_info(_ds_registry, _config.cap()), - _child_policy(name, - forked ? Rom_session_component::forked_magic_binary_name() - : name, - _args.cap(), _env.cap(), _config.cap(), - _ep, _pd_service, _ram_service, _cpu_service, - _noux_service, _rom_service, _parent_services, - *this, parent_exit, *this, _destruct_context_cap, - ref_ram, ref_ram_cap, verbose), - _child(*Genode::env()->rm_session(), _ep, _child_policy) - { - if (verbose) - _args.dump(); - - if (!_child.main_thread_cap().valid()) { - _destruct(); - throw Insufficient_memory(); - } - } - - ~Child() { _destruct(); } - - void start() { _ep.activate(); } - - void start_forked_main_thread(addr_t ip, addr_t sp, addr_t parent_cap_addr) - { - /* poke parent_cap_addr into child's address space */ - Capability::Raw const raw = _child.parent_cap().raw(); - - _pd.poke(parent_cap_addr, &raw, sizeof(raw)); - - /* start execution of new main thread at supplied trampoline */ - _cpu.start_main_thread(ip, sp); - } - - void submit_exit_signal() - { - if (init_process(this)) { - log("init process exited"); - - /* trigger exit of main event loop */ - init_process_exited(_child_policy.exit_value()); - } else { - Signal_transmitter(_destruct_context_cap).submit(); - } - } - - Ram_session_component &ram() { return _ram; } - Pd_session_component &pd() { return _pd; } - - Dataspace_registry &ds_registry() { return _ds_registry; } - - - /**************************** - ** Noux session interface ** - ****************************/ - - Dataspace_capability sysio_dataspace() - { - return _sysio_ds.cap(); - } - - Capability lookup_region_map(addr_t const addr) - { - return _pd.lookup_region_map(addr); - } - - bool syscall(Syscall sc); - - int next_open_fd(int start_fd) - { - if (start_fd >= 0) - for (int fd = start_fd; fd < MAX_FILE_DESCRIPTORS; fd++) - if (fd_in_use(fd)) - return fd; - return -1; - } - - - /**************************************** - ** File_descriptor_registry overrides ** - ****************************************/ - - /** - * Find out if the IO channel associated with 'fd' has more file - * descriptors associated with it - */ - bool _is_the_only_fd_for_io_channel(int fd, - Shared_pointer io_channel) - { - for (int f = 0; f < MAX_FILE_DESCRIPTORS; f++) { - if ((f != fd) && - fd_in_use(f) && - (io_channel_by_fd(f) == io_channel)) - return false; - } - - return true; - } - - int add_io_channel(Shared_pointer io_channel, int fd = -1) - { - fd = File_descriptor_registry::add_io_channel(io_channel, fd); - - /* Register the interrupt handler only once per IO channel */ - if (_is_the_only_fd_for_io_channel(fd, io_channel)) { - Io_channel_listener *l = new (env()->heap()) Io_channel_listener(this); - io_channel->register_interrupt_handler(l); - } - - return fd; - } - - void remove_io_channel(int fd) - { - Shared_pointer io_channel = _lookup_channel(fd); - - /* - * Unregister the interrupt handler only if there are no other - * file descriptors associated with the IO channel. - */ - if (_is_the_only_fd_for_io_channel(fd, io_channel)) { - Io_channel_listener *l = io_channel->lookup_io_channel_listener(this); - io_channel->unregister_interrupt_handler(l); - Genode::destroy(env()->heap(), l); - } - - File_descriptor_registry::remove_io_channel(fd); - } - - void flush() - { - for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++) - try { - remove_io_channel(fd); - } catch (Invalid_fd) { } - } - - - /***************************** - ** Family_member interface ** - *****************************/ - - void submit_signal(Noux::Sysio::Signal sig) - { + void flush() + { + for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++) try { - _pending_signals.add(sig); - } catch (Signal_queue::Overflow) { - error("signal queue is full - signal dropped"); - } + remove_io_channel(fd); + } catch (Invalid_fd) { } + } - _blocker.unlock(); + + /***************************** + ** Family_member interface ** + *****************************/ + + void submit_signal(Noux::Sysio::Signal sig) + { + try { + _pending_signals.add(sig); + } catch (Signal_queue::Overflow) { + error("signal queue is full - signal dropped"); } - Family_member *do_execve(const char *filename, - Args const &args, - Sysio::Env const &env, - bool verbose) - { - Lock::Guard signal_lock_guard(signal_lock()); + _blocker.unlock(); + } - Child *child = new Child(filename, - _parent_exit, - _kill_broadcaster, - _parent_execve, - pid(), - _sig_rec, - _root_dir, - args, - env, - _env_pd_session, - _ref_ram, _ref_ram_cap, - _parent_services, - _ep, - false, - *Genode::env()->heap(), - _destruct_queue, - verbose); + Family_member *do_execve(const char *filename, + Args const &args, + Sysio::Env const &env) override + { + Lock::Guard signal_lock_guard(signal_lock()); - _assign_io_channels_to(child); + Child *child = new (_heap) Child(filename, + _verbose, + _user_info, + _parent_exit, + _kill_broadcaster, + _timeout_scheduler, + _parent_execve, + _pid_allocator, + pid(), + _env, + _root_dir, + args, + env, + _heap, + _ref_ram, _ref_ram_cap, + _parent_services, + false, + _destruct_queue); - /* move the signal queue */ - while (!_pending_signals.empty()) - child->_pending_signals.add(_pending_signals.get()); + _assign_io_channels_to(child); - /* - * Close all open files. - * - * This action is not part of the child destructor, - * because in the case that a child exits itself, - * it may need to close all files to unblock the - * parent (which might be reading from a pipe) before - * the parent can destroy the child object. - */ - flush(); + /* move the signal queue */ + while (!_pending_signals.empty()) + child->_pending_signals.add(_pending_signals.get()); - /* signal main thread to remove ourself */ - Genode::Signal_transmitter(_destruct_context_cap).submit(); + /* + * Close all open files. + * + * This action is not part of the child destructor, + * because in the case that a child exits itself, + * it may need to close all files to unblock the + * parent (which might be reading from a pipe) before + * the parent can destroy the child object. + */ + flush(); - /* start executing the new process */ - child->start(); + /* signal main thread to remove ourself */ + Signal_transmitter(_destruct_handler).submit(); - /* this child will be removed by the execve_finalization_dispatcher */ + /* start executing the new process */ + child->start(); - return child; - } + /* this child will be removed by the execve_finalization_dispatcher */ - /********************************* - ** Interrupt_handler interface ** - *********************************/ + return child; + } - void handle_interrupt() - { - submit_signal(Sysio::SIG_INT); - } + /********************************* + ** Interrupt_handler interface ** + *********************************/ - }; + void handle_interrupt() + { + submit_signal(Sysio::SIG_INT); + } }; #endif /* _NOUX__CHILD_H_ */ diff --git a/repos/ports/src/noux/child_env.h b/repos/ports/src/noux/child_env.h index ae3e4833c1..973861345c 100644 --- a/repos/ports/src/noux/child_env.h +++ b/repos/ports/src/noux/child_env.h @@ -23,140 +23,142 @@ #include namespace Noux { - + template class Child_env; using namespace Genode; - - /** - * \param ARGS_SIZE size of the argument buffer given - * to the constructor - */ - template - class Child_env - { - private: - - enum { MAX_LEN_INTERPRETER_LINE = 128 }; - - char const *_binary_name; - char _args[ARGS_SIZE + MAX_LEN_INTERPRETER_LINE]; - Sysio::Env _env; - - void _process_env(Sysio::Env env) - { - memcpy(_env, env, sizeof(Sysio::Env)); - } - - /** - * Handle the case that the given binary needs an interpreter - */ - void _process_binary_name_and_args(const char *binary_name, - Dataspace_capability binary_ds, - const char *args) - { - bool interpretable = true; - - const size_t binary_size = Dataspace_client(binary_ds).size(); - - if (binary_size < 4) - interpretable = false; - - const char *binary_addr = 0; - if (interpretable) - try { - binary_addr = Genode::env()->rm_session()->attach(binary_ds); - } catch(...) { - PWRN("could not attach dataspace"); - interpretable = false; - } - - if (interpretable && - ((binary_addr[0] != '#') || (binary_addr[1] != '!'))) - interpretable = false; - - if (!interpretable) { - Genode::env()->rm_session()->detach(binary_addr); - _binary_name = binary_name; - Genode::memcpy(_args, args, ARGS_SIZE); - return; - } - - /* find end of line */ - Range_checked_index - eol(2, min(binary_size, MAX_LEN_INTERPRETER_LINE)); - - try { - while (binary_addr[eol] != '\n') eol++; - } catch (Index_out_of_range) { } - - /* skip leading spaces */ - Range_checked_index - interpreter_line_cursor(2, eol); - - try { - while (binary_addr[interpreter_line_cursor] == ' ') - interpreter_line_cursor++; - } catch (Index_out_of_range) { } - - /* no interpreter name found */ - if (interpreter_line_cursor == eol) - throw Child::Binary_does_not_exist(); - - int interpreter_name_start = interpreter_line_cursor; - - /* find end of interpreter name */ - try { - while (binary_addr[interpreter_line_cursor] != ' ') - interpreter_line_cursor++; - } catch (Index_out_of_range) { } - - size_t interpreter_name_len = - interpreter_line_cursor - interpreter_name_start; - - /* copy interpreter name into argument buffer */ - unsigned int args_buf_cursor = 0; - Genode::strncpy(&_args[args_buf_cursor], - &binary_addr[interpreter_name_start], - interpreter_name_len + 1); - _binary_name = &_args[args_buf_cursor]; - args_buf_cursor += interpreter_name_len + 1; - - /* skip more spaces */ - try { - while (binary_addr[interpreter_line_cursor] == ' ') - interpreter_line_cursor++; - } catch (Index_out_of_range) { } - - /* append interpreter arguments to argument buffer */ - size_t interpreter_args_len = eol - interpreter_line_cursor; - if (interpreter_args_len > 0) { - Genode::strncpy(&_args[args_buf_cursor], - &binary_addr[interpreter_line_cursor], - interpreter_args_len + 1); - args_buf_cursor += interpreter_args_len + 1; - } - - /* append script arguments to argument buffer */ - Genode::memcpy(&_args[args_buf_cursor], - args, ARGS_SIZE); - - Genode::env()->rm_session()->detach(binary_addr); - } - - public: - - Child_env(const char *binary_name, Dataspace_capability binary_ds, - const char *args, Sysio::Env env) - { - _process_env(env); - _process_binary_name_and_args(binary_name, binary_ds, args); - } - - char const *binary_name() const { return _binary_name; } - - Args args() { return Args(_args, sizeof(_args)); } - - Sysio::Env const &env() const { return _env; } - }; } + +/** + * \param ARGS_SIZE size of the argument buffer given + * to the constructor + */ +template +class Noux::Child_env +{ + private: + + enum { MAX_LEN_INTERPRETER_LINE = 128 }; + + char const *_binary_name; + char _args[ARGS_SIZE + MAX_LEN_INTERPRETER_LINE]; + Sysio::Env _env; + + void _process_env(Sysio::Env env) + { + memcpy(_env, env, sizeof(Sysio::Env)); + } + + /** + * Handle the case that the given binary needs an interpreter + */ + void _process_binary_name_and_args(Region_map &local_rm, + const char *binary_name, + Dataspace_capability binary_ds, + const char *args) + { + bool interpretable = true; + + const size_t binary_size = Dataspace_client(binary_ds).size(); + + if (binary_size < 4) + interpretable = false; + + const char *binary_addr = 0; + if (interpretable) + try { + binary_addr = local_rm.attach(binary_ds); + } catch(...) { + PWRN("could not attach dataspace"); + interpretable = false; + } + + if (interpretable && + ((binary_addr[0] != '#') || (binary_addr[1] != '!'))) + interpretable = false; + + if (!interpretable) { + local_rm.detach(binary_addr); + _binary_name = binary_name; + Genode::memcpy(_args, args, ARGS_SIZE); + return; + } + + /* find end of line */ + Range_checked_index + eol(2, min(binary_size, MAX_LEN_INTERPRETER_LINE)); + + try { + while (binary_addr[eol] != '\n') eol++; + } catch (Index_out_of_range) { } + + /* skip leading spaces */ + Range_checked_index + interpreter_line_cursor(2, eol); + + try { + while (binary_addr[interpreter_line_cursor] == ' ') + interpreter_line_cursor++; + } catch (Index_out_of_range) { } + + /* no interpreter name found */ + if (interpreter_line_cursor == eol) + throw Child::Binary_does_not_exist(); + + int interpreter_name_start = interpreter_line_cursor; + + /* find end of interpreter name */ + try { + while (binary_addr[interpreter_line_cursor] != ' ') + interpreter_line_cursor++; + } catch (Index_out_of_range) { } + + size_t interpreter_name_len = + interpreter_line_cursor - interpreter_name_start; + + /* copy interpreter name into argument buffer */ + unsigned int args_buf_cursor = 0; + Genode::strncpy(&_args[args_buf_cursor], + &binary_addr[interpreter_name_start], + interpreter_name_len + 1); + _binary_name = &_args[args_buf_cursor]; + args_buf_cursor += interpreter_name_len + 1; + + /* skip more spaces */ + try { + while (binary_addr[interpreter_line_cursor] == ' ') + interpreter_line_cursor++; + } catch (Index_out_of_range) { } + + /* append interpreter arguments to argument buffer */ + size_t interpreter_args_len = eol - interpreter_line_cursor; + if (interpreter_args_len > 0) { + Genode::strncpy(&_args[args_buf_cursor], + &binary_addr[interpreter_line_cursor], + interpreter_args_len + 1); + args_buf_cursor += interpreter_args_len + 1; + } + + /* append script arguments to argument buffer */ + Genode::memcpy(&_args[args_buf_cursor], + args, ARGS_SIZE); + + local_rm.detach(binary_addr); + } + + public: + + Child_env(Region_map &local_rm, const char *binary_name, + Dataspace_capability binary_ds, const char *args, Sysio::Env env) + { + _process_env(env); + _process_binary_name_and_args(local_rm, binary_name, binary_ds, args); + } + + char const *binary_name() const { return _binary_name; } + + Args args() { return Args(_args, sizeof(_args)); } + + Sysio::Env const &env() const { return _env; } +}; + #endif /* _NOUX__CHILD_ENV_H_ */ diff --git a/repos/ports/src/noux/child_policy.h b/repos/ports/src/noux/child_policy.h index 9d6a413361..8be2de68fe 100644 --- a/repos/ports/src/noux/child_policy.h +++ b/repos/ports/src/noux/child_policy.h @@ -33,161 +33,164 @@ namespace Noux { typedef Local_service Cpu_service; typedef Local_service > Noux_service; - class Child_policy : public Genode::Child_policy - { - private: - - Name const _name; - Binary_name const _binary_name; - Init::Child_policy_provide_rom_file _args_policy; - Init::Child_policy_provide_rom_file _env_policy; - Init::Child_policy_provide_rom_file _config_policy; - Pd_service &_pd_service; - Ram_service &_ram_service; - Cpu_service &_cpu_service; - Noux_service &_noux_service; - Local_rom_service &_rom_service; - Parent_services &_parent_services; - Family_member &_family_member; - Parent_exit *_parent_exit; - File_descriptor_registry &_file_descriptor_registry; - Signal_context_capability _destruct_context_cap; - Ram_session &_ref_ram; - Ram_session_capability _ref_ram_cap; - int _exit_value; - bool _verbose; - - template - static Genode::Service *_find_service(Genode::Registry &services, - Genode::Service::Name const &name) - { - Genode::Service *service = nullptr; - services.for_each([&] (T &s) { - if (!service && (s.name() == name)) - service = &s; }); - return service; - } - - public: - - Child_policy(Name const &name, - Binary_name const &binary_name, - Dataspace_capability args_ds, - Dataspace_capability env_ds, - Dataspace_capability config_ds, - Rpc_entrypoint &entrypoint, - Pd_service &pd_service, - Ram_service &ram_service, - Cpu_service &cpu_service, - Noux_service &noux_service, - Local_rom_service &rom_service, - Parent_services &parent_services, - Family_member &family_member, - Parent_exit *parent_exit, - File_descriptor_registry &file_descriptor_registry, - Signal_context_capability destruct_context_cap, - Ram_session &ref_ram, - Ram_session_capability ref_ram_cap, - bool verbose) - : - _name(name), - _binary_name(binary_name), - _args_policy( "args", args_ds, &entrypoint), - _env_policy( "env", env_ds, &entrypoint), - _config_policy("config", config_ds, &entrypoint), - _pd_service(pd_service), _ram_service(ram_service), - _cpu_service(cpu_service), _noux_service(noux_service), - _rom_service(rom_service), _parent_services(parent_services), - _family_member(family_member), - _parent_exit(parent_exit), - _file_descriptor_registry(file_descriptor_registry), - _destruct_context_cap(destruct_context_cap), - _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), - _exit_value(~0), - _verbose(verbose) - { } - - int exit_value() const { return _exit_value; } - - /**************************** - ** Child policy interface ** - ****************************/ - - Name name() const override { return _name; } - Binary_name binary_name() const override { return _binary_name; } - - Ram_session &ref_ram() override { return _ref_ram; } - - Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } - - void init(Ram_session &session, Ram_session_capability cap) override - { - session.ref_account(_ref_ram_cap); - } - - Service &resolve_session_request(Service::Name const &service_name, - Session_state::Args const &args) override - { - Session_label const label(Genode::label_from_args(args.string())); - - /* route initial ROM requests (binary and linker) to the parent */ - if (service_name == Genode::Rom_session::service_name()) { - if (label.last_element() == binary_name()) return _rom_service; - if (label.last_element() == linker_name()) return _rom_service; - } - - Genode::Service *service = nullptr; - - /* check for local ROM requests */ - if ((service = _args_policy .resolve_session_request(service_name.string(), args.string())) - || (service = _env_policy .resolve_session_request(service_name.string(), args.string())) - || (service = _config_policy.resolve_session_request(service_name.string(), args.string()))) - return *service; - - /* check for local services */ - if (service_name == Genode::Ram_session::service_name()) return _ram_service; - if (service_name == Genode::Cpu_session::service_name()) return _cpu_service; - if (service_name == Genode::Rom_session::service_name()) return _rom_service; - if (service_name == Genode::Pd_session::service_name()) return _pd_service; - if (service_name == Noux::Session::service_name()) return _noux_service; - - /* check for parent services */ - if ((service = _find_service(_parent_services, service_name))) - return *service; - - throw Parent::Service_denied(); - } - - void exit(int exit_value) override - { - _exit_value = exit_value; - - if (_verbose || (exit_value != 0)) - log("child ", _name, " exited with exit value ", exit_value); - - /* - * Close all open file descriptors. This is necessary to unblock - * the parent if it is trying to read from a pipe (connected to - * the child) before calling 'wait4()'. - */ - _file_descriptor_registry.flush(); - - _family_member.exit(exit_value); - - /* notify the parent */ - if (_parent_exit) - _parent_exit->exit_child(); - else { - /* handle exit of the init process */ - Signal_transmitter(_destruct_context_cap).submit(); - } - } - - Region_map *address_space(Pd_session &pd) override - { - return &static_cast(pd).address_space_region_map(); - } - }; + class Child_policy; } + +class Noux::Child_policy : public Genode::Child_policy +{ + private: + + Name const _name; + Binary_name const _binary_name; + Init::Child_policy_provide_rom_file _args_policy; + Init::Child_policy_provide_rom_file _env_policy; + Init::Child_policy_provide_rom_file _config_policy; + Pd_service &_pd_service; + Ram_service &_ram_service; + Cpu_service &_cpu_service; + Noux_service &_noux_service; + Local_rom_service &_rom_service; + Parent_services &_parent_services; + Family_member &_family_member; + Parent_exit *_parent_exit; + File_descriptor_registry &_file_descriptor_registry; + Signal_context_capability _destruct_context_cap; + Ram_session &_ref_ram; + Ram_session_capability _ref_ram_cap; + int _exit_value; + bool _verbose; + + template + static Genode::Service *_find_service(Genode::Registry &services, + Genode::Service::Name const &name) + { + Genode::Service *service = nullptr; + services.for_each([&] (T &s) { + if (!service && (s.name() == name)) + service = &s; }); + return service; + } + + public: + + Child_policy(Name const &name, + Binary_name const &binary_name, + Dataspace_capability args_ds, + Dataspace_capability env_ds, + Dataspace_capability config_ds, + Rpc_entrypoint &entrypoint, + Pd_service &pd_service, + Ram_service &ram_service, + Cpu_service &cpu_service, + Noux_service &noux_service, + Local_rom_service &rom_service, + Parent_services &parent_services, + Family_member &family_member, + Parent_exit *parent_exit, + File_descriptor_registry &file_descriptor_registry, + Signal_context_capability destruct_context_cap, + Ram_session &ref_ram, + Ram_session_capability ref_ram_cap, + bool verbose) + : + _name(name), + _binary_name(binary_name), + _args_policy( "args", args_ds, &entrypoint), + _env_policy( "env", env_ds, &entrypoint), + _config_policy("config", config_ds, &entrypoint), + _pd_service(pd_service), _ram_service(ram_service), + _cpu_service(cpu_service), _noux_service(noux_service), + _rom_service(rom_service), _parent_services(parent_services), + _family_member(family_member), + _parent_exit(parent_exit), + _file_descriptor_registry(file_descriptor_registry), + _destruct_context_cap(destruct_context_cap), + _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), + _exit_value(~0), + _verbose(verbose) + { } + + int exit_value() const { return _exit_value; } + + /**************************** + ** Child policy interface ** + ****************************/ + + Name name() const override { return _name; } + Binary_name binary_name() const override { return _binary_name; } + + Ram_session &ref_ram() override { return _ref_ram; } + + Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } + + void init(Ram_session &session, Ram_session_capability cap) override + { + session.ref_account(_ref_ram_cap); + } + + Service &resolve_session_request(Service::Name const &service_name, + Session_state::Args const &args) override + { + Session_label const label(Genode::label_from_args(args.string())); + + /* route initial ROM requests (binary and linker) to the parent */ + if (service_name == Genode::Rom_session::service_name()) { + if (label.last_element() == binary_name()) return _rom_service; + if (label.last_element() == linker_name()) return _rom_service; + } + + Genode::Service *service = nullptr; + + /* check for local ROM requests */ + if ((service = _args_policy .resolve_session_request(service_name.string(), args.string())) + || (service = _env_policy .resolve_session_request(service_name.string(), args.string())) + || (service = _config_policy.resolve_session_request(service_name.string(), args.string()))) + return *service; + + /* check for local services */ + if (service_name == Genode::Ram_session::service_name()) return _ram_service; + if (service_name == Genode::Cpu_session::service_name()) return _cpu_service; + if (service_name == Genode::Rom_session::service_name()) return _rom_service; + if (service_name == Genode::Pd_session::service_name()) return _pd_service; + if (service_name == Noux::Session::service_name()) return _noux_service; + + /* check for parent services */ + if ((service = _find_service(_parent_services, service_name))) + return *service; + + throw Parent::Service_denied(); + } + + void exit(int exit_value) override + { + _exit_value = exit_value; + + if (_verbose || (exit_value != 0)) + log("child ", _name, " exited with exit value ", exit_value); + + /* + * Close all open file descriptors. This is necessary to unblock + * the parent if it is trying to read from a pipe (connected to + * the child) before calling 'wait4()'. + */ + _file_descriptor_registry.flush(); + + _family_member.exit(exit_value); + + /* notify the parent */ + if (_parent_exit) + _parent_exit->exit_child(); + else { + /* handle exit of the init process */ + Signal_transmitter(_destruct_context_cap).submit(); + } + } + + Region_map *address_space(Pd_session &pd) override + { + return &static_cast(pd).address_space_region_map(); + } +}; + #endif /* _NOUX__CHILD_POLICY_H_ */ diff --git a/repos/ports/src/noux/cpu_session_component.h b/repos/ports/src/noux/cpu_session_component.h index abbaf9971c..c19275f1ba 100644 --- a/repos/ports/src/noux/cpu_session_component.h +++ b/repos/ports/src/noux/cpu_session_component.h @@ -34,137 +34,140 @@ #include namespace Noux { - + class Cpu_session_component; using namespace Genode; - - class Cpu_session_component : public Rpc_object - { - private: - - Rpc_entrypoint &_ep; - bool const _forked; - Cpu_connection _cpu; - - enum { MAX_THREADS = 8, MAIN_THREAD_IDX = 0 }; - - Thread_capability _threads[MAX_THREADS]; - Dataspace_capability _trace_control; - Dataspace_registry &_registry; - - public: - - /** - * Constructor - * - * \param forked false if the CPU session belongs to a child - * created via execve or to the init process, or - * true if the CPU session belongs to a newly - * forked process. - * - * The 'forked' parameter controls the policy applied to the - * startup of the main thread. - */ - Cpu_session_component(Rpc_entrypoint &ep, Child_policy::Name const &label, - bool forked, Dataspace_registry ®istry) - : _ep(ep), _forked(forked), _cpu(label.string()), _registry(registry) - { _ep.manage(this); } - - ~Cpu_session_component() - { - _ep.dissolve(this); - - if (!_trace_control.valid()) - return; - - auto lambda = [&] (Static_dataspace_info *rdi) { return rdi; }; - Static_dataspace_info *ds_info = _registry.apply(_trace_control, lambda); - if (ds_info) - destroy(env()->heap(), ds_info); - } - - /** - * Explicitly start main thread, only meaningful when - * 'forked' is true - */ - void start_main_thread(addr_t ip, addr_t sp) - { - Capability main_thread = _threads[MAIN_THREAD_IDX]; - Cpu_thread_client(main_thread).start(ip, sp); - } - - Cpu_session_capability cpu_cap() { return _cpu.cap(); } - - - /*************************** - ** Cpu_session interface ** - ***************************/ - - Thread_capability create_thread(Capability pd_cap, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb) override - { - /* create thread at core, keep local copy (needed on NOVA) */ - for (unsigned i = 0; i < MAX_THREADS; i++) { - if (_threads[i].valid()) - continue; - - auto lambda = [&] (Pd_session_component *pd) - { - if (!pd) - throw Thread_creation_failed(); - - return _cpu.create_thread(pd->core_pd_cap(), name, - affinity, weight, utcb); - }; - - Thread_capability cap = _ep.apply(pd_cap, lambda); - _threads[i] = cap; - return cap; - } - - error("maximum number of threads per session reached"); - throw Thread_creation_failed(); - } - - void kill_thread(Thread_capability thread) override - { - /* purge local copy of thread capability */ - for (unsigned i = 0; i < MAX_THREADS; i++) - if (_threads[i].local_name() == thread.local_name()) - _threads[i] = Thread_capability(); - - _cpu.kill_thread(thread); - } - - void exception_sigh(Signal_context_capability handler) override { - _cpu.exception_sigh(handler); } - - Affinity::Space affinity_space() const override { - return _cpu.affinity_space(); } - - Dataspace_capability trace_control() override - { - if (!_trace_control.valid()) { - _trace_control = _cpu.trace_control(); - new (env()->heap()) Static_dataspace_info(_registry, - _trace_control); - } - return _trace_control; - } - - Quota quota() override { return _cpu.quota(); } - - int ref_account(Cpu_session_capability c) override { - return _cpu.ref_account(c); } - - int transfer_quota(Cpu_session_capability c, size_t q) override { - return _cpu.transfer_quota(c, q); } - - Capability native_cpu() override { - return _cpu.native_cpu(); } - }; } + +class Noux::Cpu_session_component : public Rpc_object +{ + private: + + Rpc_entrypoint &_ep; + bool const _forked; + Cpu_connection _cpu; + + enum { MAX_THREADS = 8, MAIN_THREAD_IDX = 0 }; + + Thread_capability _threads[MAX_THREADS]; + Dataspace_capability _trace_control; + Dataspace_registry &_registry; + + Constructible _ds_info; + + public: + + /** + * Constructor + * + * \param forked false if the CPU session belongs to a child + * created via execve or to the init process, or + * true if the CPU session belongs to a newly + * forked process. + * + * The 'forked' parameter controls the policy applied to the + * startup of the main thread. + */ + Cpu_session_component(Env &env, + Rpc_entrypoint &ep, + Child_policy::Name const &label, + bool forked, + Dataspace_registry ®istry) + : + _ep(ep), _forked(forked), _cpu(env, label.string()), _registry(registry) + { + _ep.manage(this); + } + + ~Cpu_session_component() + { + _ep.dissolve(this); + + if (!_trace_control.valid()) + return; + } + + /** + * Explicitly start main thread, only meaningful when + * 'forked' is true + */ + void start_main_thread(addr_t ip, addr_t sp) + { + Capability main_thread = _threads[MAIN_THREAD_IDX]; + Cpu_thread_client(main_thread).start(ip, sp); + } + + Cpu_session_capability cpu_cap() { return _cpu.cap(); } + + + /*************************** + ** Cpu_session interface ** + ***************************/ + + Thread_capability create_thread(Capability pd_cap, + Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb) override + { + /* create thread at core, keep local copy (needed on NOVA) */ + for (unsigned i = 0; i < MAX_THREADS; i++) { + if (_threads[i].valid()) + continue; + + auto lambda = [&] (Pd_session_component *pd) + { + if (!pd) + throw Thread_creation_failed(); + + return _cpu.create_thread(pd->core_pd_cap(), name, + affinity, weight, utcb); + }; + + Thread_capability cap = _ep.apply(pd_cap, lambda); + _threads[i] = cap; + return cap; + } + + error("maximum number of threads per session reached"); + throw Thread_creation_failed(); + } + + void kill_thread(Thread_capability thread) override + { + /* purge local copy of thread capability */ + for (unsigned i = 0; i < MAX_THREADS; i++) + if (_threads[i].local_name() == thread.local_name()) + _threads[i] = Thread_capability(); + + _cpu.kill_thread(thread); + } + + void exception_sigh(Signal_context_capability handler) override { + _cpu.exception_sigh(handler); } + + Affinity::Space affinity_space() const override { + return _cpu.affinity_space(); } + + Dataspace_capability trace_control() override + { + if (!_trace_control.valid()) { + _trace_control = _cpu.trace_control(); + _ds_info.construct(_registry, _trace_control); + } + return _trace_control; + } + + Quota quota() override { return _cpu.quota(); } + + int ref_account(Cpu_session_capability c) override { + return _cpu.ref_account(c); } + + int transfer_quota(Cpu_session_capability c, size_t q) override { + return _cpu.transfer_quota(c, q); } + + Capability native_cpu() override { + return _cpu.native_cpu(); } +}; + #endif /* _NOUX__CPU_SESSION_COMPONENT_H_ */ diff --git a/repos/ports/src/noux/dataspace_registry.h b/repos/ports/src/noux/dataspace_registry.h index cda9fab6f3..33f6dfbe59 100644 --- a/repos/ports/src/noux/dataspace_registry.h +++ b/repos/ports/src/noux/dataspace_registry.h @@ -19,163 +19,186 @@ #include namespace Noux { - - class Dataspace_registry; + class Dataspace_user; class Dataspace_info; + class Dataspace_registry; + struct Static_dataspace_info; - struct Dataspace_user : List::Element - { - virtual void dissolve(Dataspace_info &ds) = 0; - }; - - - class Dataspace_info : public Object_pool::Entry - { - private: - - size_t _size; - Dataspace_capability _ds_cap; - Lock _users_lock; - List _users; - - public: - - Dataspace_info(Dataspace_capability ds_cap) - : - Object_pool::Entry(ds_cap), - _size(ds_cap.valid() ? Dataspace_client(ds_cap).size() : 0), - _ds_cap(ds_cap) - { } - - virtual ~Dataspace_info() { } - - size_t size() const { return _size; } - Dataspace_capability ds_cap() const { return _ds_cap; } - - void register_user(Dataspace_user &user) - { - Lock::Guard guard(_users_lock); - _users.insert(&user); - } - - void unregister_user(Dataspace_user &user) - { - Lock::Guard guard(_users_lock); - _users.remove(&user); - } - - void dissolve_users() - { - for (;;) { - Dataspace_user *user = 0; - { - Lock::Guard guard(_users_lock); - user = _users.first(); - if (!user) - break; - - _users.remove(user); - } - user->dissolve(*this); - } - } - - /** - * Create shadow copy of dataspace - * - * \param ds_registry registry for keeping track of - * the new dataspace - * \param ep entrypoint used to serve the RPC - * interface of the new dataspace - * (used if the dataspace is a sub - * RM session) - * \return capability for the new dataspace - */ - virtual Dataspace_capability fork(Ram_session &ram, - Dataspace_registry &ds_registry, - Rpc_entrypoint &ep) = 0; - - /** - * Write raw byte sequence into dataspace - * - * \param dst_offset destination offset within dataspace - * \param src data source buffer - * \param len length of source buffer in bytes - */ - virtual void poke(addr_t dst_offset, void const *src, size_t len) = 0; - - /** - * Return leaf region map that covers a given address - * - * \param addr address that is covered by the requested region map - */ - virtual Capability lookup_region_map(addr_t const addr) - { - /* by default a dataspace is no sub region map, so return invalid */ - return Capability(); - } - }; - - - class Dataspace_registry : public Object_pool - { - public: - - ~Dataspace_registry() - { - /* - * At the time the destructor is called, most 'Dataspace_info' - * objects are expected to be gone already because - * 'Child::_resources' and 'Child::_child' are destructed - * before the 'Child::_ds_registry'. However, RM dataspaces - * created via 'Rm_dataspace_info::fork', are not handled by - * those destructors. So we have to clean them up here. - */ - remove_all([&] (Dataspace_info *info) { - destroy(env()->heap(), info); }); - } - }; - - - struct Static_dataspace_info : Dataspace_info - { - Dataspace_registry &_ds_registry; - - Static_dataspace_info(Dataspace_registry &ds_registry, - Dataspace_capability ds) - : Dataspace_info(ds), _ds_registry(ds_registry) - { - _ds_registry.insert(this); - } - - ~Static_dataspace_info() - { - auto lambda = [this] (Static_dataspace_info *info) { - if (!info) { - error("lookup of binary ds info failed"); - return; - } - - _ds_registry.remove(info); - - info->dissolve_users(); - }; - _ds_registry.apply(ds_cap(), lambda); - } - - Dataspace_capability fork(Ram_session &, - Dataspace_registry &, - Rpc_entrypoint &) - { - return ds_cap(); - } - - void poke(addr_t dst_offset, void const *src, size_t len) - { - error("attempt to poke onto a static dataspace"); - } - }; + using namespace Genode; } + +struct Noux::Dataspace_user : List::Element +{ + virtual void dissolve(Dataspace_info &ds) = 0; +}; + + +class Noux::Dataspace_info : public Object_pool::Entry +{ + private: + + size_t _size; + Dataspace_capability _ds_cap; + Lock _users_lock; + List _users; + + public: + + Dataspace_info(Dataspace_capability ds_cap) + : + Object_pool::Entry(ds_cap), + _size(ds_cap.valid() ? Dataspace_client(ds_cap).size() : 0), + _ds_cap(ds_cap) + { } + + virtual ~Dataspace_info() { } + + size_t size() const { return _size; } + Dataspace_capability ds_cap() const { return _ds_cap; } + + void register_user(Dataspace_user &user) + { + Lock::Guard guard(_users_lock); + _users.insert(&user); + } + + void unregister_user(Dataspace_user &user) + { + Lock::Guard guard(_users_lock); + _users.remove(&user); + } + + void dissolve_users() + { + for (;;) { + Dataspace_user *user = 0; + { + Lock::Guard guard(_users_lock); + user = _users.first(); + if (!user) + break; + + _users.remove(user); + } + user->dissolve(*this); + } + } + + /** + * Create shadow copy of dataspace + * + * \param ram backing store used for copied dataspaces + * \param local_rm region map used for temporarily attaching + * dataspaces to the local address space + * \param alloc allocator used for creatng new 'Dataspace_info' + * objects + * \param ds_registry registry for keeping track of + * the new dataspace + * \param ep entrypoint used to serve the RPC + * interface of the new dataspace + * (used if the dataspace is a sub + * RM session) + * \return capability for the new dataspace + */ + virtual Dataspace_capability fork(Ram_session &ram, + Region_map &local_rm, + Allocator &alloc, + Dataspace_registry &ds_registry, + Rpc_entrypoint &ep) = 0; + + /** + * Write raw byte sequence into dataspace + * + * \param local_rm region map used for temporarily attaching + * the targeted dataspace to the local address + * space + * \param dst_offset destination offset within dataspace + * \param src data source buffer + * \param len length of source buffer in bytes + */ + virtual void poke(Region_map &local_rm, addr_t dst_offset, + char const *src, size_t len) = 0; + + /** + * Return leaf region map that covers a given address + * + * \param addr address that is covered by the requested region map + */ + virtual Capability lookup_region_map(addr_t const addr) + { + /* by default a dataspace is no sub region map, so return invalid */ + return Capability(); + } +}; + + +class Noux::Dataspace_registry : public Object_pool +{ + private: + + Allocator &_alloc; + + public: + + Dataspace_registry(Allocator &alloc) : _alloc(alloc) { } + + ~Dataspace_registry() + { + /* + * At the time the destructor is called, most 'Dataspace_info' + * objects are expected to be gone already because + * 'Child::_resources' and 'Child::_child' are destructed + * before the 'Child::_ds_registry'. However, RM dataspaces + * created via 'Rm_dataspace_info::fork', are not handled by + * those destructors. So we have to clean them up here. + */ + remove_all([&] (Dataspace_info *info) { destroy(_alloc, info); }); + } +}; + + +struct Noux::Static_dataspace_info : Dataspace_info +{ + Dataspace_registry &_ds_registry; + + Static_dataspace_info(Dataspace_registry &ds_registry, + Dataspace_capability ds) + : Dataspace_info(ds), _ds_registry(ds_registry) + { + _ds_registry.insert(this); + } + + ~Static_dataspace_info() + { + auto lambda = [this] (Static_dataspace_info *info) { + + if (!info) { + error("lookup of binary ds info failed"); + return; + } + + _ds_registry.remove(info); + + info->dissolve_users(); + }; + _ds_registry.apply(ds_cap(), lambda); + } + + Dataspace_capability fork(Ram_session &, + Region_map &, + Allocator &, + Dataspace_registry &, + Rpc_entrypoint &) override + { + return ds_cap(); + } + + void poke(Region_map &, addr_t, char const *, size_t) override + { + error("attempt to poke onto a static dataspace"); + } +}; + #endif /* _NOUX__DATASPACE_REGISTRY_H_ */ diff --git a/repos/ports/src/noux/destruct_dispatcher.h b/repos/ports/src/noux/destruct_dispatcher.h deleted file mode 100644 index e7a962ba6c..0000000000 --- a/repos/ports/src/noux/destruct_dispatcher.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * \brief Signal_dispatcher which adds a destruct queue element into a - * destruct queue - * \author Christian Prochaska - * \date 2013-01-03 - */ - -/* - * Copyright (C) 2013-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NOUX__DESTRUCT_DISPATCHER_H_ -#define _NOUX__DESTRUCT_DISPATCHER_H_ - -/* Genode includes */ -#include - -/* Noux includes */ -#include - -namespace Noux { - - using namespace Genode; - - class Destruct_dispatcher : public Signal_dispatcher_base - { - private: - - Destruct_queue &_destruct_queue; - Destruct_queue::Element_base *_element; - - public: - - Destruct_dispatcher(Destruct_queue &destruct_queue, - Destruct_queue::Element_base *element) - : _destruct_queue(destruct_queue), _element(element) { } - - void dispatch(unsigned) - { - _destruct_queue.insert(_element); - } - }; -} - -#endif /* _NOUX__DESTRUCT_DISPATCHER_H_ */ diff --git a/repos/ports/src/noux/destruct_queue.h b/repos/ports/src/noux/destruct_queue.h index 7c1720d974..ae415a408a 100644 --- a/repos/ports/src/noux/destruct_queue.h +++ b/repos/ports/src/noux/destruct_queue.h @@ -18,77 +18,81 @@ #include #include -namespace Noux { +namespace Noux { class Destruct_queue; } - class Destruct_queue - { - public: - struct Element_base : Genode::List::Element - { - virtual void destroy() = 0; - }; +class Noux::Destruct_queue +{ + public: - /* - * When a pointer to an object which inherits 'Element' among other - * base classes gets static-casted to a pointer to the 'Element' - * base object, the resulting address can differ from the start - * address of the inherited object. To be able to pass the start - * address of the inherited object to the allocator, a static-cast - * back to the inherited class needs to be performed. Therefore the - * type of the class inheriting from 'Element' needs to be given as - * template parameter. - */ - template - class Element : public Element_base - { - private: + struct Element_base : Genode::List::Element + { + virtual void destroy() = 0; + }; - Genode::Allocator *_alloc; + /* + * When a pointer to an object which inherits 'Element' among other + * base classes gets static-casted to a pointer to the 'Element' + * base object, the resulting address can differ from the start + * address of the inherited object. To be able to pass the start + * address of the inherited object to the allocator, a static-cast + * back to the inherited class needs to be performed. Therefore the + * type of the class inheriting from 'Element' needs to be given as + * template parameter. + */ + template + class Element : public Element_base + { + private: - public: + Genode::Allocator &_alloc; - /** - * Constructor - * - * \param alloc the allocator which was used to allocate - * the element - */ - Element(Genode::Allocator *alloc) : _alloc(alloc) { } + public: - virtual ~Element() { }; + /** + * Constructor + * + * \param alloc the allocator which was used to allocate + * the element + */ + Element(Genode::Allocator &alloc) : _alloc(alloc) { } - void destroy() - { - Genode::destroy(_alloc, static_cast(this)); - } - }; + virtual ~Element() { }; - private: - - Genode::List _destruct_list; - Genode::Lock _destruct_list_lock; - - public: - - void insert(Element_base *element) - { - Genode::Lock::Guard guard(_destruct_list_lock); - _destruct_list.insert(element); - } - - void flush() - { - Genode::Lock::Guard guard(_destruct_list_lock); - - Element_base *element; - while ((element = _destruct_list.first())) { - _destruct_list.remove(element); - element->destroy(); + void destroy() + { + Genode::destroy(_alloc, static_cast(this)); } - } - }; + }; -} + private: + + Genode::List _destruct_list; + Genode::Lock _destruct_list_lock; + Signal_context_capability _sigh; + + public: + + Destruct_queue(Signal_context_capability sigh) : _sigh(sigh) { } + + void insert(Element_base *element) + { + Genode::Lock::Guard guard(_destruct_list_lock); + _destruct_list.insert(element); + + Signal_transmitter(_sigh).submit(); + } + + void flush() + { + Genode::Lock::Guard guard(_destruct_list_lock); + + Element_base *element; + while ((element = _destruct_list.first())) { + _destruct_list.remove(element); + element->destroy(); + } + } +}; #endif /* _NOUX__DESTRUCT_QUEUE_H_ */ diff --git a/repos/ports/src/noux/dummy_input_io_channel.h b/repos/ports/src/noux/dummy_input_io_channel.h deleted file mode 100644 index 1577b8c85a..0000000000 --- a/repos/ports/src/noux/dummy_input_io_channel.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * \brief Dummy input I/O channel to be used for non-interactive init - * \author Norman Feske - * \date 2011-02-17 - */ - -/* - * Copyright (C) 2011-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NOUX__DUMMY_INPUT_IO_CHANNEL_H_ -#define _NOUX__DUMMY_INPUT_IO_CHANNEL_H_ - -/* Noux includes */ -#include - -namespace Noux { - - class Sysio; - - struct Dummy_input_io_channel : public Io_channel - { }; -} - -#endif /* _NOUX__DUMMY_INPUT_IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/environment.h b/repos/ports/src/noux/environment.h index 5515a81a32..918aa32709 100644 --- a/repos/ports/src/noux/environment.h +++ b/repos/ports/src/noux/environment.h @@ -11,39 +11,49 @@ * under the terms of the GNU General Public License version 2. */ +#ifndef _NOUX__ENVIRONMENT_H_ +#define _NOUX__ENVIRONMENT_H_ + /* Genode includes */ #include -#include -#include +#include /* Noux includes */ #include namespace Noux { - - class Environment : private Attached_ram_dataspace - { - private: - - Sysio::Env *_env; - - public: - - /** - * \param env comma-separated list of environment variables - */ - Environment(Sysio::Env const &env) : - Attached_ram_dataspace(Genode::env()->ram_session(), sizeof(Sysio::Env)), - _env(local_addr()) - { - memcpy(_env, env, sizeof(Sysio::Env)); - } - - using Attached_ram_dataspace::cap; - - /** - * Return list of environment variables as zero-separated list - */ - Sysio::Env const &env() { return *_env; } - }; + class Environment; + using namespace Genode; } + + +class Noux::Environment : private Attached_ram_dataspace +{ + private: + + Sysio::Env *_env; + + public: + + /** + * Constructor + * + * \param env comma-separated list of environment variables + */ + Environment(Ram_session &ram, Region_map &local_rm, Sysio::Env const &env) + : + Attached_ram_dataspace(ram, local_rm, sizeof(Sysio::Env)), + _env(local_addr()) + { + memcpy(_env, env, sizeof(Sysio::Env)); + } + + using Attached_ram_dataspace::cap; + + /** + * Return list of environment variables as zero-separated list + */ + Sysio::Env const &env() { return *_env; } +}; + +#endif /* _NOUX__ENVIRONMENT_H_ */ diff --git a/repos/ports/src/noux/family_member.h b/repos/ports/src/noux/family_member.h index 73aff942e4..69fd7a4bd5 100644 --- a/repos/ports/src/noux/family_member.h +++ b/repos/ports/src/noux/family_member.h @@ -22,159 +22,156 @@ #include #include -namespace Noux { +namespace Noux { class Family_member; } - class Family_member : public List::Element, - public Parent_exit, - public Parent_execve - { - private: - int const _pid; - Lock _lock; - List _list; - bool _has_exited; - int _exit_status; +class Noux::Family_member : public List::Element, + public Parent_exit, + public Parent_execve +{ + private: - protected: + int const _pid; + Lock _lock; + List _list; + bool _has_exited; + int _exit_status; - /** - * Lock used for implementing blocking syscalls, - * i.e., select, wait4, ... - */ - Lock _blocker; + protected: - public: + /** + * Lock used for implementing blocking syscalls, + * i.e., select, wait4, ... + */ + Lock _blocker; - Family_member(int pid) - : _pid(pid), _has_exited(false), _exit_status(0) - { } + public: - virtual ~Family_member() { } + Family_member(int pid) + : _pid(pid), _has_exited(false), _exit_status(0) + { } - int pid() const { return _pid; } + virtual ~Family_member() { } - int exit_status() const { return _exit_status; } + int pid() const { return _pid; } - /** - * Called by the parent at creation time of the process - */ - void insert(Family_member *member) - { - Lock::Guard guard(_lock); - _list.insert(member); + int exit_status() const { return _exit_status; } + + /** + * Called by the parent at creation time of the process + */ + void insert(Family_member *member) + { + Lock::Guard guard(_lock); + _list.insert(member); + } + + /** + * Called by the parent from the return path of the wait4 syscall + */ + void remove(Family_member *member) + { + Lock::Guard guard(_lock); + _list.remove(member); + } + + virtual void submit_signal(Noux::Sysio::Signal sig) = 0; + + /** + * Called by the parent (originates from Kill_broadcaster) + */ + bool deliver_kill(int pid, Noux::Sysio::Signal sig) + { + Lock::Guard guard(_lock); + + if (pid == _pid) { + submit_signal(sig); + return true; } - /** - * Called by the parent from the return path of the wait4 syscall - */ - void remove(Family_member *member) - { - Lock::Guard guard(_lock); - _list.remove(member); + bool result = false; + + for (Family_member *child = _list.first(); child; child = child->next()) + if (child->deliver_kill(pid, sig)) + result = true; + + return result; + } + + /** + * Parent_exit interface + */ + + /* Called by the child on the parent (via Parent_exit) */ + void exit_child() + { + submit_signal(Sysio::Signal::SIG_CHLD); + } + + /** + * Parent_execve interface + */ + + /* Called by the parent from 'execve_child()' */ + virtual Family_member *do_execve(const char *filename, + Args const &args, + Sysio::Env const &env) = 0; + + /* Called by the child on the parent (via Parent_execve) */ + void execve_child(Family_member &child, + const char *filename, + Args const &args, + Sysio::Env const &env) + { + Lock::Guard guard(_lock); + Family_member *new_child = child.do_execve(filename, + args, + env); + _list.insert(new_child); + _list.remove(&child); + } + + + /** + * Tell the parent that we exited + */ + void exit(int exit_status) + { + _exit_status = exit_status; + _has_exited = true; + } + + Family_member *poll4() + { + Lock::Guard guard(_lock); + + /* check if any of our children has exited */ + Family_member *curr = _list.first(); + for (; curr; curr = curr->next()) { + if (curr->_has_exited) + return curr; } + return 0; + } - virtual void submit_signal(Noux::Sysio::Signal sig) = 0; - - /** - * Called by the parent (originates from Kill_broadcaster) - */ - bool deliver_kill(int pid, Noux::Sysio::Signal sig) - { - Lock::Guard guard(_lock); - - if (pid == _pid) { - submit_signal(sig); - return true; - } - - bool result = false; - - for (Family_member *child = _list.first(); child; child = child->next()) - if (child->deliver_kill(pid, sig)) - result = true; + /** + * Wait for the exit of any of our children + */ + Family_member *wait4() + { + /* reset the blocker lock to the 'locked' state */ + _blocker.unlock(); + _blocker.lock(); + Family_member *result = poll4(); + if (result) return result; - } - /** - * Parent_exit interface - */ + _blocker.lock(); - /* Called by the child on the parent (via Parent_exit) */ - void exit_child() - { - submit_signal(Sysio::Signal::SIG_CHLD); - } - - /** - * Parent_execve interface - */ - - /* Called by the parent from 'execve_child()' */ - virtual Family_member *do_execve(const char *filename, - Args const &args, - Sysio::Env const &env, - bool verbose) = 0; - - /* Called by the child on the parent (via Parent_execve) */ - void execve_child(Family_member &child, - const char *filename, - Args const &args, - Sysio::Env const &env, - bool verbose) - { - Lock::Guard guard(_lock); - Family_member *new_child = child.do_execve(filename, - args, - env, - verbose); - _list.insert(new_child); - _list.remove(&child); - } - - - /** - * Tell the parent that we exited - */ - void exit(int exit_status) - { - _exit_status = exit_status; - _has_exited = true; - } - - Family_member *poll4() - { - Lock::Guard guard(_lock); - - /* check if any of our children has exited */ - Family_member *curr = _list.first(); - for (; curr; curr = curr->next()) { - if (curr->_has_exited) - return curr; - } - return 0; - } - - /** - * Wait for the exit of any of our children - */ - Family_member *wait4() - { - /* reset the blocker lock to the 'locked' state */ - _blocker.unlock(); - _blocker.lock(); - - Family_member *result = poll4(); - if (result) - return result; - - _blocker.lock(); - - /* either a child exited or a signal occurred */ - return poll4(); - } - }; -} + /* either a child exited or a signal occurred */ + return poll4(); + } +}; #endif /* _NOUX__FAMILY_MEMBER_H_ */ diff --git a/repos/ports/src/noux/file_descriptor_registry.h b/repos/ports/src/noux/file_descriptor_registry.h index 2b173c8e9d..22d4a594af 100644 --- a/repos/ports/src/noux/file_descriptor_registry.h +++ b/repos/ports/src/noux/file_descriptor_registry.h @@ -17,105 +17,105 @@ /* Noux includes */ #include -namespace Noux { +namespace Noux { class File_descriptor_registry; } - class File_descriptor_registry - { - public: - enum { MAX_FILE_DESCRIPTORS = 64 }; +class Noux::File_descriptor_registry +{ + public: - private: + enum { MAX_FILE_DESCRIPTORS = 64 }; - struct { - bool allocated; - Shared_pointer io_channel; - } _fds[MAX_FILE_DESCRIPTORS]; + private: - bool _valid_fd(int fd) const - { - return (fd >= 0) && (fd < MAX_FILE_DESCRIPTORS); - } + struct { + bool allocated; + Shared_pointer io_channel; + } _fds[MAX_FILE_DESCRIPTORS]; - bool _find_available_fd(int *fd) const - { - /* allocate the first free file descriptor */ - for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++) - if (_fds[i].allocated == false) { - *fd = i; - return true; - } - return false; - } + bool _valid_fd(int fd) const + { + return (fd >= 0) && (fd < MAX_FILE_DESCRIPTORS); + } - void _assign_fd(int fd, Shared_pointer &io_channel) - { - _fds[fd].io_channel = io_channel; - _fds[fd].allocated = true; - } - - void _reset_fd(int fd) - { - _fds[fd].io_channel = Shared_pointer(); - _fds[fd].allocated = false; - } - - public: - - File_descriptor_registry() - { - flush(); - } - - /** - * Associate I/O channel with file descriptor - * - * \return noux file descriptor used for the I/O channel - */ - virtual int add_io_channel(Shared_pointer io_channel, int fd = -1) - { - if ((fd == -1) && !_find_available_fd(&fd)) { - error("could not allocate file descriptor"); - return -1; + bool _find_available_fd(int *fd) const + { + /* allocate the first free file descriptor */ + for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++) + if (_fds[i].allocated == false) { + *fd = i; + return true; } + return false; + } - if (!_valid_fd(fd)) { - error("file descriptor ", fd, " is out of range"); - return -2; - } + void _assign_fd(int fd, Shared_pointer &io_channel) + { + _fds[fd].io_channel = io_channel; + _fds[fd].allocated = true; + } - _assign_fd(fd, io_channel); - return fd; + void _reset_fd(int fd) + { + _fds[fd].io_channel = Shared_pointer(); + _fds[fd].allocated = false; + } + + public: + + File_descriptor_registry() + { + flush(); + } + + /** + * Associate I/O channel with file descriptor + * + * \return noux file descriptor used for the I/O channel + */ + virtual int add_io_channel(Shared_pointer io_channel, int fd = -1) + { + if ((fd == -1) && !_find_available_fd(&fd)) { + error("could not allocate file descriptor"); + return -1; } - virtual void remove_io_channel(int fd) - { - if (!_valid_fd(fd)) - error("file descriptor ", fd, " is out of range"); - else - _reset_fd(fd); + if (!_valid_fd(fd)) { + error("file descriptor ", fd, " is out of range"); + return -2; } - bool fd_in_use(int fd) const - { - return (_valid_fd(fd) && _fds[fd].io_channel); - } + _assign_fd(fd, io_channel); + return fd; + } - Shared_pointer io_channel_by_fd(int fd) const - { - if (!fd_in_use(fd)) - return Shared_pointer(); + virtual void remove_io_channel(int fd) + { + if (!_valid_fd(fd)) + error("file descriptor ", fd, " is out of range"); + else + _reset_fd(fd); + } - return _fds[fd].io_channel; - } + bool fd_in_use(int fd) const + { + return (_valid_fd(fd) && _fds[fd].io_channel); + } - virtual void flush() - { - /* close all file descriptors */ - for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++) - _reset_fd(i); - } - }; -} + Shared_pointer io_channel_by_fd(int fd) const + { + if (!fd_in_use(fd)) + return Shared_pointer(); + + return _fds[fd].io_channel; + } + + virtual void flush() + { + /* close all file descriptors */ + for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++) + _reset_fd(i); + } +}; #endif /* _NOUX__FILE_DESCRIPTOR_REGISTRY_H_ */ diff --git a/repos/ports/src/noux/io_channel.h b/repos/ports/src/noux/io_channel.h index a4b9afac97..a950b872ba 100644 --- a/repos/ports/src/noux/io_channel.h +++ b/repos/ports/src/noux/io_channel.h @@ -28,174 +28,176 @@ #include namespace Noux { - - class Terminal_io_channel; - extern Genode::Lock &signal_lock(); - /** - * Input/output channel backend that is used for calling - * different methos which does not belong to the original - * interface, e.g. network methods. - */ - class Io_channel_backend - { - public: + class Io_channel_backend; + class Io_channel; - virtual ~Io_channel_backend() { } - - virtual int type() const { return -1; } - }; - - /** - * Input/output channel interface - */ - class Io_channel : public Reference_counter - { - private: - - /** - * List of notifiers (i.e., processes) used by threads that block - * for an I/O-channel event - */ - List _notifiers; - Lock _notifiers_lock; - List _interrupt_handlers; - Lock _interrupt_handlers_lock; - - public: - - bool close_on_execve; - - Io_channel() : close_on_execve(false) { } - - virtual ~Io_channel() { } - - virtual Io_channel_backend* backend() { return 0; } - - virtual bool write(Sysio *sysio, size_t &offset) { return false; } - virtual bool read(Sysio *sysio) { return false; } - virtual bool fstat(Sysio *sysio) { return false; } - virtual bool ftruncate(Sysio *sysio) { return false; } - virtual bool fcntl(Sysio *sysio) { return false; } - virtual bool dirent(Sysio *sysio) { return false; } - virtual bool ioctl(Sysio *sysio) { return false; } - virtual bool lseek(Sysio *sysio) { return false; } - - /** - * Return true if an unblocking condition of the channel is satisfied - * - * \param rd if true, check for data available for reading - * \param wr if true, check for readiness for writing - * \param ex if true, check for exceptions - */ - virtual bool check_unblock(bool rd, bool wr, bool ex) const { - return false; } - - /** - * Return true if the channel is set to non-blocking mode - */ - virtual bool nonblocking() { return false; } - - /** - * Register blocker for getting waked up on an I/O channel event - * - * This function is normally called by the to-be-blocked thread - * prior blocking itself, e.g., during a 'select' syscall. - */ - void register_wake_up_notifier(Wake_up_notifier *notifier) - { - Lock::Guard guard(_notifiers_lock); - - _notifiers.insert(notifier); - } - - /** - * Unregister wake-up notifier - * - * This function is normally called after a blocker has left the - * blocking condition, e.g., during the return from the 'select' - * syscall'. - */ - void unregister_wake_up_notifier(Wake_up_notifier *notifier) - { - Lock::Guard guard(_notifiers_lock); - - _notifiers.remove(notifier); - } - - /** - * Tell all registered notifiers about an occurred I/O event - * - * This function is called by I/O channel implementations that - * respond to external signals, e.g., the availability of new - * input from a terminal session. - */ - void invoke_all_notifiers() - { - Lock::Guard guard(_notifiers_lock); - - for (Wake_up_notifier *n = _notifiers.first(); n; n = n->next()) - n->wake_up(); - } - - /** - * Register interrupt handler - * - * This function is called by Child objects to get woken up if the - * terminal sends, for example, Ctrl-C. - */ - void register_interrupt_handler(Io_channel_listener *handler) - { - Lock::Guard guard(_interrupt_handlers_lock); - - _interrupt_handlers.insert(handler); - } - - /** - * Unregister interrupt handler - */ - void unregister_interrupt_handler(Io_channel_listener *handler) - { - Lock::Guard guard(_interrupt_handlers_lock); - - _interrupt_handlers.remove(handler); - } - - /** - * Find the 'Io_channel_listener' object which contains the given - * 'Interrupt_handler' pointer - */ - Io_channel_listener *lookup_io_channel_listener(Interrupt_handler *handler) - { - for (Io_channel_listener *l = _interrupt_handlers.first(); - l; l = l->next()) - if (l->object() == handler) - return l; - return 0; - } - - /** - * Tell all registered handlers about an interrupt event - */ - void invoke_all_interrupt_handlers() - { - Lock::Guard signal_lock_guard(signal_lock()); - Lock::Guard guard(_interrupt_handlers_lock); - - for (Io_channel_listener *l = _interrupt_handlers.first(); - l; l = l->next()) - l->object()->handle_interrupt(); - } - - /** - * Get the path of the file associated with the I/O channel - * - * This function is used to simplify the implemenation of SYSCALL_FSTAT - * and is only implemented by Vfs_io_channel. - */ - virtual bool path(char *path, size_t len) { return false; } - }; + class Terminal_io_channel; } + +/** + * Input/output channel backend that is used for calling + * different methods, which does not belong to the original + * interface, e.g. network methods. + */ +struct Noux::Io_channel_backend +{ + virtual ~Io_channel_backend() { } + + virtual int type() const { return -1; } +}; + + +/** + * Input/output channel interface + */ +class Noux::Io_channel : public Reference_counter +{ + private: + + /** + * List of notifiers (i.e., processes) used by threads that block + * for an I/O-channel event + */ + List _notifiers; + Lock _notifiers_lock; + List _interrupt_handlers; + Lock _interrupt_handlers_lock; + + public: + + bool close_on_execve; + + Io_channel() : close_on_execve(false) { } + + virtual ~Io_channel() { } + + virtual Io_channel_backend *backend() { return nullptr; } + + virtual bool write(Sysio &sysio, size_t &offset) { return false; } + virtual bool read(Sysio &sysio) { return false; } + virtual bool fstat(Sysio &sysio) { return false; } + virtual bool ftruncate(Sysio &sysio) { return false; } + virtual bool fcntl(Sysio &sysio) { return false; } + virtual bool dirent(Sysio &sysio) { return false; } + virtual bool ioctl(Sysio &sysio) { return false; } + virtual bool lseek(Sysio &sysio) { return false; } + + /** + * Return true if an unblocking condition of the channel is satisfied + * + * \param rd if true, check for data available for reading + * \param wr if true, check for readiness for writing + * \param ex if true, check for exceptions + */ + virtual bool check_unblock(bool rd, bool wr, bool ex) const { + return false; } + + /** + * Return true if the channel is set to non-blocking mode + */ + virtual bool nonblocking() { return false; } + + /** + * Register blocker for getting waked up on an I/O channel event + * + * This function is normally called by the to-be-blocked thread + * prior blocking itself, e.g., during a 'select' syscall. + */ + void register_wake_up_notifier(Wake_up_notifier *notifier) + { + Lock::Guard guard(_notifiers_lock); + + _notifiers.insert(notifier); + } + + /** + * Unregister wake-up notifier + * + * This function is normally called after a blocker has left the + * blocking condition, e.g., during the return from the 'select' + * syscall'. + */ + void unregister_wake_up_notifier(Wake_up_notifier *notifier) + { + Lock::Guard guard(_notifiers_lock); + + _notifiers.remove(notifier); + } + + /** + * Tell all registered notifiers about an occurred I/O event + * + * This function is called by I/O channel implementations that + * respond to external signals, e.g., the availability of new + * input from a terminal session. + */ + void invoke_all_notifiers() + { + Lock::Guard guard(_notifiers_lock); + + for (Wake_up_notifier *n = _notifiers.first(); n; n = n->next()) + n->wake_up(); + } + + /** + * Register interrupt handler + * + * This function is called by Child objects to get woken up if the + * terminal sends, for example, Ctrl-C. + */ + void register_interrupt_handler(Io_channel_listener *handler) + { + Lock::Guard guard(_interrupt_handlers_lock); + + _interrupt_handlers.insert(handler); + } + + /** + * Unregister interrupt handler + */ + void unregister_interrupt_handler(Io_channel_listener *handler) + { + Lock::Guard guard(_interrupt_handlers_lock); + + _interrupt_handlers.remove(handler); + } + + /** + * Find the 'Io_channel_listener' object which contains the given + * 'Interrupt_handler' pointer + */ + Io_channel_listener *lookup_io_channel_listener(Interrupt_handler *handler) + { + for (Io_channel_listener *l = _interrupt_handlers.first(); + l; l = l->next()) + if (l->object() == handler) + return l; + return 0; + } + + /** + * Tell all registered handlers about an interrupt event + */ + void invoke_all_interrupt_handlers() + { + Lock::Guard signal_lock_guard(signal_lock()); + Lock::Guard guard(_interrupt_handlers_lock); + + for (Io_channel_listener *l = _interrupt_handlers.first(); + l; l = l->next()) + l->object()->handle_interrupt(); + } + + /** + * Get the path of the file associated with the I/O channel + * + * This function is used to simplify the implemenation of SYSCALL_FSTAT + * and is only implemented by Vfs_io_channel. + */ + virtual bool path(char *path, size_t len) { return false; } +}; + #endif /* _NOUX__IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/io_channel_listener.h b/repos/ports/src/noux/io_channel_listener.h index f2cdf10138..b007054a70 100644 --- a/repos/ports/src/noux/io_channel_listener.h +++ b/repos/ports/src/noux/io_channel_listener.h @@ -20,9 +20,7 @@ /* Noux includes */ #include -namespace Noux { - typedef List_element Io_channel_listener; -} +namespace Noux { typedef List_element Io_channel_listener; } #endif /* _NOUX__IO_CHANNEL_LISTENER__H_ */ diff --git a/repos/ports/src/noux/io_receptor_registry.h b/repos/ports/src/noux/io_receptor_registry.h index 7d5c9f10a0..a77032eacc 100644 --- a/repos/ports/src/noux/io_receptor_registry.h +++ b/repos/ports/src/noux/io_receptor_registry.h @@ -20,63 +20,62 @@ namespace Noux { - - struct Io_receptor : List::Element - { - private: - - Lock *_lock; - - public: - - Io_receptor(Lock *lock) - : - _lock(lock) - { } - - void check_and_wakeup() - { - if (_lock) - _lock->unlock(); - } - }; - - class Io_receptor_registry - { - private: - - List _receptors; - Lock _receptors_lock; - - public: - - Io_receptor_registry() { } - - ~Io_receptor_registry() - { - Io_receptor *receptor; - while ((receptor = _receptors.first()) != 0) - _receptors.remove(receptor); - } - - void register_receptor(Io_receptor *receptor) - { - Lock::Guard guard(_receptors_lock); - - _receptors.insert(receptor); - } - - void unregister_receptor(Io_receptor *receptor) - { - Lock::Guard guard(_receptors_lock); - - _receptors.remove(receptor); - } - - Io_receptor *first() { return _receptors.first(); } - - }; - + struct Io_receptor; + struct Io_receptor_registry; } + +struct Noux::Io_receptor : List::Element +{ + private: + + Lock *_lock; + + public: + + Io_receptor(Lock *lock) : _lock(lock) { } + + void check_and_wakeup() + { + if (_lock) + _lock->unlock(); + } +}; + + +class Noux::Io_receptor_registry +{ + private: + + List _receptors; + Lock _receptors_lock; + + public: + + Io_receptor_registry() { } + + ~Io_receptor_registry() + { + Io_receptor *receptor; + while ((receptor = _receptors.first()) != 0) + _receptors.remove(receptor); + } + + void register_receptor(Io_receptor *receptor) + { + Lock::Guard guard(_receptors_lock); + + _receptors.insert(receptor); + } + + void unregister_receptor(Io_receptor *receptor) + { + Lock::Guard guard(_receptors_lock); + + _receptors.remove(receptor); + } + + Io_receptor *first() { return _receptors.first(); } +}; + #endif /* _NOUX__IO_RECEPTOR_REGISTRY_H_ */ diff --git a/repos/ports/src/noux/local_rom_service.h b/repos/ports/src/noux/local_rom_service.h index c02d23289c..b47a86b673 100644 --- a/repos/ports/src/noux/local_rom_service.h +++ b/repos/ports/src/noux/local_rom_service.h @@ -36,16 +36,19 @@ class Noux::Local_rom_factory : public Local_rom_service::Factory { private: + Allocator &_alloc; + Env &_env; Rpc_entrypoint &_ep; Vfs::Dir_file_system &_root_dir; Dataspace_registry &_registry; public: - Local_rom_factory(Rpc_entrypoint &ep, Vfs::Dir_file_system &root_dir, + Local_rom_factory(Allocator &alloc, Env &env, Rpc_entrypoint &ep, + Vfs::Dir_file_system &root_dir, Dataspace_registry ®istry) : - _ep(ep), _root_dir(root_dir), _registry(registry) + _alloc(alloc), _env(env), _ep(ep), _root_dir(root_dir), _registry(registry) { } Rom_session_component &create(Args const &args, Affinity) override @@ -54,8 +57,8 @@ class Noux::Local_rom_factory : public Local_rom_service::Factory Rom_session_component::Name const rom_name = label_from_args(args.string()).last_element(); - return *new (env()->heap()) - Rom_session_component(_ep, _root_dir, _registry, rom_name); + return *new (_alloc) + Rom_session_component(_alloc, _env, _ep, _root_dir, _registry, rom_name); } catch (Rom_connection::Rom_connection_failed) { throw Denied(); } } @@ -64,7 +67,7 @@ class Noux::Local_rom_factory : public Local_rom_service::Factory void destroy(Rom_session_component &session) override { - Genode::destroy(env()->heap(), &session); + Genode::destroy(_alloc, &session); } }; diff --git a/repos/ports/src/noux/main.cc b/repos/ports/src/noux/main.cc index 3d623bbce4..e750ae11cd 100644 --- a/repos/ports/src/noux/main.cc +++ b/repos/ports/src/noux/main.cc @@ -12,33 +12,20 @@ */ /* Genode includes */ -#include #include +#include +#include /* Noux includes */ #include -#include #include #include #include -#include -#include #include #include #include #include #include -#include -#include - -/* supported file systems */ -#include -#include - - -static const bool verbose_quota = false; -static bool trace_syscalls = false; -static bool verbose = false; namespace Noux { @@ -47,902 +34,15 @@ namespace Noux { bool init_process(Child *child) { return child == init_child; } void init_process_exited(int exit) { init_child = 0; exit_value = exit; } - -}; +} extern void init_network(); -/** - * Timeout thread for SYSCALL_SELECT - */ -namespace Noux { - using namespace Genode; - - class Timeout_scheduler : Thread_deprecated<1024*sizeof(long)>, - public Alarm_scheduler - { - private: - Timer::Connection _timer; - Alarm::Time _curr_time; - - enum { TIMER_GRANULARITY_MSEC = 10 }; - - void entry() - { - for (;;) { - _timer.msleep(TIMER_GRANULARITY_MSEC); - Alarm_scheduler::handle(_curr_time); - _curr_time += TIMER_GRANULARITY_MSEC; - } - } - - public: - Timeout_scheduler(unsigned long curr_time) - : Thread_deprecated("timeout_sched"), _curr_time(curr_time) { start(); } - - Alarm::Time curr_time() const { return _curr_time; } - }; - - struct Timeout_state - { - bool timed_out; - - Timeout_state() : timed_out(false) { } - }; - - class Timeout_alarm : public Alarm - { - private: - Timeout_state *_state; - Lock *_blocker; - Timeout_scheduler *_scheduler; - - public: - Timeout_alarm(Timeout_state *st, Lock *blocker, Timeout_scheduler *scheduler, Time timeout) - : - _state(st), - _blocker(blocker), - _scheduler(scheduler) - { - _scheduler->schedule_absolute(this, _scheduler->curr_time() + timeout); - _state->timed_out = false; - } - - void discard() { _scheduler->discard(this); } - - protected: - - bool on_alarm(unsigned) override - { - _state->timed_out = true; - _blocker->unlock(); - - return false; - } - }; - - /** - * This function is used to generate inode values from the given - * path using the FNV-1a algorithm. - */ - inline uint32_t hash_path(const char *path, size_t len) - { - const unsigned char * p = reinterpret_cast(path); - uint32_t hash = 2166136261U; - - for (size_t i = 0; i < len; i++) { - hash ^= p[i]; - hash *= 16777619; - } - - return hash; - } -}; - - -/***************************** - ** Noux syscall dispatcher ** - *****************************/ - -bool Noux::Child::syscall(Noux::Session::Syscall sc) +Noux::Io_receptor_registry * Noux::io_receptor_registry() { - if (trace_syscalls) - log("PID ", pid(), " -> SYSCALL ", Noux::Session::syscall_name(sc)); - - bool result = false; - - try { - switch (sc) { - - case SYSCALL_WRITE: - { - size_t const count_in = _sysio.write_in.count; - - for (size_t offset = 0; offset != count_in; ) { - - Shared_pointer io = _lookup_channel(_sysio.write_in.fd); - - if (!io->nonblocking()) - _block_for_io_channel(io, false, true, false); - - if (io->check_unblock(false, true, false)) { - /* - * 'io->write' is expected to update - * '_sysio.write_out.count' and 'offset' - */ - result = io->write(&_sysio, offset); - if (result == false) - break; - } else { - if (result == false) { - /* nothing was written yet */ - _sysio.error.write = Vfs::File_io_service::WRITE_ERR_INTERRUPT; - } - break; - } - } - break; - } - - case SYSCALL_READ: - { - Shared_pointer io = _lookup_channel(_sysio.read_in.fd); - - if (!io->nonblocking()) - _block_for_io_channel(io, true, false, false); - - if (io->check_unblock(true, false, false)) - result = io->read(&_sysio); - else - _sysio.error.read = Vfs::File_io_service::READ_ERR_INTERRUPT; - - break; - } - - case SYSCALL_FTRUNCATE: - { - Shared_pointer io = _lookup_channel(_sysio.ftruncate_in.fd); - - _block_for_io_channel(io, false, true, false); - - if (io->check_unblock(false, true, false)) - result = io->ftruncate(&_sysio); - else - _sysio.error.ftruncate = Vfs::File_io_service::FTRUNCATE_ERR_INTERRUPT; - - break; - } - - case SYSCALL_STAT: - case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */ - { - /** - * We calculate the inode by hashing the path because there is - * no inode registry in noux. - */ - size_t path_len = strlen(_sysio.stat_in.path); - uint32_t path_hash = hash_path(_sysio.stat_in.path, path_len); - - Vfs::Directory_service::Stat stat_out; - _sysio.error.stat = _root_dir.stat(_sysio.stat_in.path, stat_out); - - result = (_sysio.error.stat == Vfs::Directory_service::STAT_OK); - - /* - * Instead of using the uid/gid given by the actual file system - * we use the ones specificed in the config. - */ - if (result) { - stat_out.uid = user_info()->uid; - stat_out.gid = user_info()->gid; - - stat_out.inode = path_hash; - } - - _sysio.stat_out.st = stat_out; - - break; - } - - case SYSCALL_FSTAT: - { - Shared_pointer io = _lookup_channel(_sysio.fstat_in.fd); - - result = io->fstat(&_sysio); - - if (result) { - Sysio::Path path; - - /** - * Only actual fd's are valid fstat targets. - */ - if (io->path(path, sizeof (path))) { - size_t path_len = strlen(path); - uint32_t path_hash = hash_path(path, path_len); - - _sysio.stat_out.st.inode = path_hash; - } - } - - break; - } - - case SYSCALL_FCNTL: - - if (_sysio.fcntl_in.cmd == Sysio::FCNTL_CMD_SET_FD_FLAGS) { - - /* we assume that there is only the close-on-execve flag */ - _lookup_channel(_sysio.fcntl_in.fd)->close_on_execve = - !!_sysio.fcntl_in.long_arg; - result = true; - break; - } - - result = _lookup_channel(_sysio.fcntl_in.fd)->fcntl(&_sysio); - break; - - case SYSCALL_OPEN: - { - Vfs::Vfs_handle *vfs_handle = 0; - _sysio.error.open = _root_dir.open(_sysio.open_in.path, - _sysio.open_in.mode, - &vfs_handle, - *Genode::env()->heap()); - if (!vfs_handle) - break; - - char const *leaf_path = _root_dir.leaf_path(_sysio.open_in.path); - - /* - * File descriptors of opened directories are handled by - * '_root_dir'. In this case, we use the absolute path as leaf - * path because path operations always refer to the global - * root. - */ - if (&vfs_handle->ds() == &_root_dir) - leaf_path = _sysio.open_in.path; - - Shared_pointer - channel(new Vfs_io_channel(_sysio.open_in.path, - leaf_path, &_root_dir, - vfs_handle, _sig_rec), - Genode::env()->heap()); - - _sysio.open_out.fd = add_io_channel(channel); - result = true; - break; - } - - case SYSCALL_CLOSE: - { - remove_io_channel(_sysio.close_in.fd); - result = true; - break; - } - - case SYSCALL_IOCTL: - - result = _lookup_channel(_sysio.ioctl_in.fd)->ioctl(&_sysio); - break; - - case SYSCALL_LSEEK: - - result = _lookup_channel(_sysio.lseek_in.fd)->lseek(&_sysio); - break; - - case SYSCALL_DIRENT: - - result = _lookup_channel(_sysio.dirent_in.fd)->dirent(&_sysio); - break; - - case SYSCALL_EXECVE: - { - /* - * We have to check the dataspace twice because the binary - * could be a script that uses an interpreter which maybe - * does not exist. - */ - Dataspace_capability binary_ds = - _root_dir.dataspace(_sysio.execve_in.filename); - - if (!binary_ds.valid()) { - _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; - break; - } - - Child_env - child_env(_sysio.execve_in.filename, binary_ds, - _sysio.execve_in.args, _sysio.execve_in.env); - - _root_dir.release(_sysio.execve_in.filename, binary_ds); - - binary_ds = _root_dir.dataspace(child_env.binary_name()); - - if (!binary_ds.valid()) { - _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; - break; - } - - _root_dir.release(child_env.binary_name(), binary_ds); - - try { - _parent_execve.execve_child(*this, - child_env.binary_name(), - child_env.args(), - child_env.env(), - verbose); - - /* - * 'return' instead of 'break' to skip possible signal delivery, - * which might cause the old child process to exit itself - */ - return true; - } - catch (Child::Binary_does_not_exist) { - _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; } - catch (Child::Insufficient_memory) { - _sysio.error.execve = Sysio::EXECVE_NOMEM; } - - break; - } - - case SYSCALL_SELECT: - { - size_t in_fds_total = _sysio.select_in.fds.total_fds(); - Sysio::Select_fds in_fds; - for (Genode::size_t i = 0; i < in_fds_total; i++) - in_fds.array[i] = _sysio.select_in.fds.array[i]; - in_fds.num_rd = _sysio.select_in.fds.num_rd; - in_fds.num_wr = _sysio.select_in.fds.num_wr; - in_fds.num_ex = _sysio.select_in.fds.num_ex; - - int _rd_array[in_fds_total]; - int _wr_array[in_fds_total]; - - long timeout_sec = _sysio.select_in.timeout.sec; - long timeout_usec = _sysio.select_in.timeout.usec; - bool timeout_reached = false; - - /* reset the blocker lock to the 'locked' state */ - _blocker.unlock(); - _blocker.lock(); - - /* - * Register ourself at all watched I/O channels - * - * We instantiate as many notifiers as we have file - * descriptors to observe. Each notifier is associated - * with the child's blocking semaphore. When any of the - * notifiers get woken up, the semaphore gets unblocked. - * - * XXX However, the blocker may get unblocked for other - * conditions such as the destruction of the child. - * ...to be done. - */ - - Wake_up_notifier notifiers[in_fds_total]; - - for (Genode::size_t i = 0; i < in_fds_total; i++) { - int fd = in_fds.array[i]; - if (!fd_in_use(fd)) continue; - - Shared_pointer io = io_channel_by_fd(fd); - notifiers[i].lock = &_blocker; - - io->register_wake_up_notifier(¬ifiers[i]); - } - - /** - * Register ourself at the Io_receptor_registry - * - * Each entry in the registry will be unblocked if an external - * event has happend, e.g. network I/O. - */ - - Io_receptor receptor(&_blocker); - io_receptor_registry()->register_receptor(&receptor); - - - /* - * Block for one action of the watched file descriptors - */ - for (;;) { - - /* - * Check I/O channels of specified file descriptors for - * unblock condition. Return if one I/O channel satisfies - * the condition. - */ - size_t unblock_rd = 0; - size_t unblock_wr = 0; - size_t unblock_ex = 0; - - /* process read fds */ - for (Genode::size_t i = 0; i < in_fds_total; i++) { - - int fd = in_fds.array[i]; - if (!fd_in_use(fd)) continue; - - Shared_pointer io = io_channel_by_fd(fd); - - if (in_fds.watch_for_rd(i)) - if (io->check_unblock(true, false, false)) { - _rd_array[unblock_rd++] = fd; - } - if (in_fds.watch_for_wr(i)) - if (io->check_unblock(false, true, false)) { - _wr_array[unblock_wr++] = fd; - } - if (in_fds.watch_for_ex(i)) - if (io->check_unblock(false, false, true)) { - unblock_ex++; - } - } - - if (unblock_rd || unblock_wr || unblock_ex) { - /** - * Merge the fd arrays in one output array - */ - for (size_t i = 0; i < unblock_rd; i++) { - _sysio.select_out.fds.array[i] = _rd_array[i]; - } - _sysio.select_out.fds.num_rd = unblock_rd; - - /* XXX could use a pointer to select_out.fds.array instead */ - for (size_t j = unblock_rd, i = 0; i < unblock_wr; i++, j++) { - _sysio.select_out.fds.array[j] = _wr_array[i]; - } - _sysio.select_out.fds.num_wr = unblock_wr; - - /* exception fds are currently not considered */ - _sysio.select_out.fds.num_ex = unblock_ex; - - result = true; - break; - } - - /* - * Return if timeout is zero or timeout exceeded - */ - - if (_sysio.select_in.timeout.zero() || timeout_reached) { - /* - if (timeout_reached) log("timeout_reached"); - else log("timeout.zero()"); - */ - _sysio.select_out.fds.num_rd = 0; - _sysio.select_out.fds.num_wr = 0; - _sysio.select_out.fds.num_ex = 0; - - result = true; - break; - } - - /* - * Return if signals are pending - */ - - if (!_pending_signals.empty()) { - _sysio.error.select = Sysio::SELECT_ERR_INTERRUPT; - break; - } - - /* - * Block at barrier except when reaching the timeout - */ - - if (!_sysio.select_in.timeout.infinite()) { - unsigned long to_msec = (timeout_sec * 1000) + (timeout_usec / 1000); - Timeout_state ts; - Timeout_alarm ta(&ts, &_blocker, Noux::timeout_scheduler(), to_msec); - - /* block until timeout is reached or we were unblocked */ - _blocker.lock(); - - if (ts.timed_out) { - timeout_reached = 1; - } - else { - /* - * We woke up before reaching the timeout, - * so we discard the alarm - */ - ta.discard(); - } - } - else { - /* let's block infinitely */ - _blocker.lock(); - } - - } - - /* - * Unregister barrier at watched I/O channels - */ - for (Genode::size_t i = 0; i < in_fds_total; i++) { - int fd = in_fds.array[i]; - if (!fd_in_use(fd)) continue; - - Shared_pointer io = io_channel_by_fd(fd); - io->unregister_wake_up_notifier(¬ifiers[i]); - } - - /* - * Unregister receptor - */ - io_receptor_registry()->unregister_receptor(&receptor); - - break; - } - - case SYSCALL_FORK: - { - Genode::addr_t ip = _sysio.fork_in.ip; - Genode::addr_t sp = _sysio.fork_in.sp; - Genode::addr_t parent_cap_addr = _sysio.fork_in.parent_cap_addr; - - int const new_pid = pid_allocator()->alloc(); - Child * child = nullptr; - - try { - /* - * XXX To ease debugging, it would be useful to generate a - * unique name that includes the PID instead of just - * reusing the name of the parent. - */ - child = new Child(_child_policy.name(), - this, - _kill_broadcaster, - *this, - new_pid, - _sig_rec, - _root_dir, - _args, - _env.env(), - _env_pd_session, - _ref_ram, _ref_ram_cap, - _parent_services, - _ep, - true, - *env()->heap(), - _destruct_queue, - verbose); - } catch (Child::Insufficient_memory) { - _sysio.error.fork = Sysio::FORK_NOMEM; - break; - } - - Family_member::insert(child); - - _assign_io_channels_to(child); - - /* copy our address space into the new child */ - try { - _pd.replay(child->ram(), child->pd(), - child->ds_registry(), _ep); - - /* start executing the main thread of the new process */ - child->start_forked_main_thread(ip, sp, parent_cap_addr); - - /* activate child entrypoint, thereby starting the new process */ - child->start(); - - _sysio.fork_out.pid = new_pid; - - result = true; - } - catch (Region_map::Region_conflict) { - error("region conflict while replaying the address space"); } - - break; - } - - case SYSCALL_GETPID: - { - _sysio.getpid_out.pid = pid(); - return true; - } - - case SYSCALL_WAIT4: - { - Family_member *exited = _sysio.wait4_in.nohang ? poll4() : wait4(); - - if (exited) { - _sysio.wait4_out.pid = exited->pid(); - _sysio.wait4_out.status = exited->exit_status(); - Family_member::remove(exited); - - if (verbose) - log("submit exit signal for PID ", exited->pid()); - static_cast(exited)->submit_exit_signal(); - - } else { - if (_sysio.wait4_in.nohang) { - _sysio.wait4_out.pid = 0; - _sysio.wait4_out.status = 0; - } else { - _sysio.error.wait4 = Sysio::WAIT4_ERR_INTERRUPT; - break; - } - } - result = true; - break; - } - - case SYSCALL_PIPE: - { - Shared_pointer pipe(new Pipe, Genode::env()->heap()); - - Shared_pointer pipe_sink(new Pipe_sink_io_channel(pipe, _sig_rec), - Genode::env()->heap()); - Shared_pointer pipe_source(new Pipe_source_io_channel(pipe, _sig_rec), - Genode::env()->heap()); - - _sysio.pipe_out.fd[0] = add_io_channel(pipe_source); - _sysio.pipe_out.fd[1] = add_io_channel(pipe_sink); - - result = true; - break; - } - - case SYSCALL_DUP2: - { - int fd = add_io_channel(io_channel_by_fd(_sysio.dup2_in.fd), - _sysio.dup2_in.to_fd); - - _sysio.dup2_out.fd = fd; - - result = true; - break; - } - - case SYSCALL_UNLINK: - - _sysio.error.unlink = _root_dir.unlink(_sysio.unlink_in.path); - - result = (_sysio.error.unlink == Vfs::Directory_service::UNLINK_OK); - break; - - case SYSCALL_READLINK: - { - Vfs::file_size out_count = 0; - - _sysio.error.readlink = - _root_dir.readlink(_sysio.readlink_in.path, - _sysio.readlink_out.chunk, - min(_sysio.readlink_in.bufsiz, - sizeof(_sysio.readlink_out.chunk)), - out_count); - - _sysio.readlink_out.count = out_count; - - result = (_sysio.error.readlink == Vfs::Directory_service::READLINK_OK); - break; - } - - case SYSCALL_RENAME: - - _sysio.error.rename = _root_dir.rename(_sysio.rename_in.from_path, - _sysio.rename_in.to_path); - - result = (_sysio.error.rename == Vfs::Directory_service::RENAME_OK); - break; - - case SYSCALL_MKDIR: - - _sysio.error.mkdir = _root_dir.mkdir(_sysio.mkdir_in.path, 0); - - result = (_sysio.error.mkdir == Vfs::Directory_service::MKDIR_OK); - break; - - case SYSCALL_SYMLINK: - - _sysio.error.symlink = _root_dir.symlink(_sysio.symlink_in.oldpath, - _sysio.symlink_in.newpath); - - result = (_sysio.error.symlink == Vfs::Directory_service::SYMLINK_OK); - break; - - case SYSCALL_USERINFO: - { - if (_sysio.userinfo_in.request == Sysio::USERINFO_GET_UID - || _sysio.userinfo_in.request == Sysio::USERINFO_GET_GID) { - _sysio.userinfo_out.uid = Noux::user_info()->uid; - _sysio.userinfo_out.gid = Noux::user_info()->gid; - - result = true; - break; - } - - /* - * Since NOUX supports exactly one user, return false if we - * got a unknown uid. - */ - if (_sysio.userinfo_in.uid != Noux::user_info()->uid) - break; - - Genode::memcpy(_sysio.userinfo_out.name, - Noux::user_info()->name, - sizeof(Noux::user_info()->name)); - Genode::memcpy(_sysio.userinfo_out.shell, - Noux::user_info()->shell, - sizeof(Noux::user_info()->shell)); - Genode::memcpy(_sysio.userinfo_out.home, - Noux::user_info()->home, - sizeof(Noux::user_info()->home)); - - _sysio.userinfo_out.uid = user_info()->uid; - _sysio.userinfo_out.gid = user_info()->gid; - - result = true; - break; - } - - case SYSCALL_GETTIMEOFDAY: - { - /** - * Since the timeout_scheduler thread is started after noux it - * basicly returns the eleapsed time since noux was started. We - * abuse this timer to provide a more useful implemenation of - * gettimeofday() to make certain programs (e.g. ping(1)) happy. - * Note: this is just a short-term solution because Genode currently - * lacks a proper time interface (there is a RTC driver however, but - * there is no interface for it). - */ - unsigned long time = Noux::timeout_scheduler()->curr_time(); - - _sysio.gettimeofday_out.sec = (time / 1000); - _sysio.gettimeofday_out.usec = (time % 1000) * 1000; - - result = true; - break; - } - - case SYSCALL_CLOCK_GETTIME: - { - /** - * It's the same procedure as in SYSCALL_GETTIMEOFDAY. - */ - unsigned long time = Noux::timeout_scheduler()->curr_time(); - - switch (_sysio.clock_gettime_in.clock_id) { - - /* CLOCK_SECOND is used by time(3) in the libc. */ - case Sysio::CLOCK_ID_SECOND: - { - _sysio.clock_gettime_out.sec = (time / 1000); - _sysio.clock_gettime_out.nsec = 0; - - result = true; - break; - } - - default: - { - _sysio.clock_gettime_out.sec = 0; - _sysio.clock_gettime_out.nsec = 0; - _sysio.error.clock = Sysio::CLOCK_ERR_INVALID; - - break; - } - - } - - break; - - } - - case SYSCALL_UTIMES: - { - /** - * This systemcall is currently not implemented because we lack - * the needed mechanisms in most file-systems. - * - * But we return true anyway to keep certain programs, e.g. make - * happy. - */ - result = true; - break; - } - - case SYSCALL_SYNC: - { - _root_dir.sync("/"); - result = true; - break; - } - - case SYSCALL_KILL: - { - if (_kill_broadcaster.kill(_sysio.kill_in.pid, - _sysio.kill_in.sig)) - result = true; - else - _sysio.error.kill = Sysio::KILL_ERR_SRCH; - - break; - } - - case SYSCALL_GETDTABLESIZE: - { - _sysio.getdtablesize_out.n = - Noux::File_descriptor_registry::MAX_FILE_DESCRIPTORS; - result = true; - break; - } - - case SYSCALL_SOCKET: - case SYSCALL_GETSOCKOPT: - case SYSCALL_SETSOCKOPT: - case SYSCALL_ACCEPT: - case SYSCALL_BIND: - case SYSCALL_LISTEN: - case SYSCALL_SEND: - case SYSCALL_SENDTO: - case SYSCALL_RECV: - case SYSCALL_RECVFROM: - case SYSCALL_GETPEERNAME: - case SYSCALL_SHUTDOWN: - case SYSCALL_CONNECT: - - result = _syscall_net(sc); - break; - - case SYSCALL_INVALID: break; - } - } - - catch (Invalid_fd) { - _sysio.error.general = Vfs::Directory_service::ERR_FD_INVALID; - error("invalid file descriptor"); } - - catch (...) { error("unexpected exception"); } - - /* handle signals which might have occured */ - while (!_pending_signals.empty() && - (_sysio.pending_signals.avail_capacity() > 0)) { - _sysio.pending_signals.add(_pending_signals.get()); - } - - return result; -} - - -/** - * Return name of init process as specified in the config - */ -static Genode::Child_policy::Name name_of_init_process(Genode::Xml_node config) -{ - return config.sub_node("start").attribute_value("name", Genode::Child_policy::Name()); -} - - -/** - * Read command-line arguments of init process from config - */ -static Noux::Args const &args_of_init_process(Genode::Xml_node config) -{ - static char args_buf[4096]; - static Noux::Args args(args_buf, sizeof(args_buf)); - - Genode::Xml_node start_node = config.sub_node("start"); - - try { - /* the first argument is the program name */ - args.append(name_of_init_process(config).string()); - - Genode::Xml_node arg_node = start_node.sub_node("arg"); - for (; ; arg_node = arg_node.next("arg")) { - typedef Genode::String<512> Value; - args.append(arg_node.attribute_value("value", Value()).string()); - } - } - catch (Genode::Xml_node::Nonexistent_sub_node) { } - catch (Noux::Args::Overrun) { Genode::error("argument buffer overrun"); } - - return args; + static Noux::Io_receptor_registry _inst; + return &_inst; } @@ -985,52 +85,19 @@ static Noux::Sysio::Env &env_string_of_init_process(Genode::Xml_node config) } -Noux::Pid_allocator *Noux::pid_allocator() -{ - static Noux::Pid_allocator inst; - return &inst; -} - - -Noux::Timeout_scheduler *Noux::timeout_scheduler() -{ - static Noux::Timeout_scheduler inst(0); - return &inst; -} - - -Noux::User_info* Noux::user_info() -{ - static Noux::User_info inst; - return &inst; -} - - -Noux::Io_receptor_registry * Noux::io_receptor_registry() -{ - static Noux::Io_receptor_registry _inst; - return &_inst; -} - - -Terminal::Connection *Noux::terminal() -{ - static Terminal::Connection _inst; - return &_inst; -} - - -class Stdio_unavailable : Genode::Exception { }; +namespace Noux { class Stdio_unavailable : Genode::Exception { }; } /* * \throw Stdio_unavailable */ -static Noux::Io_channel &connect_stdio(Genode::Xml_node config, - Vfs::Dir_file_system &root, - Noux::Terminal_io_channel::Type type, - Genode::Signal_receiver &sig_rec, - Genode::Allocator &alloc) +static Noux::Io_channel & +connect_stdio(Genode::Env &env, + Genode::Constructible &terminal, + Genode::Xml_node config, + Vfs::Dir_file_system &root, + Noux::Terminal_io_channel::Type type, + Genode::Allocator &alloc) { using namespace Vfs; using namespace Noux; @@ -1057,8 +124,10 @@ static Noux::Io_channel &connect_stdio(Genode::Xml_node config, }; if (!config.has_attribute(stdio_name)) { + if (!terminal.constructed()) + terminal.construct(env); warning(stdio_name, " VFS path not defined, connecting to terminal session"); - return *new (alloc) Tio(*Noux::terminal(), type, sig_rec); + return *new (alloc) Tio(*terminal, type, env.ep()); } Path const path = config.attribute_value(stdio_name, Path()); @@ -1071,7 +140,8 @@ static Noux::Io_channel &connect_stdio(Genode::Xml_node config, } return *new (alloc) - Vfs_io_channel(path.string(), root.leaf_path(path.string()), &root, vfs_handle, sig_rec); + Vfs_io_channel(path.string(), root.leaf_path(path.string()), &root, + vfs_handle, env.ep()); } @@ -1089,96 +159,85 @@ Genode::Lock &Noux::signal_lock() } -void *operator new (__SIZE_TYPE__ size) +namespace Noux { struct Main; } + + +struct Noux::Main { - void * ptr = Genode::env()->heap()->alloc(size); - if (!ptr) - return ptr; + Env &_env; - Genode::memset(ptr, 0, size); - return ptr; -} - - -void operator delete (void * ptr) -{ - if (Genode::env()->heap()->need_size_for_free()) { - Genode::warning("leaking memory"); - return; - } - - Genode::env()->heap()->free(ptr, 0); -} - - -template -struct File_system_factory : Vfs::File_system_factory -{ - Vfs::File_system *create(Genode::Env &env, Genode::Allocator &alloc, - Genode::Xml_node node) - { - return new FILE_SYSTEM(env, alloc, node); - } -}; - - -/** - * XXX: only a partial conversion from `int main(...)` to `void construct(...)` - */ -void Component::construct(Genode::Env &env) -{ - using namespace Noux; - log("--- noux started ---"); + Heap _heap { _env.ram(), _env.rm() }; /* whitelist of service requests to be routed to the parent */ - static Noux::Parent_services parent_services; - char const *service_names[] = { "LOG", "ROM", "Timer", 0 }; - for (unsigned i = 0; service_names[i]; i++) - new Noux::Parent_service(parent_services, service_names[i]); + Noux::Parent_services _parent_services; - static Genode::Attached_rom_dataspace config(env, "config"); + Noux::Parent_service _log_parent_service { _parent_services, "LOG" }; + Noux::Parent_service _timer_parent_service { _parent_services, "Timer" }; - static Genode::Heap heap(env.ram(), env.rm()); + Attached_rom_dataspace _config { _env, "config" }; - /* obtain global configuration */ - trace_syscalls = config.xml().attribute_value("trace_syscalls", trace_syscalls); - verbose = config.xml().attribute_value("verbose", verbose); + Verbose _verbose { _config.xml() }; - /* register additional file systems to the VFS */ - Vfs::Global_file_system_factory &fs_factory = Vfs::global_file_system_factory(); + /** + * Return name of init process as specified in the config + */ + Child_policy::Name _name_of_init_process() const + { + return _config.xml().sub_node("start").attribute_value("name", Child_policy::Name()); + } - File_system_factory stdio_file_system_factory; - File_system_factory random_file_system_factory; + /** + * Read command-line arguments of init process from config + */ + Args const &_args_of_init_process() + { + static char args_buf[4096]; + static Args args(args_buf, sizeof(args_buf)); - fs_factory.extend("stdio", stdio_file_system_factory); - fs_factory.extend("random", random_file_system_factory); + Xml_node start_node = _config.xml().sub_node("start"); + try { + /* the first argument is the program name */ + args.append(_name_of_init_process().string()); + + start_node.for_each_sub_node("arg", [&] (Xml_node arg_node) { + typedef String<512> Value; + args.append(arg_node.attribute_value("value", Value()).string()); + }); + + } catch (Args::Overrun) { error("argument buffer overrun"); } + + return args; + } /* initialize virtual file system */ - static Vfs::Dir_file_system root_dir(env, heap, - config.xml().sub_node("fstab"), - fs_factory); + Vfs::Global_file_system_factory &_fs_factory = Vfs::global_file_system_factory(); - /* set user information */ - try { - user_info()->set_info(config.xml().sub_node("user")); + Vfs::Dir_file_system _root_dir { _env, _heap, _config.xml().sub_node("fstab"), + _fs_factory }; + + Pid_allocator _pid_allocator; + + Timeout_scheduler _timeout_scheduler { _env }; + + User_info _user_info { _config.xml() }; + + bool _network_initialized = (init_network(), true); + + Signal_handler
_destruct_handler { + _env.ep(), *this, &Main::_handle_destruct }; + + Destruct_queue _destruct_queue { _destruct_handler }; + + void _handle_destruct() + { + _destruct_queue.flush(); + + /* let noux exit if the init process exited */ + if (!init_child) + _env.parent().exit(exit_value); } - catch (...) { } - /* initialize network */ - init_network(); - - /* - * Entrypoint used to virtualize child resources such as RAM, RM - */ - enum { STACK_SIZE = 2*1024*sizeof(long) }; - static Genode::Rpc_entrypoint - resources_ep(&env.pd(), STACK_SIZE, "noux_rsc_ep"); - - /* create init process */ - static Genode::Signal_receiver sig_rec; - static Destruct_queue destruct_queue; - - struct Kill_broadcaster_implementation : Kill_broadcaster + struct Kill_broadcaster_impl: Kill_broadcaster { Family_member *init_process = nullptr; @@ -1186,77 +245,63 @@ void Component::construct(Genode::Env &env) { return init_process->deliver_kill(pid, sig); } - }; - static Dataspace_registry ref_ram_ds_registry; - static Ram_session_component ref_ram(resources_ep, ref_ram_ds_registry); + } _kill_broadcaster; - static Kill_broadcaster_implementation kill_broadcaster; + Dataspace_registry _ref_ram_ds_registry { _heap }; + Ram_session_component _ref_ram { _env.ram(), _heap, _env.ep().rpc_ep(), _ref_ram_ds_registry }; - init_child = new Noux::Child(name_of_init_process(config.xml()), - 0, - kill_broadcaster, - *init_child, - pid_allocator()->alloc(), - sig_rec, - root_dir, - args_of_init_process(config.xml()), - env_string_of_init_process(config.xml()), - env.pd(), - ref_ram, - Ram_session_capability(), - parent_services, - resources_ep, - false, - heap, - destruct_queue, - verbose); + Noux::Child _init_child { _name_of_init_process(), + _verbose, + _user_info, + 0, + _kill_broadcaster, + _timeout_scheduler, + _init_child, + _pid_allocator, + _pid_allocator.alloc(), + _env, + _root_dir, + _args_of_init_process(), + env_string_of_init_process(_config.xml()), + _heap, + _ref_ram, + Ram_session_capability(), + _parent_services, + false, + _destruct_queue }; - kill_broadcaster.init_process = init_child; + Constructible _terminal; /* * I/O channels must be dynamically allocated to handle cases where the * init program closes one of these. */ typedef Terminal_io_channel Tio; /* just a local abbreviation */ + Shared_pointer - channel_0(&connect_stdio(config.xml(), root_dir, Tio::STDIN, sig_rec, heap), &heap), - channel_1(&connect_stdio(config.xml(), root_dir, Tio::STDOUT, sig_rec, heap), &heap), - channel_2(&connect_stdio(config.xml(), root_dir, Tio::STDERR, sig_rec, heap), &heap); + _channel_0 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDIN, _heap), _heap }, + _channel_1 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDOUT, _heap), _heap }, + _channel_2 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDERR, _heap), _heap }; - init_child->add_io_channel(channel_0, 0); - init_child->add_io_channel(channel_1, 1); - init_child->add_io_channel(channel_2, 2); + Main(Env &env) : _env(env) + { + log("--- noux started ---"); - init_child->start(); + _init_child.add_io_channel(_channel_0, 0); + _init_child.add_io_channel(_channel_1, 1); + _init_child.add_io_channel(_channel_2, 2); - /* handle asynchronous events */ - while (init_child) { + _kill_broadcaster.init_process = &_init_child; - /* - * limit the scope of the 'Signal' object, so the signal context may - * get freed by the destruct queue - */ - { - Genode::Signal signal = sig_rec.wait_for_signal(); + init_child = &_init_child; - Signal_dispatcher_base *dispatcher = - static_cast(signal.context()); - - for (unsigned i = 0; i < signal.num(); i++) - dispatcher->dispatch(1); - } - - destruct_queue.flush(); - - if (verbose_quota) - log("quota: avail=", env.ram().avail(), " " - "used=", env.ram().used()); + _init_child.start(); } +}; - log("--- exiting noux ---"); - env.parent().exit(exit_value); -} + +void Component::construct(Genode::Env &env) { static Noux::Main main(env); } /** diff --git a/repos/ports/src/noux/minimal/target.mk b/repos/ports/src/noux/minimal/target.mk index a66945d250..7b82b0f327 100644 --- a/repos/ports/src/noux/minimal/target.mk +++ b/repos/ports/src/noux/minimal/target.mk @@ -1,8 +1,9 @@ TARGET = noux LIBS = alarm vfs -SRC_CC = main.cc dummy_net.cc +SRC_CC = main.cc syscall.cc dummy_net.cc INC_DIR += $(PRG_DIR) INC_DIR += $(PRG_DIR)/../ vpath main.cc $(PRG_DIR)/.. +vpath syscall.cc $(PRG_DIR)/.. vpath dummy_net.cc $(PRG_DIR) diff --git a/repos/ports/src/noux/net/net.cc b/repos/ports/src/noux/net/net.cc index 78b33a0528..2063c4e7bf 100644 --- a/repos/ports/src/noux/net/net.cc +++ b/repos/ports/src/noux/net/net.cc @@ -72,6 +72,7 @@ void init_network() libc_select_notify = select_notify; } + /********************************* ** Noux net syscall dispatcher ** *********************************/ @@ -117,16 +118,16 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) break; case SYSCALL_SOCKET: { - Socket_io_channel *socket_io_channel = new Socket_io_channel(); + Socket_io_channel *socket_io_channel = new (_heap) Socket_io_channel(); GET_SOCKET_IO_CHANNEL_BACKEND(socket_io_channel->backend(), backend); - if (!backend->socket(&_sysio)) { + if (!backend->socket(_sysio)) { delete socket_io_channel; return false; } - Shared_pointer io_channel(socket_io_channel, Genode::env()->heap()); + Shared_pointer io_channel(socket_io_channel, _heap); _sysio.socket_out.fd = add_io_channel(io_channel); @@ -138,7 +139,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return backend->getsockopt(&_sysio); + return backend->getsockopt(_sysio); } case SYSCALL_SETSOCKOPT: { @@ -146,7 +147,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return backend->setsockopt(&_sysio); + return backend->setsockopt(_sysio); } case SYSCALL_ACCEPT: { @@ -154,12 +155,12 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - int socket = backend->accept(&_sysio); + int socket = backend->accept(_sysio); if (socket == -1) return false; - Socket_io_channel *socket_io_channel = new Socket_io_channel(socket); - Shared_pointer io_channel(socket_io_channel, Genode::env()->heap()); + Socket_io_channel *socket_io_channel = new (_heap) Socket_io_channel(socket); + Shared_pointer io_channel(socket_io_channel, _heap); _sysio.accept_out.fd = add_io_channel(io_channel); @@ -171,7 +172,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->bind(&_sysio) == -1) ? false : true; + return (backend->bind(_sysio) == -1) ? false : true; } case SYSCALL_LISTEN: { @@ -179,7 +180,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->listen(&_sysio) == -1) ? false : true; + return (backend->listen(_sysio) == -1) ? false : true; } case SYSCALL_SEND: { @@ -187,7 +188,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->send(&_sysio) == -1) ? false : true; + return (backend->send(_sysio) == -1) ? false : true; } case SYSCALL_SENDTO: { @@ -195,7 +196,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->sendto(&_sysio) == -1) ? false : true; + return (backend->sendto(_sysio) == -1) ? false : true; } case SYSCALL_RECV: { @@ -203,7 +204,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->recv(&_sysio) == -1) ? false : true; + return (backend->recv(_sysio) == -1) ? false : true; } case SYSCALL_RECVFROM: { @@ -211,7 +212,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->recvfrom(&_sysio) == -1) ? false : true; + return (backend->recvfrom(_sysio) == -1) ? false : true; } case SYSCALL_GETPEERNAME: { @@ -219,7 +220,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->getpeername(&_sysio) == -1) ? false : true; + return (backend->getpeername(_sysio) == -1) ? false : true; } case SYSCALL_SHUTDOWN: { @@ -227,7 +228,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->shutdown(&_sysio) == -1) ? false : true; + return (backend->shutdown(_sysio) == -1) ? false : true; } case SYSCALL_CONNECT: { @@ -235,7 +236,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return (backend->connect(&_sysio) == -1) ? false : true; + return (backend->connect(_sysio) == -1) ? false : true; } } diff --git a/repos/ports/src/noux/net/socket_io_channel.h b/repos/ports/src/noux/net/socket_io_channel.h index ab8a669a08..2e9d5610a9 100644 --- a/repos/ports/src/noux/net/socket_io_channel.h +++ b/repos/ports/src/noux/net/socket_io_channel.h @@ -32,492 +32,470 @@ #include #include - namespace Noux { + class Socket_io_channel_backend; + class Socket_io_channel; +} - class Socket_io_channel_backend : public Io_channel_backend - { - private: - int _socket; +class Noux::Socket_io_channel_backend : public Io_channel_backend +{ + private: - public: + int _socket; - Socket_io_channel_backend() - : - _socket(-1) - { } + public: - Socket_io_channel_backend(int s) - : - _socket(s) - { } + Socket_io_channel_backend() + : + _socket(-1) + { } - ~Socket_io_channel_backend() - { - if (_socket != -1) { - ::shutdown(_socket, SHUT_RDWR); - ::close(_socket); - } + Socket_io_channel_backend(int s) + : + _socket(s) + { } + + ~Socket_io_channel_backend() + { + if (_socket != -1) { + ::shutdown(_socket, SHUT_RDWR); + ::close(_socket); } + } - int type() const { return 1; } + int type() const { return 1; } - int socket() const { return _socket; } + int socket() const { return _socket; } - /** - * Io_channel interface implementation (only needed methods) - */ + /** + * Io_channel interface implementation (only needed methods) + */ - bool write(Sysio *sysio, ::size_t &count) - { - ssize_t result = ::write(_socket, sysio->write_in.chunk, - sysio->write_in.count); + bool write(Sysio &sysio, ::size_t &count) + { + ssize_t result = ::write(_socket, sysio.write_in.chunk, + sysio.write_in.count); - if (result > -1) { - sysio->write_out.count = result; - count = result; + if (result > -1) { + sysio.write_out.count = result; + count = result; - return true; - } - - switch (errno) { - /* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break; - case EINVAL: sysio->error.read = Vfs::File_io_service::READ_ERR_INVALID; break; - case EIO: sysio->error.read = Vfs::File_io_service::READ_ERR_IO; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - - return false; - } - - bool read(Sysio *sysio) - { - ::size_t const max_count = Genode::min(sysio->read_in.count, sizeof(sysio->read_out.chunk)); - - ssize_t result = ::read(_socket, sysio->read_out.chunk, max_count); - - if (result > -1) { - sysio->read_out.count = result; - return true; - } - - switch (errno) { - /* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break; - case EINVAL: sysio->error.read = Vfs::File_io_service::READ_ERR_INVALID; break; - case EIO: sysio->error.read = Vfs::File_io_service::READ_ERR_IO; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - - return false; - } - - bool fcntl(Sysio *sysio) - { - int cmd = -1; - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: cmd = F_GETFL; break; - case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: cmd = F_SETFL; break; - default: - log("invalid fcntl command: ", (int)sysio->fcntl_in.cmd); - sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; - return false; - } - - int result = ::fcntl(_socket, cmd, sysio->fcntl_in.long_arg); - - sysio->fcntl_out.result = result; return true; } - bool dirent(Sysio *sysio) { return false; } - - bool ioctl(Sysio *sysio) - { - int request; - - switch (sysio->ioctl_in.request) { - - case Vfs::File_io_service::IOCTL_OP_FIONBIO: request = FIONBIO; break; - default: - log(__func__, ": invalid ioctl request: ", (int)sysio->ioctl_in.request); - return false; - } - int result = ::ioctl(_socket, request, NULL); - - return result ? false : true; + switch (errno) { + /* case EAGAIN: sysio.error.read = Sysio::READ_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break; + case EINVAL: sysio.error.read = Vfs::File_io_service::READ_ERR_INVALID; break; + case EIO: sysio.error.read = Vfs::File_io_service::READ_ERR_IO; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; } - bool check_unblock(bool rd, bool wr, bool ex) const - { - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - int ready; + return false; + } - /** - * The timeout will be overriden in libc's select() function - * but we still need a valid pointer because libc's select() - * will block forever otherwise. - */ - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - - FD_SET(_socket, &readfds); - FD_SET(_socket, &writefds); - FD_SET(_socket, &exceptfds); + bool read(Sysio &sysio) + { + ::size_t const max_count = Genode::min(sysio.read_in.count, sizeof(sysio.read_out.chunk)); - ready = ::select(_socket + 1, &readfds, &writefds, &exceptfds, &timeout); - - if (ready > 0) { - if (rd) { - if (FD_ISSET(_socket, &readfds)) - return true; - } + ssize_t result = ::read(_socket, sysio.read_out.chunk, max_count); - if (wr) { - if (FD_ISSET(_socket, &writefds)) - return true; - } + if (result > -1) { + sysio.read_out.count = result; + return true; + } - if (ex) { - if (FD_ISSET(_socket, &exceptfds)) - return true; - } - } + switch (errno) { + /* case EAGAIN: sysio.error.read = Sysio::READ_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break; + case EINVAL: sysio.error.read = Vfs::File_io_service::READ_ERR_INVALID; break; + case EIO: sysio.error.read = Vfs::File_io_service::READ_ERR_IO; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } - /** - * HACK: Since lwip won't mark fds as writable, even if they - * are, if asked multiple times we return true in this - * case. Hopefully that won't break any time soon. - */ - if (wr) - return true; + return false; + } + bool fcntl(Sysio &sysio) + { + int cmd = -1; + switch (sysio.fcntl_in.cmd) { + + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: cmd = F_GETFL; break; + case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: cmd = F_SETFL; break; + default: + log("invalid fcntl command: ", (int)sysio.fcntl_in.cmd); + sysio.error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; return false; } + int result = ::fcntl(_socket, cmd, sysio.fcntl_in.long_arg); + + sysio.fcntl_out.result = result; + return true; + } + + bool dirent(Sysio &sysio) { return false; } + + bool ioctl(Sysio &sysio) + { + int request; + + switch (sysio.ioctl_in.request) { + + case Vfs::File_io_service::IOCTL_OP_FIONBIO: request = FIONBIO; break; + default: + log(__func__, ": invalid ioctl request: ", (int)sysio.ioctl_in.request); + return false; + } + int result = ::ioctl(_socket, request, NULL); + + return result ? false : true; + } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + int ready; + /** - * Socket methods + * The timeout will be overriden in libc's select() function + * but we still need a valid pointer because libc's select() + * will block forever otherwise. */ + struct timeval timeout = { 0, 0 }; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + FD_SET(_socket, &readfds); + FD_SET(_socket, &writefds); + FD_SET(_socket, &exceptfds); - int accept(Sysio *sysio) - { - int result; - - if (sysio->accept_in.addrlen == 0) { - result = ::accept(_socket, NULL, NULL); - } - else { - result = ::accept(_socket, (sockaddr *)&sysio->accept_in.addr, - &sysio->accept_in.addrlen); + ready = ::select(_socket + 1, &readfds, &writefds, &exceptfds, &timeout); + + if (ready > 0) { + if (rd) { + if (FD_ISSET(_socket, &readfds)) + return true; } - if (result == -1) { - switch (errno) { - /* case EAGAIN: sysio->error.accept = Sysio::ACCEPT_ERR_AGAIN; break; */ - case ENOMEM: sysio->error.accept = Sysio::ACCEPT_ERR_NO_MEMORY; break; - case EINVAL: sysio->error.accept = Sysio::ACCEPT_ERR_INVALID; break; - case EOPNOTSUPP: sysio->error.accept = Sysio::ACCEPT_ERR_NOT_SUPPORTED; break; - case EWOULDBLOCK: sysio->error.accept = Sysio::ACCEPT_ERR_WOULD_BLOCK; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } + if (wr) { + if (FD_ISSET(_socket, &writefds)) + return true; } - return result; - } - - int bind(Sysio *sysio) - { - int result = ::bind(_socket, (const struct sockaddr *)&sysio->bind_in.addr, - sysio->bind_in.addrlen); - - if (result == -1) { - switch (errno) { - case EACCES: sysio->error.bind = Sysio::BIND_ERR_ACCESS; break; - case EADDRINUSE: sysio->error.bind = Sysio::BIND_ERR_ADDR_IN_USE; break; - case EINVAL: sysio->error.bind = Sysio::BIND_ERR_INVALID; break; - case ENOMEM: sysio->error.bind = Sysio::BIND_ERR_NO_MEMORY; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } + if (ex) { + if (FD_ISSET(_socket, &exceptfds)) + return true; } - - return result; - } - - int connect(Sysio *sysio) - { - int result = ::connect(_socket, (struct sockaddr *)&sysio->connect_in.addr, - sysio->connect_in.addrlen); - - if (result == -1) { - switch (errno) { - case EAGAIN: sysio->error.connect = Sysio::CONNECT_ERR_AGAIN; break; - case EALREADY: sysio->error.connect = Sysio::CONNECT_ERR_ALREADY; break; - case EADDRINUSE: sysio->error.connect = Sysio::CONNECT_ERR_ADDR_IN_USE; break; - case EINPROGRESS: sysio->error.connect = Sysio::CONNECT_ERR_IN_PROGRESS; break; - case EISCONN: sysio->error.connect = Sysio::CONNECT_ERR_IS_CONNECTED; break; - case ECONNRESET: sysio->error.connect = Sysio::CONNECT_ERR_RESET; break; - case ECONNABORTED: sysio->error.connect = Sysio::CONNECT_ERR_ABORTED; break; - case EHOSTUNREACH: sysio->error.connect = Sysio::CONNECT_ERR_NO_ROUTE; break; - - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - return result; - } - - int getpeername(Sysio *sysio) - { - return ::getpeername(_socket, (struct sockaddr *)&sysio->getpeername_in.addr, - (socklen_t *)&sysio->getpeername_in.addrlen); - } - - bool getsockopt(Sysio *sysio) - { - int result = ::getsockopt(_socket, sysio->getsockopt_in.level, - sysio->getsockopt_in.optname, - sysio->getsockopt_in.optval, - &sysio->getsockopt_in.optlen); - - return (result == -1) ? false : true; - } - - int listen(Sysio *sysio) - { - int result = ::listen(_socket, sysio->listen_in.backlog); - - if (result == -1) { - switch (errno) { - case EADDRINUSE: sysio->error.listen = Sysio::LISTEN_ERR_ADDR_IN_USE; break; - case EOPNOTSUPP: sysio->error.listen = Sysio::LISTEN_ERR_NOT_SUPPORTED; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - return result; - } - - ssize_t recv(Sysio *sysio) - { - ssize_t result = ::recv(_socket, sysio->recv_in.buf, sysio->recv_in.len, sysio->recv_in.flags); - - if (result == -1) { - switch (errno) { - /*case EAGAIN: sysio->error.recv = Sysio::RECV_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; - case EINVAL: sysio->error.recv = Sysio::RECV_ERR_INVALID; break; - case ENOTCONN: sysio->error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - sysio->recv_out.len = result; - - return result; - } - - ssize_t recvfrom(Sysio *sysio) - { - ssize_t result = ::recvfrom(_socket, sysio->recv_in.buf, sysio->recv_in.len, - sysio->recv_in.flags, (struct sockaddr *)&sysio->recvfrom_in.src_addr, - &sysio->recvfrom_in.addrlen); - - if (result == -1) { - switch (errno) { - /*case EAGAIN: sysio->error.recv = Sysio::RECV_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; - case EINVAL: sysio->error.recv = Sysio::RECV_ERR_INVALID; break; - case ENOTCONN: sysio->error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; - default: - log(__func__, " unhandled errno: ", (int)errno); - break; - } - } - - sysio->recvfrom_out.len = result; - - return result; - } - - bool setsockopt(Sysio *sysio) - { - /* - * Filter options out because lwip only supports several socket - * options. Therefore for now we silently return 0 and notify - * the user via debug message. - */ - switch (sysio->setsockopt_in.optname) { - case SO_DEBUG: - case SO_LINGER: - warning("SOL_SOCKET option '", sysio->setsockopt_in.optname, "' " - "is currently not supported, however we report success"); - return true; - } - - int result = ::setsockopt(_socket, sysio->setsockopt_in.level, - sysio->setsockopt_in.optname, - sysio->setsockopt_in.optval, - sysio->setsockopt_in.optlen); - - return (result == -1) ? false : true; - } - - ssize_t send(Sysio *sysio) - { - ssize_t result = ::send(_socket, sysio->send_in.buf, sysio->send_in.len, - sysio->send_in.flags); - - if (result == -1) { - switch (errno) { - /*case EAGAIN: sysio->error.send = Sysio::SEND_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; - case ECONNRESET: sysio->error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; - case EINVAL: sysio->error.send = Sysio::SEND_ERR_INVALID; break; - case EISCONN: sysio->error.send = Sysio::SEND_ERR_IS_CONNECTED; break; - case ENOMEM: sysio->error.send = Sysio::SEND_ERR_NO_MEMORY; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - sysio->send_out.len = result; - - return result; - } - - ssize_t sendto(Sysio *sysio) - { - ssize_t result = ::sendto(_socket, sysio->sendto_in.buf, sysio->sendto_in.len, - sysio->sendto_in.flags, - (const struct sockaddr *) &sysio->sendto_in.dest_addr, - sysio->sendto_in.addrlen); - - if (result == -1) { - switch (errno) { - /*case EAGAIN: sysio->error.send = Sysio::SEND_ERR_AGAIN; break; */ - case EWOULDBLOCK: sysio->error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; - case ECONNRESET: sysio->error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; - case EINVAL: sysio->error.send = Sysio::SEND_ERR_INVALID; break; - case EISCONN: sysio->error.send = Sysio::SEND_ERR_IS_CONNECTED; break; - case ENOMEM: sysio->error.send = Sysio::SEND_ERR_NO_MEMORY; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - sysio->sendto_out.len = result; - - return result; - } - - int shutdown(Sysio *sysio) - { - int result = ::shutdown(_socket, sysio->shutdown_in.how); - - if (result == -1) { - switch (errno) { - case ENOTCONN: sysio->error.shutdown = Sysio::SHUTDOWN_ERR_NOT_CONNECTED; break; - default: - log(__func__, ": unhandled errno: ", (int)errno); - break; - } - } - - return result; - } - - bool socket(Sysio *sysio) - { - _socket = ::socket(sysio->socket_in.domain, - sysio->socket_in.type, - sysio->socket_in.protocol); - - return (_socket == -1) ? false : true; - } - }; - - class Socket_io_channel : public Io_channel - { - private: - - - Socket_io_channel_backend *_backend; - - public: - - Socket_io_channel() - : - _backend(new (env()->heap()) Socket_io_channel_backend()) - { } - - Socket_io_channel(int s) - : - _backend(new (env()->heap()) Socket_io_channel_backend(s)) - { } - - ~Socket_io_channel() - { - destroy(env()->heap(), _backend); } /** - * Io_channel interface (only needed methods) + * HACK: Since lwip won't mark fds as writable, even if they + * are, if asked multiple times we return true in this + * case. Hopefully that won't break any time soon. */ + if (wr) + return true; - Io_channel_backend *backend() { return _backend; } + return false; + } - bool write(Sysio *sysio, ::size_t &count) - { - return _backend->write(sysio, count); + /** + * Socket methods + */ + + int accept(Sysio &sysio) + { + int result; + + if (sysio.accept_in.addrlen == 0) { + result = ::accept(_socket, NULL, NULL); + } + else { + result = ::accept(_socket, (sockaddr *)&sysio.accept_in.addr, + &sysio.accept_in.addrlen); } - bool read(Sysio *sysio) - { - return _backend->read(sysio); + if (result == -1) { + switch (errno) { + /* case EAGAIN: sysio.error.accept = Sysio::ACCEPT_ERR_AGAIN; break; */ + case ENOMEM: sysio.error.accept = Sysio::ACCEPT_ERR_NO_MEMORY; break; + case EINVAL: sysio.error.accept = Sysio::ACCEPT_ERR_INVALID; break; + case EOPNOTSUPP: sysio.error.accept = Sysio::ACCEPT_ERR_NOT_SUPPORTED; break; + case EWOULDBLOCK: sysio.error.accept = Sysio::ACCEPT_ERR_WOULD_BLOCK; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } } - bool fcntl(Sysio* sysio) - { - return _backend->fcntl(sysio); + return result; + } + + int bind(Sysio &sysio) + { + int result = ::bind(_socket, (const struct sockaddr *)&sysio.bind_in.addr, + sysio.bind_in.addrlen); + + if (result == -1) { + switch (errno) { + case EACCES: sysio.error.bind = Sysio::BIND_ERR_ACCESS; break; + case EADDRINUSE: sysio.error.bind = Sysio::BIND_ERR_ADDR_IN_USE; break; + case EINVAL: sysio.error.bind = Sysio::BIND_ERR_INVALID; break; + case ENOMEM: sysio.error.bind = Sysio::BIND_ERR_NO_MEMORY; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } } - bool ioctl(Sysio *sysio) - { - return _backend->ioctl(sysio); + return result; + } + + int connect(Sysio &sysio) + { + int result = ::connect(_socket, (struct sockaddr *)&sysio.connect_in.addr, + sysio.connect_in.addrlen); + + if (result == -1) { + switch (errno) { + case EAGAIN: sysio.error.connect = Sysio::CONNECT_ERR_AGAIN; break; + case EALREADY: sysio.error.connect = Sysio::CONNECT_ERR_ALREADY; break; + case EADDRINUSE: sysio.error.connect = Sysio::CONNECT_ERR_ADDR_IN_USE; break; + case EINPROGRESS: sysio.error.connect = Sysio::CONNECT_ERR_IN_PROGRESS; break; + case EISCONN: sysio.error.connect = Sysio::CONNECT_ERR_IS_CONNECTED; break; + case ECONNRESET: sysio.error.connect = Sysio::CONNECT_ERR_RESET; break; + case ECONNABORTED: sysio.error.connect = Sysio::CONNECT_ERR_ABORTED; break; + case EHOSTUNREACH: sysio.error.connect = Sysio::CONNECT_ERR_NO_ROUTE; break; + + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } } - bool check_unblock(bool rd, bool wr, bool ex) const - { - return _backend->check_unblock(rd, wr, ex); + return result; + } + + int getpeername(Sysio &sysio) + { + return ::getpeername(_socket, (struct sockaddr *)&sysio.getpeername_in.addr, + (socklen_t *)&sysio.getpeername_in.addrlen); + } + + bool getsockopt(Sysio &sysio) + { + int result = ::getsockopt(_socket, sysio.getsockopt_in.level, + sysio.getsockopt_in.optname, + sysio.getsockopt_in.optval, + &sysio.getsockopt_in.optlen); + + return (result == -1) ? false : true; + } + + int listen(Sysio &sysio) + { + int result = ::listen(_socket, sysio.listen_in.backlog); + + if (result == -1) { + switch (errno) { + case EADDRINUSE: sysio.error.listen = Sysio::LISTEN_ERR_ADDR_IN_USE; break; + case EOPNOTSUPP: sysio.error.listen = Sysio::LISTEN_ERR_NOT_SUPPORTED; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } } + return result; + } - }; -} + ssize_t recv(Sysio &sysio) + { + ssize_t result = ::recv(_socket, sysio.recv_in.buf, sysio.recv_in.len, sysio.recv_in.flags); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio.error.recv = Sysio::RECV_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; + case EINVAL: sysio.error.recv = Sysio::RECV_ERR_INVALID; break; + case ENOTCONN: sysio.error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } + } + + sysio.recv_out.len = result; + + return result; + } + + ssize_t recvfrom(Sysio &sysio) + { + ssize_t result = ::recvfrom(_socket, sysio.recv_in.buf, sysio.recv_in.len, + sysio.recv_in.flags, (struct sockaddr *)&sysio.recvfrom_in.src_addr, + &sysio.recvfrom_in.addrlen); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio.error.recv = Sysio::RECV_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; + case EINVAL: sysio.error.recv = Sysio::RECV_ERR_INVALID; break; + case ENOTCONN: sysio.error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; + default: + log(__func__, " unhandled errno: ", (int)errno); + break; + } + } + + sysio.recvfrom_out.len = result; + + return result; + } + + bool setsockopt(Sysio &sysio) + { + /* + * Filter options out because lwip only supports several socket + * options. Therefore for now we silently return 0 and notify + * the user via debug message. + */ + switch (sysio.setsockopt_in.optname) { + case SO_DEBUG: + case SO_LINGER: + warning("SOL_SOCKET option '", sysio.setsockopt_in.optname, "' " + "is currently not supported, however we report success"); + return true; + } + + int result = ::setsockopt(_socket, sysio.setsockopt_in.level, + sysio.setsockopt_in.optname, + sysio.setsockopt_in.optval, + sysio.setsockopt_in.optlen); + + return (result == -1) ? false : true; + } + + ssize_t send(Sysio &sysio) + { + ssize_t result = ::send(_socket, sysio.send_in.buf, sysio.send_in.len, + sysio.send_in.flags); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio.error.send = Sysio::SEND_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; + case ECONNRESET: sysio.error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; + case EINVAL: sysio.error.send = Sysio::SEND_ERR_INVALID; break; + case EISCONN: sysio.error.send = Sysio::SEND_ERR_IS_CONNECTED; break; + case ENOMEM: sysio.error.send = Sysio::SEND_ERR_NO_MEMORY; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } + } + + sysio.send_out.len = result; + + return result; + } + + ssize_t sendto(Sysio &sysio) + { + ssize_t result = ::sendto(_socket, sysio.sendto_in.buf, sysio.sendto_in.len, + sysio.sendto_in.flags, + (const struct sockaddr *) &sysio.sendto_in.dest_addr, + sysio.sendto_in.addrlen); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio.error.send = Sysio::SEND_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio.error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; + case ECONNRESET: sysio.error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; + case EINVAL: sysio.error.send = Sysio::SEND_ERR_INVALID; break; + case EISCONN: sysio.error.send = Sysio::SEND_ERR_IS_CONNECTED; break; + case ENOMEM: sysio.error.send = Sysio::SEND_ERR_NO_MEMORY; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } + } + + sysio.sendto_out.len = result; + + return result; + } + + int shutdown(Sysio &sysio) + { + int result = ::shutdown(_socket, sysio.shutdown_in.how); + + if (result == -1) { + switch (errno) { + case ENOTCONN: sysio.error.shutdown = Sysio::SHUTDOWN_ERR_NOT_CONNECTED; break; + default: + log(__func__, ": unhandled errno: ", (int)errno); + break; + } + } + + return result; + } + + bool socket(Sysio &sysio) + { + _socket = ::socket(sysio.socket_in.domain, + sysio.socket_in.type, + sysio.socket_in.protocol); + + return (_socket == -1) ? false : true; + } +}; + + +class Noux::Socket_io_channel : public Io_channel +{ + private: + + Socket_io_channel_backend _backend; + + public: + + Socket_io_channel() { } + Socket_io_channel(int s) : _backend(s) { } + ~Socket_io_channel() { } + + /* + * Io_channel interface (only needed methods) + */ + + Io_channel_backend *backend() { return &_backend; } + + bool write(Sysio &sysio, ::size_t &count) + { + return _backend.write(sysio, count); + } + + bool read(Sysio &sysio) { return _backend.read(sysio); } + bool fcntl(Sysio &sysio) { return _backend.fcntl(sysio); } + bool ioctl(Sysio &sysio) { return _backend.ioctl(sysio); } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + return _backend.check_unblock(rd, wr, ex); + } +}; #endif /* _NOUX__SOCKET_IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/net/target.mk b/repos/ports/src/noux/net/target.mk index 01a49a50ed..dd40c7fb3d 100644 --- a/repos/ports/src/noux/net/target.mk +++ b/repos/ports/src/noux/net/target.mk @@ -1,10 +1,10 @@ TARGET = noux_net LIBS += alarm libc libc_lwip_nic_dhcp vfs - -SRC_CC = main.cc net.cc +SRC_CC = main.cc syscall.cc net.cc INC_DIR += $(PRG_DIR) INC_DIR += $(PRG_DIR)/../ -vpath main.cc $(PRG_DIR)/.. -vpath net.cc $(PRG_DIR) +vpath main.cc $(PRG_DIR)/.. +vpath syscall.cc $(PRG_DIR)/.. +vpath net.cc $(PRG_DIR) diff --git a/repos/ports/src/noux/parent_execve.h b/repos/ports/src/noux/parent_execve.h index d8adbe1419..700ad5120c 100644 --- a/repos/ports/src/noux/parent_execve.h +++ b/repos/ports/src/noux/parent_execve.h @@ -18,18 +18,17 @@ #include namespace Noux { - struct Family_member; + struct Parent_execve; +} - struct Parent_execve - { - virtual void execve_child(Family_member &child, - const char *filename, - Args const &args, - Sysio::Env const &env, - bool verbose) = 0; - }; +struct Noux::Parent_execve +{ + virtual void execve_child(Family_member &child, + const char *filename, + Args const &args, + Sysio::Env const &env) = 0; }; #endif /* _NOUX__PARENT_EXECVE__H_ */ diff --git a/repos/ports/src/noux/pd_session_component.h b/repos/ports/src/noux/pd_session_component.h index 2f4a5e1e7a..c9265d79a0 100644 --- a/repos/ports/src/noux/pd_session_component.h +++ b/repos/ports/src/noux/pd_session_component.h @@ -42,13 +42,14 @@ class Noux::Pd_session_component : public Rpc_object /** * Constructor */ - Pd_session_component(Rpc_entrypoint &ep, Child_policy::Name const &name, + Pd_session_component(Allocator &alloc, Env &env, Rpc_entrypoint &ep, + Child_policy::Name const &name, Dataspace_registry &ds_registry) : - _ep(ep), _pd(name.string()), - _address_space(_ep, ds_registry, _pd, _pd.address_space()), - _stack_area (_ep, ds_registry, _pd, _pd.stack_area()), - _linker_area (_ep, ds_registry, _pd, _pd.linker_area()) + _ep(ep), _pd(env, name.string()), + _address_space(alloc, _ep, ds_registry, _pd, _pd.address_space()), + _stack_area (alloc, _ep, ds_registry, _pd, _pd.stack_area()), + _linker_area (alloc, _ep, ds_registry, _pd, _pd.linker_area()) { _ep.manage(this); } @@ -60,9 +61,9 @@ class Noux::Pd_session_component : public Rpc_object Pd_session_capability core_pd_cap() { return _pd.cap(); } - void poke(addr_t dst_addr, void const *src, size_t len) + void poke(Region_map &rm, addr_t dst_addr, char const *src, size_t len) { - _address_space.poke(dst_addr, src, len); + _address_space.poke(rm, dst_addr, src, len); } Capability lookup_region_map(addr_t const addr) @@ -76,13 +77,15 @@ class Noux::Pd_session_component : public Rpc_object void replay(Ram_session &dst_ram, Pd_session_component &dst_pd, + Region_map &local_rm, + Allocator &alloc, Dataspace_registry &ds_registry, Rpc_entrypoint &ep) { /* replay region map into new protection domain */ - _stack_area .replay(dst_ram, dst_pd.stack_area_region_map(), ds_registry, ep); - _linker_area .replay(dst_ram, dst_pd.linker_area_region_map(), ds_registry, ep); - _address_space.replay(dst_ram, dst_pd.address_space_region_map(), ds_registry, ep); + _stack_area .replay(dst_ram, dst_pd.stack_area_region_map(), local_rm, alloc, ds_registry, ep); + _linker_area .replay(dst_ram, dst_pd.linker_area_region_map(), local_rm, alloc, ds_registry, ep); + _address_space.replay(dst_ram, dst_pd.address_space_region_map(), local_rm, alloc, ds_registry, ep); Region_map &dst_address_space = dst_pd.address_space_region_map(); Region_map &dst_stack_area = dst_pd.stack_area_region_map(); diff --git a/repos/ports/src/noux/pipe_io_channel.h b/repos/ports/src/noux/pipe_io_channel.h index 5495532b6f..de0eed93e2 100644 --- a/repos/ports/src/noux/pipe_io_channel.h +++ b/repos/ports/src/noux/pipe_io_channel.h @@ -18,350 +18,330 @@ #include namespace Noux { - - class Pipe : public Reference_counter - { - private: - - Lock mutable _lock; - - enum { BUFFER_SIZE = 4096 }; - char _buffer[BUFFER_SIZE]; - - unsigned _read_offset; - unsigned _write_offset; - - Signal_context_capability _read_ready_sigh; - Signal_context_capability _write_ready_sigh; - - bool _writer_is_gone; - - /** - * Return space available in the buffer for writing, in bytes - */ - size_t _avail_buffer_space() const - { - if (_read_offset < _write_offset) - return (BUFFER_SIZE - _write_offset) + _read_offset - 1; - - if (_read_offset > _write_offset) - return _read_offset - _write_offset - 1; - - /* _read_offset == _write_offset */ - return BUFFER_SIZE - 1; - } - - bool _any_space_avail_for_writing() const - { - return _avail_buffer_space() > 0;; - } - - void _wake_up_reader() - { - if (_read_ready_sigh.valid()) - Signal_transmitter(_read_ready_sigh).submit(); - } - - void _wake_up_writer() - { - if (_write_ready_sigh.valid()) - Signal_transmitter(_write_ready_sigh).submit(); - } - - public: - - Pipe() - : _read_offset(0), _write_offset(0), _writer_is_gone(false) { } - - ~Pipe() - { - Lock::Guard guard(_lock); - } - - void writer_close() - { - Lock::Guard guard(_lock); - - _writer_is_gone = true; - _write_ready_sigh = Signal_context_capability(); - _wake_up_reader(); - } - - void reader_close() - { - Lock::Guard guard(_lock); - _read_ready_sigh = Signal_context_capability(); - } - - bool writer_is_gone() const - { - Lock::Guard guard(_lock); - return _writer_is_gone; - } - - bool any_space_avail_for_writing() const - { - Lock::Guard guard(_lock); - return _any_space_avail_for_writing(); - } - - bool data_avail_for_reading() const - { - Lock::Guard guard(_lock); - - return _read_offset != _write_offset; - } - - size_t read(char *dst, size_t dst_len) - { - Lock::Guard guard(_lock); - - if (_read_offset < _write_offset) { - - size_t len = min(dst_len, _write_offset - _read_offset); - memcpy(dst, &_buffer[_read_offset], len); - - _read_offset += len; - _wake_up_writer(); - - return len; - } - - if (_read_offset > _write_offset) { - - size_t const upper_len = min(dst_len, BUFFER_SIZE - _read_offset); - memcpy(dst, &_buffer[_read_offset], upper_len); - - size_t const lower_len = min(dst_len - upper_len, _write_offset); - if (lower_len) { - memcpy(dst + upper_len, &_buffer[0], lower_len); - _read_offset = lower_len; - } else { - _read_offset += upper_len; - } - _wake_up_writer(); - - return upper_len + lower_len; - } - - /* _read_offset == _write_offset */ - return 0; - } - - /** - * Write to pipe buffer - * - * \return number of written bytes (may be less than 'len') - */ - size_t write(char *src, size_t len) - { - Lock::Guard guard(_lock); - - /* trim write request to the available buffer space */ - size_t const trimmed_len = min(len, _avail_buffer_space()); - - /* - * Remember pipe state prior writing to see whether a reader - * must be unblocked after writing. - */ - bool const pipe_was_empty = (_read_offset == _write_offset); - - /* write data up to the upper boundary of the pipe buffer */ - size_t const upper_len = min(BUFFER_SIZE - _write_offset, trimmed_len); - memcpy(&_buffer[_write_offset], src, upper_len); - - _write_offset += upper_len; - - /* - * Determine number of remaining bytes beyond the buffer boundary. - * The buffer wraps. So this data will end up in the lower part - * of the pipe buffer. - */ - size_t const lower_len = trimmed_len - upper_len; - - if (lower_len > 0) { - - /* pipe buffer wrap-around, write remaining data to the lower part */ - memcpy(&_buffer[0], src + upper_len, lower_len); - _write_offset = lower_len; - } - - /* - * Wake up reader who may block for incoming data. - */ - if (pipe_was_empty || !_any_space_avail_for_writing()) - _wake_up_reader(); - - /* return number of written bytes */ - return trimmed_len; - } - - void register_write_ready_sigh(Signal_context_capability sigh) - { - Lock::Guard guard(_lock); - _write_ready_sigh = sigh; - } - - void register_read_ready_sigh(Signal_context_capability sigh) - { - Lock::Guard guard(_lock); - _read_ready_sigh = sigh; - } - }; - - - class Pipe_sink_io_channel : public Io_channel, public Signal_dispatcher_base - { - private: - - Shared_pointer _pipe; - Signal_receiver &_sig_rec; - - public: - - Pipe_sink_io_channel(Shared_pointer pipe, - Signal_receiver &sig_rec) - : _pipe(pipe), _sig_rec(sig_rec) - { - pipe->register_write_ready_sigh(_sig_rec.manage(this)); - } - - ~Pipe_sink_io_channel() - { - _sig_rec.dissolve(this); - _pipe->writer_close(); - } - - bool check_unblock(bool rd, bool wr, bool ex) const override - { - return wr && _pipe->any_space_avail_for_writing(); - } - - bool write(Sysio *sysio, size_t &offset) override - { - /* - * If the write operation is larger than the space available in - * the pipe buffer, the write function is successively called - * for different portions of original write request. The - * current read pointer of the request is tracked via the - * 'count' in/out argument. If completed, 'count' equals - * 'write_in.count'. - */ - - /* dimension the pipe write operation to the not yet written data */ - size_t curr_count = _pipe->write(sysio->write_in.chunk + offset, - sysio->write_in.count - offset); - offset += curr_count; - return true; - } - - bool fcntl(Sysio *sysio) override - { - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: - sysio->fcntl_out.result = Sysio::OPEN_MODE_WRONLY; - return true; - - default: - return false; - } - } - - bool fstat(Sysio *sysio) override - { - sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; - return true; - } - - - /************************************** - ** Signal_dispatcher_base interface ** - **************************************/ - - /** - * Called by Noux main loop on the occurrence of new STDIN input - */ - void dispatch(unsigned) override - { - Io_channel::invoke_all_notifiers(); - } - }; - - - class Pipe_source_io_channel : public Io_channel, public Signal_dispatcher_base - { - private: - - Shared_pointer _pipe; - Signal_receiver &_sig_rec; - - public: - - Pipe_source_io_channel(Shared_pointer pipe, Signal_receiver &sig_rec) - : _pipe(pipe), _sig_rec(sig_rec) - { - _pipe->register_read_ready_sigh(sig_rec.manage(this)); - } - - ~Pipe_source_io_channel() - { - _sig_rec.dissolve(this); - _pipe->reader_close(); - } - - bool check_unblock(bool rd, bool wr, bool ex) const override - { - /* unblock if the writer has already closed its pipe end */ - if (_pipe->writer_is_gone()) - return true; - - return (rd && _pipe->data_avail_for_reading()); - } - - bool read(Sysio *sysio) override - { - size_t const max_count = - min(sysio->read_in.count, - sizeof(sysio->read_out.chunk)); - - sysio->read_out.count = - _pipe->read(sysio->read_out.chunk, max_count); - - return true; - } - - bool fcntl(Sysio *sysio) override - { - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: - sysio->fcntl_out.result = Sysio::OPEN_MODE_RDONLY; - return true; - - default: - return false; - } - } - - bool fstat(Sysio *sysio) override - { - sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; - return true; - } - - /************************************** - ** Signal_dispatcher_base interface ** - **************************************/ - - /** - * Called by Noux main loop on the occurrence of new STDIN input - */ - void dispatch(unsigned) override - { - Io_channel::invoke_all_notifiers(); - } - }; + class Pipe; + class Pipe_sink_io_channel; + class Pipe_source_io_channel; } + +class Noux::Pipe : public Reference_counter +{ + private: + + Lock mutable _lock; + + enum { BUFFER_SIZE = 4096 }; + char _buffer[BUFFER_SIZE]; + + unsigned _read_offset; + unsigned _write_offset; + + Signal_context_capability _read_ready_sigh; + Signal_context_capability _write_ready_sigh; + + bool _writer_is_gone; + + /** + * Return space available in the buffer for writing, in bytes + */ + size_t _avail_buffer_space() const + { + if (_read_offset < _write_offset) + return (BUFFER_SIZE - _write_offset) + _read_offset - 1; + + if (_read_offset > _write_offset) + return _read_offset - _write_offset - 1; + + /* _read_offset == _write_offset */ + return BUFFER_SIZE - 1; + } + + bool _any_space_avail_for_writing() const + { + return _avail_buffer_space() > 0;; + } + + void _wake_up_reader() + { + if (_read_ready_sigh.valid()) + Signal_transmitter(_read_ready_sigh).submit(); + } + + void _wake_up_writer() + { + if (_write_ready_sigh.valid()) + Signal_transmitter(_write_ready_sigh).submit(); + } + + public: + + Pipe() + : _read_offset(0), _write_offset(0), _writer_is_gone(false) { } + + ~Pipe() + { + Lock::Guard guard(_lock); + } + + void writer_close() + { + Lock::Guard guard(_lock); + + _writer_is_gone = true; + _write_ready_sigh = Signal_context_capability(); + _wake_up_reader(); + } + + void reader_close() + { + Lock::Guard guard(_lock); + _read_ready_sigh = Signal_context_capability(); + } + + bool writer_is_gone() const + { + Lock::Guard guard(_lock); + return _writer_is_gone; + } + + bool any_space_avail_for_writing() const + { + Lock::Guard guard(_lock); + return _any_space_avail_for_writing(); + } + + bool data_avail_for_reading() const + { + Lock::Guard guard(_lock); + + return _read_offset != _write_offset; + } + + size_t read(char *dst, size_t dst_len) + { + Lock::Guard guard(_lock); + + if (_read_offset < _write_offset) { + + size_t len = min(dst_len, _write_offset - _read_offset); + memcpy(dst, &_buffer[_read_offset], len); + + _read_offset += len; + _wake_up_writer(); + + return len; + } + + if (_read_offset > _write_offset) { + + size_t const upper_len = min(dst_len, BUFFER_SIZE - _read_offset); + memcpy(dst, &_buffer[_read_offset], upper_len); + + size_t const lower_len = min(dst_len - upper_len, _write_offset); + if (lower_len) { + memcpy(dst + upper_len, &_buffer[0], lower_len); + _read_offset = lower_len; + } else { + _read_offset += upper_len; + } + _wake_up_writer(); + + return upper_len + lower_len; + } + + /* _read_offset == _write_offset */ + return 0; + } + + /** + * Write to pipe buffer + * + * \return number of written bytes (may be less than 'len') + */ + size_t write(char *src, size_t len) + { + Lock::Guard guard(_lock); + + /* trim write request to the available buffer space */ + size_t const trimmed_len = min(len, _avail_buffer_space()); + + /* + * Remember pipe state prior writing to see whether a reader + * must be unblocked after writing. + */ + bool const pipe_was_empty = (_read_offset == _write_offset); + + /* write data up to the upper boundary of the pipe buffer */ + size_t const upper_len = min(BUFFER_SIZE - _write_offset, trimmed_len); + memcpy(&_buffer[_write_offset], src, upper_len); + + _write_offset += upper_len; + + /* + * Determine number of remaining bytes beyond the buffer boundary. + * The buffer wraps. So this data will end up in the lower part + * of the pipe buffer. + */ + size_t const lower_len = trimmed_len - upper_len; + + if (lower_len > 0) { + + /* pipe buffer wrap-around, write remaining data to the lower part */ + memcpy(&_buffer[0], src + upper_len, lower_len); + _write_offset = lower_len; + } + + /* + * Wake up reader who may block for incoming data. + */ + if (pipe_was_empty || !_any_space_avail_for_writing()) + _wake_up_reader(); + + /* return number of written bytes */ + return trimmed_len; + } + + void register_write_ready_sigh(Signal_context_capability sigh) + { + Lock::Guard guard(_lock); + _write_ready_sigh = sigh; + } + + void register_read_ready_sigh(Signal_context_capability sigh) + { + Lock::Guard guard(_lock); + _read_ready_sigh = sigh; + } +}; + + +class Noux::Pipe_sink_io_channel : public Io_channel +{ + private: + + Signal_handler _write_ready_handler; + + void _handle_write_ready() { Io_channel::invoke_all_notifiers(); } + + Shared_pointer _pipe; + + public: + + Pipe_sink_io_channel(Shared_pointer pipe, Entrypoint &ep) + : + _write_ready_handler(ep, *this, &Pipe_sink_io_channel::_handle_write_ready), + _pipe(pipe) + { + pipe->register_write_ready_sigh(_write_ready_handler); + } + + ~Pipe_sink_io_channel() { _pipe->writer_close(); } + + bool check_unblock(bool rd, bool wr, bool ex) const override + { + return wr && _pipe->any_space_avail_for_writing(); + } + + bool write(Sysio &sysio, size_t &offset) override + { + /* + * If the write operation is larger than the space available in + * the pipe buffer, the write function is successively called + * for different portions of original write request. The + * current read pointer of the request is tracked via the + * 'count' in/out argument. If completed, 'count' equals + * 'write_in.count'. + */ + + /* dimension the pipe write operation to the not yet written data */ + size_t curr_count = _pipe->write(sysio.write_in.chunk + offset, + sysio.write_in.count - offset); + offset += curr_count; + return true; + } + + bool fcntl(Sysio &sysio) override + { + switch (sysio.fcntl_in.cmd) { + + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: + sysio.fcntl_out.result = Sysio::OPEN_MODE_WRONLY; + return true; + + default: + return false; + } + } + + bool fstat(Sysio &sysio) override + { + sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + return true; + } +}; + + +class Noux::Pipe_source_io_channel : public Io_channel +{ + private: + + Signal_handler _read_avail_handler; + + void _handle_read_avail() { Io_channel::invoke_all_notifiers(); } + + Shared_pointer _pipe; + + public: + + Pipe_source_io_channel(Shared_pointer pipe, Entrypoint &ep) + : + _read_avail_handler(ep, *this, &Pipe_source_io_channel::_handle_read_avail), + _pipe(pipe) + { + _pipe->register_read_ready_sigh(_read_avail_handler); + } + + ~Pipe_source_io_channel() { _pipe->reader_close(); } + + bool check_unblock(bool rd, bool wr, bool ex) const override + { + /* unblock if the writer has already closed its pipe end */ + if (_pipe->writer_is_gone()) + return true; + + return (rd && _pipe->data_avail_for_reading()); + } + + bool read(Sysio &sysio) override + { + size_t const max_count = + min(sysio.read_in.count, + sizeof(sysio.read_out.chunk)); + + sysio.read_out.count = + _pipe->read(sysio.read_out.chunk, max_count); + + return true; + } + + bool fcntl(Sysio &sysio) override + { + switch (sysio.fcntl_in.cmd) { + + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: + sysio.fcntl_out.result = Sysio::OPEN_MODE_RDONLY; + return true; + + default: + return false; + } + } + + bool fstat(Sysio &sysio) override + { + sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + return true; + } +}; + #endif /* _NOUX__PIPE_IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/ram_session_component.h b/repos/ports/src/noux/ram_session_component.h index 0ca3b0458a..2ea488c617 100644 --- a/repos/ports/src/noux/ram_session_component.h +++ b/repos/ports/src/noux/ram_session_component.h @@ -26,163 +26,164 @@ /* Genode includes */ #include #include -#include /* Noux includes */ #include namespace Noux { - - struct Ram_dataspace_info : Dataspace_info, - List::Element - { - Ram_dataspace_info(Ram_dataspace_capability ds_cap) - : Dataspace_info(ds_cap) { } - - Dataspace_capability fork(Ram_session &ram, - Dataspace_registry &ds_registry, - Rpc_entrypoint &) override - { - size_t const size = Dataspace_client(ds_cap()).size(); - - Ram_dataspace_capability dst_ds; - - try { dst_ds = ram.alloc(size); } - catch (...) { return Dataspace_capability(); } - - void *src = 0; - try { - src = env()->rm_session()->attach(ds_cap()); - } catch (...) { } - - void *dst = 0; - try { - dst = env()->rm_session()->attach(dst_ds); - } catch (...) { } - - if (src && dst) - memcpy(dst, src, size); - - if (src) env()->rm_session()->detach(src); - if (dst) env()->rm_session()->detach(dst); - - if (!src || !dst) { - ram.free(dst_ds); - return Dataspace_capability(); - } - - ds_registry.insert(new (env()->heap()) Ram_dataspace_info(dst_ds)); - - return dst_ds; - } - - void poke(addr_t dst_offset, void const *src, size_t len) - { - if ((dst_offset >= size()) || (dst_offset + len > size())) { - error("illegal attemt to write beyond dataspace boundary"); - return; - } - - char *dst = 0; - try { - dst = env()->rm_session()->attach(ds_cap()); - } catch (...) { } - - if (src && dst) - memcpy(dst + dst_offset, src, len); - - if (dst) env()->rm_session()->detach(dst); - } - }; - - - class Ram_session_component : public Rpc_object - { - private: - - Rpc_entrypoint &_ep; - - List _list; - - /* - * Track the RAM resources accumulated via RAM session allocations. - * - * XXX not used yet - */ - size_t _used_quota; - - Dataspace_registry &_registry; - - public: - - /** - * Constructor - */ - Ram_session_component(Rpc_entrypoint &ep, Dataspace_registry ®istry) - : _ep(ep), _used_quota(0), _registry(registry) { _ep.manage(this); } - - /** - * Destructor - */ - ~Ram_session_component() - { - _ep.dissolve(this); - Ram_dataspace_info *info = 0; - while ((info = _list.first())) - free(static_cap_cast(info->ds_cap())); - } - - - /*************************** - ** Ram_session interface ** - ***************************/ - - Ram_dataspace_capability alloc(size_t size, Cache_attribute cached) - { - Ram_dataspace_capability ds_cap = - env()->ram_session()->alloc(size, cached); - - Ram_dataspace_info *ds_info = new (env()->heap()) - Ram_dataspace_info(ds_cap); - - _used_quota += ds_info->size(); - - _registry.insert(ds_info); - _list.insert(ds_info); - - return ds_cap; - } - - void free(Ram_dataspace_capability ds_cap) - { - Ram_dataspace_info *ds_info; - - auto lambda = [&] (Ram_dataspace_info *rdi) { - ds_info = rdi; - - if (!ds_info) { - error("RAM free: dataspace lookup failed"); - return; - } - - _registry.remove(ds_info); - - ds_info->dissolve_users(); - - _list.remove(ds_info); - _used_quota -= ds_info->size(); - - env()->ram_session()->free(ds_cap); - }; - _registry.apply(ds_cap, lambda); - destroy(env()->heap(), ds_info); - } - - int ref_account(Ram_session_capability) { return 0; } - int transfer_quota(Ram_session_capability, size_t) { return 0; } - size_t quota() { return env()->ram_session()->quota(); } - size_t used() { return _used_quota; } - }; + struct Ram_dataspace_info; + struct Ram_session_component; + using namespace Genode; } + +struct Noux::Ram_dataspace_info : Dataspace_info, + List::Element +{ + Ram_dataspace_info(Ram_dataspace_capability ds_cap) + : Dataspace_info(ds_cap) { } + + Dataspace_capability fork(Ram_session &ram, + Region_map &local_rm, + Allocator &alloc, + Dataspace_registry &ds_registry, + Rpc_entrypoint &) override + { + size_t const size = Dataspace_client(ds_cap()).size(); + Ram_dataspace_capability dst_ds_cap; + + try { + dst_ds_cap = ram.alloc(size); + + Attached_dataspace src_ds(local_rm, ds_cap()); + Attached_dataspace dst_ds(local_rm, dst_ds_cap); + memcpy(dst_ds.local_addr(), src_ds.local_addr(), size); + + ds_registry.insert(new (alloc) Ram_dataspace_info(dst_ds_cap)); + return dst_ds_cap; + + } catch (...) { + error("fork of RAM dataspace failed"); + + if (dst_ds_cap.valid()) + ram.free(dst_ds_cap); + + return Dataspace_capability(); + } + } + + void poke(Region_map &rm, addr_t dst_offset, char const *src, size_t len) override + { + if (!src) return; + + if ((dst_offset >= size()) || (dst_offset + len > size())) { + error("illegal attemt to write beyond dataspace boundary"); + return; + } + + try { + Attached_dataspace ds(rm, ds_cap()); + memcpy(ds.local_addr() + dst_offset, src, len); + } catch (...) { warning("poke: failed to attach RAM dataspace"); } + } +}; + + +class Noux::Ram_session_component : public Rpc_object +{ + private: + + Ram_session &_ram; + + Allocator &_alloc; + + Rpc_entrypoint &_ep; + + List _list; + + /* + * Track the RAM resources accumulated via RAM session allocations. + * + * XXX not used yet + */ + size_t _used_quota; + + Dataspace_registry &_registry; + + public: + + /** + * Constructor + */ + Ram_session_component(Ram_session &ram, Allocator &alloc, + Rpc_entrypoint &ep, Dataspace_registry ®istry) + : + _ram(ram), _alloc(alloc), _ep(ep), _used_quota(0), + _registry(registry) + { + _ep.manage(this); + } + + /** + * Destructor + */ + ~Ram_session_component() + { + _ep.dissolve(this); + Ram_dataspace_info *info = 0; + while ((info = _list.first())) + free(static_cap_cast(info->ds_cap())); + } + + + /*************************** + ** Ram_session interface ** + ***************************/ + + Ram_dataspace_capability alloc(size_t size, Cache_attribute cached) + { + Ram_dataspace_capability ds_cap = + _ram.alloc(size, cached); + + Ram_dataspace_info *ds_info = new (_alloc) Ram_dataspace_info(ds_cap); + + _used_quota += ds_info->size(); + + _registry.insert(ds_info); + _list.insert(ds_info); + + return ds_cap; + } + + void free(Ram_dataspace_capability ds_cap) + { + Ram_dataspace_info *ds_info; + + auto lambda = [&] (Ram_dataspace_info *rdi) { + ds_info = rdi; + + if (!ds_info) { + error("RAM free: dataspace lookup failed"); + return; + } + + _registry.remove(ds_info); + + ds_info->dissolve_users(); + + _list.remove(ds_info); + _used_quota -= ds_info->size(); + + _ram.free(ds_cap); + }; + _registry.apply(ds_cap, lambda); + destroy(_alloc, ds_info); + } + + int ref_account(Ram_session_capability) { return 0; } + int transfer_quota(Ram_session_capability, size_t) { return 0; } + size_t quota() { return _ram.quota(); } + size_t used() { return _used_quota; } +}; + #endif /* _NOUX__RAM_SESSION_COMPONENT_H_ */ diff --git a/repos/ports/src/noux/random_file_system.h b/repos/ports/src/noux/random_file_system.h deleted file mode 100644 index 14443166b8..0000000000 --- a/repos/ports/src/noux/random_file_system.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * \brief Device Random filesystem - * \author Josef Soentgen - * \date 2012-07-31 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NOUX__RANDOM_FILE_SYSTEM_H_ -#define _NOUX__RANDOM_FILE_SYSTEM_H_ - -/* Genode includes */ -#include -#include -#include - -/* Noux includes */ -#include -#include - -/*- - * Copyright (c) 2010, 2012 - * Thorsten Glaser - * Copyright (c) 2012 - * Josef Soentgen - * - * Provided that these terms and disclaimer and all copyright notices - * are retained or reproduced in an accompanying document, permission - * is granted to deal in this work without restriction, including un- - * limited rights to use, publicly perform, distribute, sell, modify, - * merge, give away, or sublicence. - * - * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to - * the utmost extent permitted by applicable law, neither express nor - * implied; without malicious intent or gross negligence. In no event - * may a licensor, author or contributor be held liable for indirect, - * direct, other damage, loss, or other issues arising in any way out - * of dealing in the work, even if advised of the possibility of such - * damage or existence of a defect, except proven that it results out - * of said person's immediate fault when using the work as intended. - *- - * arc4random for use as NOUX random device. - * - * From: - * MirOS: src/kern/c/arcfour_base.c,v 1.1 2010/09/12 17:10:49 tg Exp - * MirOS: src/kern/c/arcfour_ksa.c,v 1.1 2010/09/12 17:10:50 tg Exp - * MirOS: src/lib/libc/crypt/arc4random_base.c,v 1.4 2011/07/06 22:22:09 tg Exp - * MirOS: src/lib/libc/crypt/arc4random_buf.c,v 1.1 2010/09/12 17:10:53 tg Exp - */ - - -namespace Noux { - - using namespace Genode; - - /** - * Arcfour cipher re-implementation from (alledged) spec description. - */ - - class Arc4random - { - private: - - uint8_t S[256]; - uint8_t i; - uint8_t j; - uint16_t num; - uint8_t initialised; - - /* - * Base cipher operation: initialise state - */ - void init(void) - { - register uint8_t n = 0; - - do { - S[n] = n; - } while (++n); - - i = j = 0; - } - - /* - * Base cipher operation: get byte of keystream. - */ - uint8_t byte(void) - { - register uint8_t si, sj; - - si = S[++i]; - j += si; - sj = S[j]; - S[i] = sj; - S[j] = si; - return (S[(uint8_t)(si + sj)]); - } - - /* - * Normal key scheduling algorithm. - */ - void ksa(const uint8_t *key, size_t keylen) - { - register uint8_t si, n = 0; - - --i; - do { - ++i; - si = S[i]; - j = (uint8_t)(j + si + key[n++ % keylen]); - S[i] = S[j]; - S[j] = si; - } while (n); - j = ++i; - } - - /* - * arc4random implementation - */ - void stir_unlocked(void) - { - register unsigned int m; - uint8_t n; - struct { - // struct timeval tv; - // pid_t mypid; - uint32_t mypid; - const void *stkptr, *bssptr, *txtptr; - uint16_t num; - uint8_t initialised; - // FIXME sizeof (sb) should be as close to 256 as possible - } sb; - - /* save some state; while not a secret, helps through variety */ - //sb.mypid = getpid(); - sb.mypid = 42; - sb.stkptr = &sb; - sb.bssptr = &i; - //sb.txtptr = &byte; - sb.txtptr = (const void *)0xDEADBEEF;; - sb.num = num; - sb.initialised = initialised; - - /* initialise i, j and the S-box if not done yet */ - if (!initialised) { - init(); - initialised = 1; - } - - // FIXME initialize more sb member - - /* dance around by some bytes for added protection */ - n = byte(); - /* and carry some over to below */ - m = byte(); - while (n--) - (void)byte(); - m += byte(); - - /* while time is not a secret, it helps through variety */ - //gettimeofday(&sb.tv, NULL); - - /* actually add the hopefully random-containing seed */ - ksa((const uint8_t *)&sb, sizeof(sb)); - - /* throw away the first part of the arcfour keystream */ - /* with some bytes varied for added protection */ - m += 256 * 4 + (byte() & 0x1F); - while (m--) - (void)byte(); - /* state is now good for so many bytes: (not so much in NOUX) */ - num = 2000; - } - - void buf(void *buf_, unsigned long long len) - { - size_t chunk; - uint8_t *buf = (uint8_t *)buf_; - uint8_t m, n; - - /* operate in chunks of at most 256 bytes */ - while ((chunk = len > 256 ? 256 : len) > 0) { - /* adjust len */ - len -= chunk; - - /* is the state good for this? (or even initialised, yet?) */ - if (num < chunk) - stir_unlocked(); - - /* dance around a few bytes for added protection */ - m = byte() & 3; - /* and carry some down below */ - n = byte() & 3; - while (m--) - (void)byte(); - - /* actually read out the keystream into buf */ - while (chunk--) { - *buf++ = byte(); - } - - /* dance around the bytes read from above, for protection */ - while (n--) - (void)byte(); - } - } - - public: - - Arc4random(void* bytes, size_t nbytes) - : - i(0), - j(0), - num(0), - initialised(0) - { - memset(S, 0, 256); - } - - void get(void *_buf, unsigned long long len) - { - buf(_buf, len); - } - }; - - - class Random_file_system : public Vfs::Single_file_system - { - private: - - Arc4random _arc4random; - - public: - - Random_file_system(Genode::Env&, Genode::Allocator&, - Genode::Xml_node config) - : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), - _arc4random(0, 0) - { } - - static char const *name() { return "random"; } - - - /******************************** - ** File I/O service interface ** - ********************************/ - - Write_result write(Vfs::Vfs_handle *, char const *, - Vfs::file_size buf_size, - Vfs::file_size &out_count) override - { - out_count = buf_size; - - return WRITE_OK; - } - - Read_result read(Vfs::Vfs_handle *vfs_handle, char *dst, - Vfs::file_size count, - Vfs::file_size &out_count) override - { - _arc4random.get(dst, count); - out_count = count; - - return READ_OK; - } - - Ftruncate_result ftruncate(Vfs::Vfs_handle *, - Vfs::file_size) override - { - return FTRUNCATE_OK; - } - }; -} - -#endif /* _NOUX__RANDOM_H_ */ diff --git a/repos/ports/src/noux/range_checked_index.h b/repos/ports/src/noux/range_checked_index.h index 6721eb45c5..76cb70c0d9 100644 --- a/repos/ports/src/noux/range_checked_index.h +++ b/repos/ports/src/noux/range_checked_index.h @@ -17,28 +17,29 @@ namespace Noux { class Index_out_of_range { }; - - template - struct Range_checked_index - { - T value; - T const max; - - Range_checked_index(T value, T max) - : value(value), max(max) { } - - T operator++ (int) - { - T old_value = value; - - if (++value >= max) - throw Index_out_of_range(); - - return old_value; - } - - operator T () { return value; } - }; + template struct Range_checked_index; } + +template +struct Noux::Range_checked_index +{ + T value; + T const max; + + Range_checked_index(T value, T max) : value(value), max(max) { } + + T operator++ (int) + { + T old_value = value; + + if (++value >= max) + throw Index_out_of_range(); + + return old_value; + } + + operator T () { return value; } +}; + #endif /* _NOUX__RANGE_CHECKED_INDEX_H_ */ diff --git a/repos/ports/src/noux/region_map_component.h b/repos/ports/src/noux/region_map_component.h index 45a7285149..168278d6b2 100644 --- a/repos/ports/src/noux/region_map_component.h +++ b/repos/ports/src/noux/region_map_component.h @@ -36,6 +36,8 @@ class Noux::Region_map_component : public Rpc_object, static constexpr bool verbose_attach = false; static constexpr bool verbose_replay = false; + Allocator &_alloc; + Rpc_entrypoint &_ep; /** @@ -104,13 +106,13 @@ class Noux::Region_map_component : public Rpc_object, * quota upgrades * \param rm region map at core */ - Region_map_component(Rpc_entrypoint &ep, + Region_map_component(Allocator &alloc, Rpc_entrypoint &ep, Dataspace_registry &ds_registry, Pd_connection &pd, Capability rm) : Dataspace_info(Region_map_client(rm).dataspace()), - _ep(ep), _rm(rm), _pd(pd), _ds_registry(ds_registry) + _alloc(alloc), _ep(ep), _rm(rm), _pd(pd), _ds_registry(ds_registry) { _ep.manage(this); _ds_registry.insert(this); @@ -159,6 +161,8 @@ class Noux::Region_map_component : public Rpc_object, */ void replay(Ram_session &dst_ram, Region_map &dst_rm, + Region_map &local_rm, + Allocator &alloc, Dataspace_registry &ds_registry, Rpc_entrypoint &ep) { @@ -170,7 +174,7 @@ class Noux::Region_map_component : public Rpc_object, Dataspace_capability ds; if (info) { - ds = info->fork(dst_ram, ds_registry, ep); + ds = info->fork(dst_ram, local_rm, alloc, ds_registry, ep); /* * XXX We could detect dataspaces that are attached @@ -242,7 +246,7 @@ class Noux::Region_map_component : public Rpc_object, } } - Region * region = new (env()->heap()) + Region * region = new (_alloc) Region(*this, ds, size, offset, local_addr); /* register region as user of RAM dataspaces */ @@ -289,10 +293,9 @@ class Noux::Region_map_component : public Rpc_object, _ds_registry.apply(region->ds, [&] (Dataspace_info *info) { if (info) info->unregister_user(*region); }); - destroy(env()->heap(), region); + destroy(_alloc, region); _rm.detach(local_addr); - } void fault_handler(Signal_context_capability handler) override @@ -323,6 +326,8 @@ class Noux::Region_map_component : public Rpc_object, ******************************/ Dataspace_capability fork(Ram_session &, + Region_map &, + Allocator &, Dataspace_registry &, Rpc_entrypoint &) override { @@ -358,7 +363,7 @@ class Noux::Region_map_component : public Rpc_object, return _ds_registry.apply(region->ds, lambda); } - void poke(addr_t dst_addr, void const *src, size_t len) override + void poke(Region_map &rm, addr_t dst_addr, char const *src, size_t len) override { Dataspace_capability ds_cap; addr_t local_addr; @@ -395,7 +400,7 @@ class Noux::Region_map_component : public Rpc_object, error("attempt to write to unknown dataspace type"); for (;;); } - info->poke(dst_addr - local_addr, src, len); + info->poke(rm, dst_addr - local_addr, src, len); }); } }; diff --git a/repos/ports/src/noux/rom_session_component.h b/repos/ports/src/noux/rom_session_component.h index 098cb5d690..ba45b932b7 100644 --- a/repos/ports/src/noux/rom_session_component.h +++ b/repos/ports/src/noux/rom_session_component.h @@ -32,14 +32,16 @@ struct Noux::Rom_dataspace_info : Dataspace_info ~Rom_dataspace_info() { } Dataspace_capability fork(Ram_session &, + Region_map &, + Allocator &alloc, Dataspace_registry &ds_registry, Rpc_entrypoint &) override { - ds_registry.insert(new (env()->heap()) Rom_dataspace_info(ds_cap())); + ds_registry.insert(new (alloc) Rom_dataspace_info(ds_cap())); return ds_cap(); } - void poke(addr_t dst_offset, void const *src, size_t len) + void poke(Region_map &, addr_t dst_offset, char const *src, size_t len) { error("attempt to poke onto a ROM dataspace"); } @@ -101,7 +103,7 @@ class Noux::Rom_session_component : public Rpc_object */ Constructible _rom_from_parent; - Dataspace_capability _init_ds_cap(Name const &name) + Dataspace_capability _init_ds_cap(Env &env, Name const &name) { if (name.string()[0] == '/') { _rom_from_vfs.construct(_root_dir, name); @@ -111,7 +113,7 @@ class Noux::Rom_session_component : public Rpc_object if (name == forked_magic_binary_name()) return Dataspace_capability(); - _rom_from_parent.construct(name.string()); + _rom_from_parent.construct(env, name.string()); Dataspace_capability ds = _rom_from_parent->dataspace(); return ds; } @@ -120,14 +122,15 @@ class Noux::Rom_session_component : public Rpc_object public: - Rom_session_component(Rpc_entrypoint &ep, Vfs::Dir_file_system &root_dir, + Rom_session_component(Allocator &alloc, Env &env, Rpc_entrypoint &ep, + Vfs::Dir_file_system &root_dir, Dataspace_registry &ds_registry, Name const &name) : _ep(ep), _root_dir(root_dir), _ds_registry(ds_registry), - _ds_cap(_init_ds_cap(name)) + _ds_cap(_init_ds_cap(env, name)) { _ep.manage(this); - _ds_registry.insert(new (env()->heap()) Rom_dataspace_info(_ds_cap)); + _ds_registry.insert(new (alloc) Rom_dataspace_info(_ds_cap)); } ~Rom_session_component() diff --git a/repos/ports/src/noux/shared_pointer.h b/repos/ports/src/noux/shared_pointer.h index 04b8321c69..3c6f0cd2c1 100644 --- a/repos/ports/src/noux/shared_pointer.h +++ b/repos/ports/src/noux/shared_pointer.h @@ -23,135 +23,137 @@ #include namespace Noux { - + class Reference_counter; class Shared_pointer_base; - - class Reference_counter - { - private: - - Lock _lock; - long _value; - - friend class Shared_pointer_base; - - void _inc_ref_count() - { - Lock::Guard guard(_lock); - _value++; - } - - /** - * \return reference counter after decrement - */ - long _dec_ref_count() - { - Lock::Guard guard(_lock); - return --_value; - } - - public: - - Reference_counter() : _value(0) { } - }; - - - class Shared_pointer_base - { - protected: - - Reference_counter *_ref_counter; - - Shared_pointer_base(Reference_counter *ref_counter) - : _ref_counter(ref_counter) { } - - void _inc_ref_count() { - if (_ref_counter) _ref_counter->_inc_ref_count(); } - - bool _dec_ref_count() { - return _ref_counter && (_ref_counter->_dec_ref_count() == 0); } - - long count() const { return _ref_counter ? _ref_counter->_value : -99; } - }; - - - template - class Shared_pointer : public Shared_pointer_base - { - private: - - T *_ptr; - Allocator *_alloc; - - void _dec_ref_count() - { - if (Shared_pointer_base::_dec_ref_count()) { - - destroy(_alloc, _ptr); - _ptr = 0; - _alloc = 0; - _ref_counter = 0; - } - } - - public: - - Shared_pointer() : Shared_pointer_base(0), _ptr(0), _alloc(0) { } - - Shared_pointer(T *ptr, Allocator *alloc) - : Shared_pointer_base(ptr), _ptr(ptr), _alloc(alloc) - { - _inc_ref_count(); - } - - Shared_pointer(Shared_pointer const & from) - : - Shared_pointer_base(from._ref_counter), - _ptr(from._ptr), _alloc(from._alloc) - { - _inc_ref_count(); - } - - Shared_pointer & operator=(const Shared_pointer& from) - { - /* check for self assignment */ - if (_ptr == from._ptr) - return *this; - - /* forget about original pointed-to object */ - _dec_ref_count(); - - _ref_counter = from._ref_counter; - _ptr = from._ptr; - _alloc = from._alloc; - - /* account for newly assigned pointed-to object */ - _inc_ref_count(); - - return *this; - } - - ~Shared_pointer() - { - _dec_ref_count(); - } - - T * operator -> () { return _ptr; } - T const* operator -> () const { return _ptr; } - - operator bool () const { return _ptr != 0; } - - bool operator== (const Shared_pointer &other) - { - return (_ptr == other._ptr); - } - - template - Shared_pointer dynamic_pointer_cast() - { - return Shared_pointer(dynamic_cast(_ptr), _alloc); - } - }; + template class Shared_pointer; } + +class Noux::Reference_counter +{ + private: + + Lock _lock; + long _value; + + friend class Shared_pointer_base; + + void _inc_ref_count() + { + Lock::Guard guard(_lock); + _value++; + } + + /** + * \return reference counter after decrement + */ + long _dec_ref_count() + { + Lock::Guard guard(_lock); + return --_value; + } + + public: + + Reference_counter() : _value(0) { } +}; + + +class Noux::Shared_pointer_base +{ + protected: + + Reference_counter *_ref_counter; + + Shared_pointer_base(Reference_counter *ref_counter) + : _ref_counter(ref_counter) { } + + void _inc_ref_count() { + if (_ref_counter) _ref_counter->_inc_ref_count(); } + + bool _dec_ref_count() { + return _ref_counter && (_ref_counter->_dec_ref_count() == 0); } + + long count() const { return _ref_counter ? _ref_counter->_value : -99; } +}; + + +template +class Noux::Shared_pointer : public Shared_pointer_base +{ + private: + + T *_ptr; + Allocator *_alloc; + + void _dec_ref_count() + { + if (Shared_pointer_base::_dec_ref_count()) { + + destroy(_alloc, _ptr); + _ptr = 0; + _alloc = 0; + _ref_counter = 0; + } + } + + public: + + Shared_pointer() : Shared_pointer_base(0), _ptr(0), _alloc(0) { } + + Shared_pointer(T *ptr, Allocator &alloc) + : Shared_pointer_base(ptr), _ptr(ptr), _alloc(&alloc) + { + _inc_ref_count(); + } + + Shared_pointer(Shared_pointer const & from) + : + Shared_pointer_base(from._ref_counter), + _ptr(from._ptr), _alloc(from._alloc) + { + _inc_ref_count(); + } + + Shared_pointer & operator=(const Shared_pointer& from) + { + /* check for self assignment */ + if (_ptr == from._ptr) + return *this; + + /* forget about original pointed-to object */ + _dec_ref_count(); + + _ref_counter = from._ref_counter; + _ptr = from._ptr; + _alloc = from._alloc; + + /* account for newly assigned pointed-to object */ + _inc_ref_count(); + + return *this; + } + + ~Shared_pointer() + { + _dec_ref_count(); + } + + T * operator -> () { return _ptr; } + T const* operator -> () const { return _ptr; } + + operator bool () const { return _ptr != 0; } + + bool operator== (const Shared_pointer &other) + { + return (_ptr == other._ptr); + } + + template + Shared_pointer dynamic_pointer_cast() + { + return Shared_pointer(dynamic_cast(_ptr), _alloc); + } +}; + #endif /* _NOUX__SHARED_POINTER_H_ */ diff --git a/repos/ports/src/noux/stdio_file_system.h b/repos/ports/src/noux/stdio_file_system.h deleted file mode 100644 index 31c5bff8ea..0000000000 --- a/repos/ports/src/noux/stdio_file_system.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * \brief Stdio filesystem - * \author Josef Soentgen - * \date 2012-08-02 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NOUX__STDIO_FILE_SYSTEM_H_ -#define _NOUX__STDIO_FILE_SYSTEM_H_ - -/* Genode includes */ -#include -#include -#include - -/* Noux includes */ -#include -#include "terminal_connection.h" - - -namespace Noux { - - class Stdio_file_system : public Vfs::Single_file_system - { - private: - - Terminal::Session_client *_terminal; - bool _echo; - - public: - - Stdio_file_system(Genode::Env&, Genode::Allocator&, - Genode::Xml_node config) - : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), - _terminal(terminal()), - _echo(true) - { } - - static char const *name() { return "stdio"; } - - - /******************************** - ** File I/O service interface ** - ********************************/ - - Write_result write(Vfs::Vfs_handle *, char const *buf, - Vfs::file_size buf_size, - Vfs::file_size &out_count) override - { - buf_size = buf_size > 0xFFFFFFFFULL ? ~0UL : buf_size; - - out_count = _terminal->write(buf, buf_size); - - return WRITE_OK; - } - - Read_result read(Vfs::Vfs_handle *, char *dst, - Vfs::file_size count, - Vfs::file_size &out_count) override - { - count = count > 0xFFFFFFFFULL ? ~0UL : count; - - out_count = _terminal->read(dst, count); - - if (_echo) - _terminal->write(dst, count); - - return READ_OK; - } - - Ftruncate_result ftruncate(Vfs::Vfs_handle *, - Vfs::file_size) override - { - return FTRUNCATE_OK; - } - - Ioctl_result ioctl(Vfs::Vfs_handle *vfs_handle, Ioctl_opcode opcode, - Ioctl_arg arg, Ioctl_out &out) override - { - switch (opcode) { - - case Vfs::File_io_service::IOCTL_OP_TIOCSETAF: - { - _echo = (arg & (Vfs::File_io_service::IOCTL_VAL_ECHO)); - return IOCTL_OK; - } - - case Vfs::File_io_service::IOCTL_OP_TIOCSETAW: - { - warning(__func__, ": OP_TIOCSETAW not implemented"); - return IOCTL_ERR_INVALID; - } - - default: - warning(__func__, ": invalid ioctl(request=", Hex(opcode), ")"); - break; - } - - return IOCTL_ERR_INVALID; - } - }; -} - -#endif /* _NOUX__STDIO_FILE_SYSTEM_H_ */ diff --git a/repos/ports/src/noux/syscall.cc b/repos/ports/src/noux/syscall.cc new file mode 100644 index 0000000000..de7bca40ae --- /dev/null +++ b/repos/ports/src/noux/syscall.cc @@ -0,0 +1,798 @@ +/* + * \brief Noux syscall dispatcher + * \author Norman Feske + * \date 2011-02-14 + */ + +/* + * Copyright (C) 2011-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Noux includes */ +#include +#include +#include +#include + +namespace Noux { + + /** + * This function is used to generate inode values from the given + * path using the FNV-1a algorithm. + */ + inline uint32_t hash_path(const char *path, size_t len) + { + const unsigned char * p = reinterpret_cast(path); + uint32_t hash = 2166136261U; + + for (size_t i = 0; i < len; i++) { + hash ^= p[i]; + hash *= 16777619; + } + + return hash; + } +}; + + +bool Noux::Child::syscall(Noux::Session::Syscall sc) +{ + if (_verbose.syscalls()) + log("PID ", pid(), " -> SYSCALL ", Noux::Session::syscall_name(sc)); + + bool result = false; + + try { + switch (sc) { + + case SYSCALL_WRITE: + { + size_t const count_in = _sysio.write_in.count; + + for (size_t offset = 0; offset != count_in; ) { + + Shared_pointer io = _lookup_channel(_sysio.write_in.fd); + + if (!io->nonblocking()) + _block_for_io_channel(io, false, true, false); + + if (io->check_unblock(false, true, false)) { + /* + * 'io->write' is expected to update + * '_sysio.write_out.count' and 'offset' + */ + result = io->write(_sysio, offset); + if (result == false) + break; + } else { + if (result == false) { + /* nothing was written yet */ + _sysio.error.write = Vfs::File_io_service::WRITE_ERR_INTERRUPT; + } + break; + } + } + break; + } + + case SYSCALL_READ: + { + Shared_pointer io = _lookup_channel(_sysio.read_in.fd); + + if (!io->nonblocking()) + _block_for_io_channel(io, true, false, false); + + if (io->check_unblock(true, false, false)) + result = io->read(_sysio); + else + _sysio.error.read = Vfs::File_io_service::READ_ERR_INTERRUPT; + + break; + } + + case SYSCALL_FTRUNCATE: + { + Shared_pointer io = _lookup_channel(_sysio.ftruncate_in.fd); + + _block_for_io_channel(io, false, true, false); + + if (io->check_unblock(false, true, false)) + result = io->ftruncate(_sysio); + else + _sysio.error.ftruncate = Vfs::File_io_service::FTRUNCATE_ERR_INTERRUPT; + + break; + } + + case SYSCALL_STAT: + case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */ + { + /** + * We calculate the inode by hashing the path because there is + * no inode registry in noux. + */ + size_t path_len = strlen(_sysio.stat_in.path); + uint32_t path_hash = hash_path(_sysio.stat_in.path, path_len); + + Vfs::Directory_service::Stat stat_out; + _sysio.error.stat = _root_dir.stat(_sysio.stat_in.path, stat_out); + + result = (_sysio.error.stat == Vfs::Directory_service::STAT_OK); + + /* + * Instead of using the uid/gid given by the actual file system + * we use the ones specificed in the config. + */ + if (result) { + stat_out.uid = _user_info.uid(); + stat_out.gid = _user_info.gid(); + + stat_out.inode = path_hash; + } + + _sysio.stat_out.st = stat_out; + + break; + } + + case SYSCALL_FSTAT: + { + Shared_pointer io = _lookup_channel(_sysio.fstat_in.fd); + + result = io->fstat(_sysio); + + if (result) { + Sysio::Path path; + + /** + * Only actual fd's are valid fstat targets. + */ + if (io->path(path, sizeof (path))) { + size_t path_len = strlen(path); + uint32_t path_hash = hash_path(path, path_len); + + _sysio.stat_out.st.inode = path_hash; + } + } + + break; + } + + case SYSCALL_FCNTL: + + if (_sysio.fcntl_in.cmd == Sysio::FCNTL_CMD_SET_FD_FLAGS) { + + /* we assume that there is only the close-on-execve flag */ + _lookup_channel(_sysio.fcntl_in.fd)->close_on_execve = + !!_sysio.fcntl_in.long_arg; + result = true; + break; + } + + result = _lookup_channel(_sysio.fcntl_in.fd)->fcntl(_sysio); + break; + + case SYSCALL_OPEN: + { + Vfs::Vfs_handle *vfs_handle = 0; + _sysio.error.open = _root_dir.open(_sysio.open_in.path, + _sysio.open_in.mode, + &vfs_handle, _heap); + if (!vfs_handle) + break; + + char const *leaf_path = _root_dir.leaf_path(_sysio.open_in.path); + + /* + * File descriptors of opened directories are handled by + * '_root_dir'. In this case, we use the absolute path as leaf + * path because path operations always refer to the global + * root. + */ + if (&vfs_handle->ds() == &_root_dir) + leaf_path = _sysio.open_in.path; + + Shared_pointer + channel(new (_heap) Vfs_io_channel(_sysio.open_in.path, + leaf_path, &_root_dir, + vfs_handle, _env.ep()), + _heap); + + _sysio.open_out.fd = add_io_channel(channel); + result = true; + break; + } + + case SYSCALL_CLOSE: + { + remove_io_channel(_sysio.close_in.fd); + result = true; + break; + } + + case SYSCALL_IOCTL: + + result = _lookup_channel(_sysio.ioctl_in.fd)->ioctl(_sysio); + break; + + case SYSCALL_LSEEK: + + result = _lookup_channel(_sysio.lseek_in.fd)->lseek(_sysio); + break; + + case SYSCALL_DIRENT: + + result = _lookup_channel(_sysio.dirent_in.fd)->dirent(_sysio); + break; + + case SYSCALL_EXECVE: + { + /* + * We have to check the dataspace twice because the binary + * could be a script that uses an interpreter which maybe + * does not exist. + */ + Dataspace_capability binary_ds = + _root_dir.dataspace(_sysio.execve_in.filename); + + if (!binary_ds.valid()) { + _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; + break; + } + + Child_env + child_env(_env.rm(), + _sysio.execve_in.filename, binary_ds, + _sysio.execve_in.args, _sysio.execve_in.env); + + _root_dir.release(_sysio.execve_in.filename, binary_ds); + + binary_ds = _root_dir.dataspace(child_env.binary_name()); + + if (!binary_ds.valid()) { + _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; + break; + } + + _root_dir.release(child_env.binary_name(), binary_ds); + + try { + _parent_execve.execve_child(*this, + child_env.binary_name(), + child_env.args(), + child_env.env()); + + /* + * 'return' instead of 'break' to skip possible signal delivery, + * which might cause the old child process to exit itself + */ + return true; + } + catch (Child::Binary_does_not_exist) { + _sysio.error.execve = Sysio::EXECVE_NONEXISTENT; } + catch (Child::Insufficient_memory) { + _sysio.error.execve = Sysio::EXECVE_NOMEM; } + + break; + } + + case SYSCALL_SELECT: + { + size_t in_fds_total = _sysio.select_in.fds.total_fds(); + Sysio::Select_fds in_fds; + for (Genode::size_t i = 0; i < in_fds_total; i++) + in_fds.array[i] = _sysio.select_in.fds.array[i]; + in_fds.num_rd = _sysio.select_in.fds.num_rd; + in_fds.num_wr = _sysio.select_in.fds.num_wr; + in_fds.num_ex = _sysio.select_in.fds.num_ex; + + int _rd_array[in_fds_total]; + int _wr_array[in_fds_total]; + + long timeout_sec = _sysio.select_in.timeout.sec; + long timeout_usec = _sysio.select_in.timeout.usec; + bool timeout_reached = false; + + /* reset the blocker lock to the 'locked' state */ + _blocker.unlock(); + _blocker.lock(); + + /* + * Register ourself at all watched I/O channels + * + * We instantiate as many notifiers as we have file + * descriptors to observe. Each notifier is associated + * with the child's blocking semaphore. When any of the + * notifiers get woken up, the semaphore gets unblocked. + * + * XXX However, the blocker may get unblocked for other + * conditions such as the destruction of the child. + * ...to be done. + */ + + Wake_up_notifier notifiers[in_fds_total]; + + for (Genode::size_t i = 0; i < in_fds_total; i++) { + int fd = in_fds.array[i]; + if (!fd_in_use(fd)) continue; + + Shared_pointer io = io_channel_by_fd(fd); + notifiers[i].lock = &_blocker; + + io->register_wake_up_notifier(¬ifiers[i]); + } + + /** + * Register ourself at the Io_receptor_registry + * + * Each entry in the registry will be unblocked if an external + * event has happend, e.g. network I/O. + */ + + Io_receptor receptor(&_blocker); + io_receptor_registry()->register_receptor(&receptor); + + + /* + * Block for one action of the watched file descriptors + */ + for (;;) { + + /* + * Check I/O channels of specified file descriptors for + * unblock condition. Return if one I/O channel satisfies + * the condition. + */ + size_t unblock_rd = 0; + size_t unblock_wr = 0; + size_t unblock_ex = 0; + + /* process read fds */ + for (Genode::size_t i = 0; i < in_fds_total; i++) { + + int fd = in_fds.array[i]; + if (!fd_in_use(fd)) continue; + + Shared_pointer io = io_channel_by_fd(fd); + + if (in_fds.watch_for_rd(i)) + if (io->check_unblock(true, false, false)) { + _rd_array[unblock_rd++] = fd; + } + if (in_fds.watch_for_wr(i)) + if (io->check_unblock(false, true, false)) { + _wr_array[unblock_wr++] = fd; + } + if (in_fds.watch_for_ex(i)) + if (io->check_unblock(false, false, true)) { + unblock_ex++; + } + } + + if (unblock_rd || unblock_wr || unblock_ex) { + /** + * Merge the fd arrays in one output array + */ + for (size_t i = 0; i < unblock_rd; i++) { + _sysio.select_out.fds.array[i] = _rd_array[i]; + } + _sysio.select_out.fds.num_rd = unblock_rd; + + /* XXX could use a pointer to select_out.fds.array instead */ + for (size_t j = unblock_rd, i = 0; i < unblock_wr; i++, j++) { + _sysio.select_out.fds.array[j] = _wr_array[i]; + } + _sysio.select_out.fds.num_wr = unblock_wr; + + /* exception fds are currently not considered */ + _sysio.select_out.fds.num_ex = unblock_ex; + + result = true; + break; + } + + /* + * Return if timeout is zero or timeout exceeded + */ + + if (_sysio.select_in.timeout.zero() || timeout_reached) { + /* + if (timeout_reached) log("timeout_reached"); + else log("timeout.zero()"); + */ + _sysio.select_out.fds.num_rd = 0; + _sysio.select_out.fds.num_wr = 0; + _sysio.select_out.fds.num_ex = 0; + + result = true; + break; + } + + /* + * Return if signals are pending + */ + + if (!_pending_signals.empty()) { + _sysio.error.select = Sysio::SELECT_ERR_INTERRUPT; + break; + } + + /* + * Block at barrier except when reaching the timeout + */ + + if (!_sysio.select_in.timeout.infinite()) { + unsigned long to_msec = (timeout_sec * 1000) + (timeout_usec / 1000); + Timeout_state ts; + Timeout_alarm ta(ts, _blocker, _timeout_scheduler, to_msec); + + /* block until timeout is reached or we were unblocked */ + _blocker.lock(); + + if (ts.timed_out) { + timeout_reached = 1; + } + else { + /* + * We woke up before reaching the timeout, + * so we discard the alarm + */ + ta.discard(); + } + } + else { + /* let's block infinitely */ + _blocker.lock(); + } + + } + + /* + * Unregister barrier at watched I/O channels + */ + for (Genode::size_t i = 0; i < in_fds_total; i++) { + int fd = in_fds.array[i]; + if (!fd_in_use(fd)) continue; + + Shared_pointer io = io_channel_by_fd(fd); + io->unregister_wake_up_notifier(¬ifiers[i]); + } + + /* + * Unregister receptor + */ + io_receptor_registry()->unregister_receptor(&receptor); + + break; + } + + case SYSCALL_FORK: + { + Genode::addr_t ip = _sysio.fork_in.ip; + Genode::addr_t sp = _sysio.fork_in.sp; + Genode::addr_t parent_cap_addr = _sysio.fork_in.parent_cap_addr; + + int const new_pid = _pid_allocator.alloc(); + Child * child = nullptr; + + try { + /* + * XXX To ease debugging, it would be useful to generate a + * unique name that includes the PID instead of just + * reusing the name of the parent. + */ + child = new (_heap) Child(_child_policy.name(), + _verbose, + _user_info, + this, + _kill_broadcaster, + _timeout_scheduler, + *this, + _pid_allocator, + new_pid, + _env, + _root_dir, + _args, + _sysio_env.env(), + _heap, + _ref_ram, _ref_ram_cap, + _parent_services, + true, + _destruct_queue); + } catch (Child::Insufficient_memory) { + _sysio.error.fork = Sysio::FORK_NOMEM; + break; + } + + Family_member::insert(child); + + _assign_io_channels_to(child); + + /* copy our address space into the new child */ + try { + _pd.replay(child->ram(), child->pd(), _env.rm(), _heap, + child->ds_registry(), _ep); + + /* start executing the main thread of the new process */ + child->start_forked_main_thread(ip, sp, parent_cap_addr); + + /* activate child entrypoint, thereby starting the new process */ + child->start(); + + _sysio.fork_out.pid = new_pid; + + result = true; + } + catch (Region_map::Region_conflict) { + error("region conflict while replaying the address space"); } + + break; + } + + case SYSCALL_GETPID: + { + _sysio.getpid_out.pid = pid(); + return true; + } + + case SYSCALL_WAIT4: + { + Family_member *exited = _sysio.wait4_in.nohang ? poll4() : wait4(); + + if (exited) { + _sysio.wait4_out.pid = exited->pid(); + _sysio.wait4_out.status = exited->exit_status(); + Family_member::remove(exited); + + static_cast(exited)->submit_exit_signal(); + + } else { + if (_sysio.wait4_in.nohang) { + _sysio.wait4_out.pid = 0; + _sysio.wait4_out.status = 0; + } else { + _sysio.error.wait4 = Sysio::WAIT4_ERR_INTERRUPT; + break; + } + } + result = true; + break; + } + + case SYSCALL_PIPE: + { + Shared_pointer pipe (new (_heap) Pipe, _heap); + Shared_pointer pipe_sink (new (_heap) Pipe_sink_io_channel (pipe, _env.ep()), _heap); + Shared_pointer pipe_source(new (_heap) Pipe_source_io_channel(pipe, _env.ep()), _heap); + + _sysio.pipe_out.fd[0] = add_io_channel(pipe_source); + _sysio.pipe_out.fd[1] = add_io_channel(pipe_sink); + + result = true; + break; + } + + case SYSCALL_DUP2: + { + int fd = add_io_channel(io_channel_by_fd(_sysio.dup2_in.fd), + _sysio.dup2_in.to_fd); + + _sysio.dup2_out.fd = fd; + + result = true; + break; + } + + case SYSCALL_UNLINK: + + _sysio.error.unlink = _root_dir.unlink(_sysio.unlink_in.path); + + result = (_sysio.error.unlink == Vfs::Directory_service::UNLINK_OK); + break; + + case SYSCALL_READLINK: + { + Vfs::file_size out_count = 0; + + _sysio.error.readlink = + _root_dir.readlink(_sysio.readlink_in.path, + _sysio.readlink_out.chunk, + min(_sysio.readlink_in.bufsiz, + sizeof(_sysio.readlink_out.chunk)), + out_count); + + _sysio.readlink_out.count = out_count; + + result = (_sysio.error.readlink == Vfs::Directory_service::READLINK_OK); + break; + } + + case SYSCALL_RENAME: + + _sysio.error.rename = _root_dir.rename(_sysio.rename_in.from_path, + _sysio.rename_in.to_path); + + result = (_sysio.error.rename == Vfs::Directory_service::RENAME_OK); + break; + + case SYSCALL_MKDIR: + + _sysio.error.mkdir = _root_dir.mkdir(_sysio.mkdir_in.path, 0); + + result = (_sysio.error.mkdir == Vfs::Directory_service::MKDIR_OK); + break; + + case SYSCALL_SYMLINK: + + _sysio.error.symlink = _root_dir.symlink(_sysio.symlink_in.oldpath, + _sysio.symlink_in.newpath); + + result = (_sysio.error.symlink == Vfs::Directory_service::SYMLINK_OK); + break; + + case SYSCALL_USERINFO: + { + if (_sysio.userinfo_in.request == Sysio::USERINFO_GET_UID + || _sysio.userinfo_in.request == Sysio::USERINFO_GET_GID) { + _sysio.userinfo_out.uid = _user_info.uid(); + _sysio.userinfo_out.gid = _user_info.gid(); + + result = true; + break; + } + + /* + * Since NOUX supports exactly one user, return false if we + * got a unknown uid. + */ + if (_sysio.userinfo_in.uid != _user_info.uid()) + break; + + Genode::memcpy(_sysio.userinfo_out.name, + _user_info.name().string(), + sizeof(User_info::Name)); + Genode::memcpy(_sysio.userinfo_out.shell, + _user_info.shell().string(), + sizeof(User_info::Shell)); + Genode::memcpy(_sysio.userinfo_out.home, + _user_info.home().string(), + sizeof(User_info::Home)); + + _sysio.userinfo_out.uid = _user_info.uid(); + _sysio.userinfo_out.gid = _user_info.gid(); + + result = true; + break; + } + + case SYSCALL_GETTIMEOFDAY: + { + /** + * Since the timeout_scheduler thread is started after noux it + * basicly returns the eleapsed time since noux was started. We + * abuse this timer to provide a more useful implemenation of + * gettimeofday() to make certain programs (e.g. ping(1)) happy. + * Note: this is just a short-term solution because Genode currently + * lacks a proper time interface (there is a RTC driver however, but + * there is no interface for it). + */ + unsigned long time = _timeout_scheduler.curr_time(); + + _sysio.gettimeofday_out.sec = (time / 1000); + _sysio.gettimeofday_out.usec = (time % 1000) * 1000; + + result = true; + break; + } + + case SYSCALL_CLOCK_GETTIME: + { + /** + * It's the same procedure as in SYSCALL_GETTIMEOFDAY. + */ + unsigned long time = _timeout_scheduler.curr_time(); + + switch (_sysio.clock_gettime_in.clock_id) { + + /* CLOCK_SECOND is used by time(3) in the libc. */ + case Sysio::CLOCK_ID_SECOND: + { + _sysio.clock_gettime_out.sec = (time / 1000); + _sysio.clock_gettime_out.nsec = 0; + + result = true; + break; + } + + default: + { + _sysio.clock_gettime_out.sec = 0; + _sysio.clock_gettime_out.nsec = 0; + _sysio.error.clock = Sysio::CLOCK_ERR_INVALID; + + break; + } + + } + + break; + + } + + case SYSCALL_UTIMES: + { + /** + * This systemcall is currently not implemented because we lack + * the needed mechanisms in most file-systems. + * + * But we return true anyway to keep certain programs, e.g. make + * happy. + */ + result = true; + break; + } + + case SYSCALL_SYNC: + { + _root_dir.sync("/"); + result = true; + break; + } + + case SYSCALL_KILL: + { + if (_kill_broadcaster.kill(_sysio.kill_in.pid, + _sysio.kill_in.sig)) + result = true; + else + _sysio.error.kill = Sysio::KILL_ERR_SRCH; + + break; + } + + case SYSCALL_GETDTABLESIZE: + { + _sysio.getdtablesize_out.n = + Noux::File_descriptor_registry::MAX_FILE_DESCRIPTORS; + result = true; + break; + } + + case SYSCALL_SOCKET: + case SYSCALL_GETSOCKOPT: + case SYSCALL_SETSOCKOPT: + case SYSCALL_ACCEPT: + case SYSCALL_BIND: + case SYSCALL_LISTEN: + case SYSCALL_SEND: + case SYSCALL_SENDTO: + case SYSCALL_RECV: + case SYSCALL_RECVFROM: + case SYSCALL_GETPEERNAME: + case SYSCALL_SHUTDOWN: + case SYSCALL_CONNECT: + + result = _syscall_net(sc); + break; + + case SYSCALL_INVALID: break; + } + } + + catch (Invalid_fd) { + _sysio.error.general = Vfs::Directory_service::ERR_FD_INVALID; + error("invalid file descriptor"); } + + catch (...) { error("unexpected exception"); } + + /* handle signals which might have occured */ + while (!_pending_signals.empty() && + (_sysio.pending_signals.avail_capacity() > 0)) { + _sysio.pending_signals.add(_pending_signals.get()); + } + + return result; +} diff --git a/repos/ports/src/noux/terminal_connection.h b/repos/ports/src/noux/terminal_connection.h deleted file mode 100644 index 7b01104cc9..0000000000 --- a/repos/ports/src/noux/terminal_connection.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief Terminal connection - * \author Josef Soentgen - * \date 2012-08-02 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NOUX__TERMINAL_CONNECTION_H_ -#define _NOUX__TERMINAL_CONNECTION_H_ - -/* Genode includes */ -#include -#include -#include -#include - -/* Noux includes */ -#include -#include - - -namespace Noux { Terminal::Connection *terminal(); } - -#endif /* _NOUX__TERMINAL_CONNECTION_H_ */ diff --git a/repos/ports/src/noux/terminal_io_channel.h b/repos/ports/src/noux/terminal_io_channel.h index 06a5e0ebde..f1f8e3d505 100644 --- a/repos/ports/src/noux/terminal_io_channel.h +++ b/repos/ports/src/noux/terminal_io_channel.h @@ -24,210 +24,201 @@ #include #include -namespace Noux { +namespace Noux { struct Terminal_io_channel; } - struct Terminal_io_channel : Io_channel, Signal_dispatcher_base + +struct Noux::Terminal_io_channel : Io_channel +{ + Terminal::Session &_terminal; + + Signal_handler _read_avail_handler; + + bool eof = false; + + enum Type { STDIN, STDOUT, STDERR } type; + + Ring_buffer read_buffer; + + Terminal_io_channel(Terminal::Session &terminal, Type type, + Entrypoint &ep) + : + _terminal(terminal), + _read_avail_handler(ep, *this, &Terminal_io_channel::_handle_read_avail), + type(type) { - Terminal::Session &terminal; - Signal_receiver &sig_rec; - bool eof; - - enum Type { STDIN, STDOUT, STDERR } type; - - Ring_buffer read_buffer; - - Terminal_io_channel(Terminal::Session &terminal, Type type, - Signal_receiver &sig_rec) - : terminal(terminal), sig_rec(sig_rec), eof(false), type(type) - { - /* - * Enable wake up STDIN channel on the presence of new input - * - * By registering our I/O channel as signal handler, the Noux - * main loop will be unblocked on the arrival of new input. - * It will check if the received signal belongs to an I/O channel - * and invokes the 'handle_signal' function of the I/O channel. - * - * This gives us the opportunity to handle the unblocking of - * blocking system calls such as 'select'. - */ - if (type == STDIN) { - terminal.read_avail_sigh(sig_rec.manage(this)); - } + /* + * Enable wake up STDIN channel on the presence of new input + * + * By registering our I/O channel as signal handler, the Noux + * main loop will be unblocked on the arrival of new input. + * It will check if the received signal belongs to an I/O channel + * and invokes the 'handle_signal' function of the I/O channel. + * + * This gives us the opportunity to handle the unblocking of + * blocking system calls such as 'select'. + */ + if (type == STDIN) { + terminal.read_avail_sigh(_read_avail_handler); } + } - ~Terminal_io_channel() - { - try { sig_rec.dissolve(this); } - catch (Genode::Signal_receiver::Context_not_associated) { } - } + bool write(Sysio &sysio, size_t &offset) override + { + size_t const count = min(sysio.write_in.count, + sizeof(sysio.write_in.chunk)); - bool write(Sysio *sysio, size_t &offset) override - { - size_t const count = min(sysio->write_in.count, - sizeof(sysio->write_in.chunk)); + _terminal.write(sysio.write_in.chunk, count); - terminal.write(sysio->write_in.chunk, count); + sysio.write_out.count = count; + offset = count; - sysio->write_out.count = count; - offset = count; - - return true; - } - - bool read(Sysio *sysio) override - { - if (type != STDIN) { - error("attempt to read from terminal output channel"); - return false; - } - - /* deliver EOF observed by the previous 'read' call */ - if (eof) { - sysio->read_out.count = 0; - eof = false; - return true; - } - - size_t const max_count = - min(sysio->read_in.count, - sizeof(sysio->read_out.chunk)); - - for (sysio->read_out.count = 0; - (sysio->read_out.count < max_count) && !read_buffer.empty(); - sysio->read_out.count++) { - - char c = read_buffer.get(); - - enum { EOF = 4 }; - - if (c == EOF) { - - /* - * If EOF was the only character of the batch, the count - * has reached zero. In this case the read result indicates - * the EOF condition as is. However, if count is greater - * than zero, we deliver the previous characters of the - * batch and return the zero result from the subsequent - * 'read' call. This condition is tracked by the 'eof' - * variable. - */ - if (sysio->read_out.count > 0) - eof = true; - - return true; - } - - sysio->read_out.chunk[sysio->read_out.count] = c; - } - - return true; - } - - bool fcntl(Sysio *sysio) override - { - /** - * Actually it is "inappropiate" to use fcntl() directly on terminals - * (atleast according to the Open Group Specification). We do it anyway - * since in our case stdout/in/err is directly connected to the terminal. - * - * Some GNU programms check if stdout is open by calling fcntl(stdout, F_GETFL, ...). - */ - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: - sysio->fcntl_out.result = 0; - return true; - - default: - return false; - } + return true; + } + bool read(Sysio &sysio) override + { + if (type != STDIN) { + error("attempt to read from terminal output channel"); return false; } - bool fstat(Sysio *sysio) override - { - /* - * Supply stat values such that libc is happy. I.e., the libc - * is checking for the file descriptor 1 being a character - * device. - */ - sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + /* deliver EOF observed by the previous 'read' call */ + if (eof) { + sysio.read_out.count = 0; + eof = false; return true; } - bool check_unblock(bool rd, bool wr, bool ex) const override - { - /* never block for writing */ - if (wr) return true; + size_t const max_count = + min(sysio.read_in.count, + sizeof(sysio.read_out.chunk)); - /* - * Unblock I/O channel if the terminal has new user input. Channels - * otther than STDIN will never unblock. - */ - return (rd && (type == STDIN) && !read_buffer.empty()); - } + for (sysio.read_out.count = 0; + (sysio.read_out.count < max_count) && !read_buffer.empty(); + sysio.read_out.count++) { - bool ioctl(Sysio *sysio) override - { - switch (sysio->ioctl_in.request) { + char c = read_buffer.get(); - case Vfs::File_io_service::IOCTL_OP_TIOCGWINSZ: - { - Terminal::Session::Size size = terminal.size(); - sysio->ioctl_out.tiocgwinsz.rows = size.lines(); - sysio->ioctl_out.tiocgwinsz.columns = size.columns(); - return true; - } + enum { EOF = 4 }; - case Vfs::File_io_service::IOCTL_OP_TIOCSETAF: - { - warning(__func__, ": OP_TIOCSETAF not implemented"); - return false; - } + if (c == EOF) { - case Vfs::File_io_service::IOCTL_OP_TIOCSETAW: - { - warning(__func__, ": OP_TIOCSETAW not implemented"); - return false; - } + /* + * If EOF was the only character of the batch, the count + * has reached zero. In this case the read result indicates + * the EOF condition as is. However, if count is greater + * than zero, we deliver the previous characters of the + * batch and return the zero result from the subsequent + * 'read' call. This condition is tracked by the 'eof' + * variable. + */ + if (sysio.read_out.count > 0) + eof = true; - default: - - warning("invalid ioctl request ", (int)sysio->ioctl_in.request); - return false; - }; - } - - - /************************************** - ** Signal_dispatcher_base interface ** - **************************************/ - - /** - * Called by Noux main loop on the occurrence of new STDIN input - */ - void dispatch(unsigned) override - { - while ((read_buffer.avail_capacity() > 0) && - terminal.avail()) { - - char c; - terminal.read(&c, 1); - - enum { INTERRUPT = 3 }; - - if (c == INTERRUPT) { - Io_channel::invoke_all_interrupt_handlers(); - } else { - read_buffer.add(c); - } + return true; } - Io_channel::invoke_all_notifiers(); + sysio.read_out.chunk[sysio.read_out.count] = c; } - }; -} + + return true; + } + + bool fcntl(Sysio &sysio) override + { + /** + * Actually it is "inappropiate" to use fcntl() directly on terminals + * (atleast according to the Open Group Specification). We do it anyway + * since in our case stdout/in/err is directly connected to the terminal. + * + * Some GNU programms check if stdout is open by calling fcntl(stdout, F_GETFL, ...). + */ + switch (sysio.fcntl_in.cmd) { + + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: + sysio.fcntl_out.result = 0; + return true; + + default: + return false; + } + + return false; + } + + bool fstat(Sysio &sysio) override + { + /* + * Supply stat values such that libc is happy. I.e., the libc + * is checking for the file descriptor 1 being a character + * device. + */ + sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + return true; + } + + bool check_unblock(bool rd, bool wr, bool ex) const override + { + /* never block for writing */ + if (wr) return true; + + /* + * Unblock I/O channel if the terminal has new user input. Channels + * otther than STDIN will never unblock. + */ + return (rd && (type == STDIN) && !read_buffer.empty()); + } + + bool ioctl(Sysio &sysio) override + { + switch (sysio.ioctl_in.request) { + + case Vfs::File_io_service::IOCTL_OP_TIOCGWINSZ: + { + Terminal::Session::Size size = _terminal.size(); + sysio.ioctl_out.tiocgwinsz.rows = size.lines(); + sysio.ioctl_out.tiocgwinsz.columns = size.columns(); + return true; + } + + case Vfs::File_io_service::IOCTL_OP_TIOCSETAF: + { + warning(__func__, ": OP_TIOCSETAF not implemented"); + return false; + } + + case Vfs::File_io_service::IOCTL_OP_TIOCSETAW: + { + warning(__func__, ": OP_TIOCSETAW not implemented"); + return false; + } + + default: + + warning("invalid ioctl request ", (int)sysio.ioctl_in.request); + return false; + }; + } + + void _handle_read_avail() + { + while ((read_buffer.avail_capacity() > 0) && + _terminal.avail()) { + + char c; + _terminal.read(&c, 1); + + enum { INTERRUPT = 3 }; + + if (c == INTERRUPT) { + Io_channel::invoke_all_interrupt_handlers(); + } else { + read_buffer.add(c); + } + } + + Io_channel::invoke_all_notifiers(); + } +}; #endif /* _NOUX__TERMINAL_IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/timeout_scheduler.h b/repos/ports/src/noux/timeout_scheduler.h new file mode 100644 index 0000000000..89babdf379 --- /dev/null +++ b/repos/ports/src/noux/timeout_scheduler.h @@ -0,0 +1,102 @@ +/* + * \brief Timeout mechanism for 'select' + * \author Norman Feske + * \date 2011-02-14 + */ + +/* + * Copyright (C) 2011-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _NOUX__TIMEOUT_SCHEDULER_H_ +#define _NOUX__TIMEOUT_SCHEDULER_H_ + +#include +#include + +namespace Noux { + class Timeout_scheduler; + class Timeout_state; + class Timeout_alarm; + using namespace Genode; +} + + +class Noux::Timeout_scheduler : public Alarm_scheduler +{ + private: + + Timer::Connection _timer; + Alarm::Time _curr_time { 0 }; + + enum { TIMER_GRANULARITY_MSEC = 10 }; + + Signal_handler _timer_handler; + + void _handle_timer() + { + _curr_time = _timer.elapsed_ms(); + Alarm_scheduler::handle(_curr_time); + } + + public: + + Timeout_scheduler(Env &env) + : + _timer(env), + _timer_handler(env.ep(), *this, &Timeout_scheduler::_handle_timer) + { + _timer.sigh(_timer_handler); + _timer.trigger_periodic(TIMER_GRANULARITY_MSEC*1000); + } + + Alarm::Time curr_time() const { return _curr_time; } +}; + + +struct Noux::Timeout_state +{ + bool timed_out; + + Timeout_state() : timed_out(false) { } +}; + + +class Noux::Timeout_alarm : public Alarm +{ + private: + + Timeout_state &_state; + Lock &_blocker; + Timeout_scheduler &_scheduler; + + public: + + Timeout_alarm(Timeout_state &st, Lock &blocker, + Timeout_scheduler &scheduler, Time timeout) + : + _state(st), + _blocker(blocker), + _scheduler(scheduler) + { + _scheduler.schedule_absolute(this, _scheduler.curr_time() + timeout); + _state.timed_out = false; + } + + void discard() { _scheduler.discard(this); } + + protected: + + bool on_alarm(unsigned) override + { + _state.timed_out = true; + _blocker.unlock(); + + return false; + } +}; + +#endif /* _NOUX__TIMEOUT_SCHEDULER_H_ */ diff --git a/repos/ports/src/noux/user_info.h b/repos/ports/src/noux/user_info.h index b47c3d7bde..6811db246f 100644 --- a/repos/ports/src/noux/user_info.h +++ b/repos/ports/src/noux/user_info.h @@ -1,6 +1,7 @@ /* * \brief User information * \author Josef Soentgen + * \author Norman Feske * \date 2012-07-23 */ @@ -22,49 +23,54 @@ #include namespace Noux { - + class User_info; using namespace Genode; - - struct User_info { - - public: - - char name[Sysio::MAX_USERNAME_LEN]; - char shell[Sysio::MAX_SHELL_LEN]; - char home[Sysio::MAX_HOME_LEN]; - - unsigned int uid; - unsigned int gid; - - User_info() : uid(0), gid(0) - { - strncpy(name, "root", sizeof(name)); - strncpy(home, "/", sizeof(home)); - strncpy(shell, "/bin/bash", sizeof(shell)); - } - - void set_info(Genode::Xml_node user_info_node) - { - try { - user_info_node.attribute("name").value(name, sizeof(name)); - user_info_node.attribute("uid").value(&uid); - user_info_node.attribute("gid").value(&gid); - - for (unsigned i = 0; i < user_info_node.num_sub_nodes(); i++) { - Xml_node sub_node = user_info_node.sub_node(i); - - if (sub_node.has_type("shell")) { - sub_node.attribute("name").value(shell, sizeof(shell)); - } - - if (sub_node.has_type("home")) { - sub_node.attribute("name").value(home, sizeof(home)); - } - } - } - catch (...) { } - } - }; } + +class Noux::User_info : Noncopyable +{ + public: + + typedef String Name; + typedef String Shell; + typedef String Home; + + private: + + unsigned const _uid; + unsigned const _gid; + + Name const _name; + Shell const _shell; + Home const _home; + + template + S _sub_node_name(Xml_node node, char const *sub_node, S const &default_name) + { + if (!node.has_sub_node(sub_node)) + return default_name; + + return node.sub_node(sub_node).attribute_value("name", default_name); + } + + public: + + User_info(Xml_node node) + : + _uid (node.attribute_value("uid", 0UL)), + _gid (node.attribute_value("gid", 0UL)), + _name(node.attribute_value("name", Name("root"))), + _shell(_sub_node_name(node, "shell", Shell("/bin/bash"))), + _home (_sub_node_name(node, "home", Home("name"))) + { } + + unsigned uid() const { return _uid; } + unsigned gid() const { return _gid; } + + Name name() const { return _name; } + Shell shell() const { return _shell; } + Home home() const { return _home; } +}; + #endif /* _NOUX__USER_INFO_H_ */ diff --git a/repos/ports/src/noux/verbose.h b/repos/ports/src/noux/verbose.h new file mode 100644 index 0000000000..76b70c7e76 --- /dev/null +++ b/repos/ports/src/noux/verbose.h @@ -0,0 +1,48 @@ +/* + * \brief Noux verbosity + * \author Norman Feske + * \date 2017-01-17 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _NOUX__VERBOSE_H_ +#define _NOUX__VERBOSE_H_ + +#include +#include + +namespace Noux { struct Verbose; } + + +class Noux::Verbose : Genode::Noncopyable +{ + private: + + bool const _enabled; + bool const _ld; + bool const _syscalls; + bool const _quota; + + public: + + Verbose(Genode::Xml_node config) + : + _enabled (config.attribute_value("verbose", false)), + _ld (config.attribute_value("ld_verbose", false)), + _syscalls(config.attribute_value("verbose_syscalls", false)), + _quota (config.attribute_value("verbose_quota", false)) + { } + + bool enabled() const { return _enabled; } + bool ld() const { return _ld; } + bool syscalls() const { return _syscalls; } + bool quota() const { return _quota; } +}; + +#endif /* _NOUX__VERBOSE_H_ */ diff --git a/repos/ports/src/noux/vfs_io_channel.h b/repos/ports/src/noux/vfs_io_channel.h index 2c21e2420e..15309f1719 100644 --- a/repos/ports/src/noux/vfs_io_channel.h +++ b/repos/ports/src/noux/vfs_io_channel.h @@ -18,212 +18,204 @@ #include #include -namespace Noux { +namespace Noux { struct Vfs_io_channel; } - struct Vfs_io_channel : Io_channel, Signal_dispatcher_base + +struct Noux::Vfs_io_channel : Io_channel +{ + Signal_handler _read_avail_handler; + + void _handle_read_avail() { - Vfs::Vfs_handle *_fh; + Io_channel::invoke_all_notifiers(); + } - Absolute_path _path; - Absolute_path _leaf_path; + Vfs::Vfs_handle *_fh; - Signal_receiver &_sig_rec; + Absolute_path _path; + Absolute_path _leaf_path; - Vfs_io_channel(char const *path, char const *leaf_path, - Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle, - Signal_receiver &sig_rec) - : _fh(vfs_handle), _path(path), _leaf_path(leaf_path), - _sig_rec(sig_rec) - { - _fh->fs().register_read_ready_sigh(_fh, _sig_rec.manage(this)); - } + Vfs_io_channel(char const *path, char const *leaf_path, + Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle, + Entrypoint &ep) + : + _read_avail_handler(ep, *this, &Vfs_io_channel::_handle_read_avail), + _fh(vfs_handle), _path(path), _leaf_path(leaf_path) + { + _fh->fs().register_read_ready_sigh(_fh, _read_avail_handler); + } - ~Vfs_io_channel() - { - _sig_rec.dissolve(this); - _fh->ds().close(_fh); - } + ~Vfs_io_channel() + { + _fh->ds().close(_fh); + } - bool write(Sysio *sysio, size_t &offset) override - { - Vfs::file_size out_count = 0; + bool write(Sysio &sysio, size_t &offset) override + { + Vfs::file_size out_count = 0; - sysio->error.write = _fh->fs().write(_fh, sysio->write_in.chunk, - sysio->write_in.count, out_count); - if (sysio->error.write != Vfs::File_io_service::WRITE_OK) - return false; + sysio.error.write = _fh->fs().write(_fh, sysio.write_in.chunk, + sysio.write_in.count, out_count); + if (sysio.error.write != Vfs::File_io_service::WRITE_OK) + return false; - _fh->advance_seek(out_count); + _fh->advance_seek(out_count); - sysio->write_out.count = out_count; - offset = out_count; + sysio.write_out.count = out_count; + offset = out_count; - return true; - } + return true; + } - bool read(Sysio *sysio) override - { - size_t count = min(sysio->read_in.count, sizeof(sysio->read_out.chunk)); + bool read(Sysio &sysio) override + { + size_t count = min(sysio.read_in.count, sizeof(sysio.read_out.chunk)); - Vfs::file_size out_count = 0; + Vfs::file_size out_count = 0; - sysio->error.read = _fh->fs().read(_fh, sysio->read_out.chunk, count, out_count); + sysio.error.read = _fh->fs().read(_fh, sysio.read_out.chunk, count, out_count); - if (sysio->error.read != Vfs::File_io_service::READ_OK) - return false; + if (sysio.error.read != Vfs::File_io_service::READ_OK) + return false; - sysio->read_out.count = out_count; + sysio.read_out.count = out_count; - _fh->advance_seek(out_count); + _fh->advance_seek(out_count); - return true; - } - - bool fstat(Sysio *sysio) override - { - /* - * 'sysio.stat_in' is not used in '_fh->ds().stat()', - * so no 'sysio' member translation is needed here - */ - Vfs::Directory_service::Stat stat; - sysio->error.stat = _fh->ds().stat(_leaf_path.base(), stat); - sysio->fstat_out.st = stat; - - return (sysio->error.stat == Vfs::Directory_service::STAT_OK); - - } - - bool ftruncate(Sysio *sysio) override - { - - sysio->error.ftruncate = _fh->fs().ftruncate(_fh, sysio->ftruncate_in.length); - - return (sysio->error.ftruncate == Vfs::File_io_service::FTRUNCATE_OK); - } - - bool fcntl(Sysio *sysio) override - { - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: - - sysio->fcntl_out.result = _fh->status_flags(); - return true; - - case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: - _fh->status_flags(sysio->fcntl_in.long_arg); - return true; - - default: - - PWRN("invalid fcntl command %d", sysio->fcntl_in.cmd); - sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; - return false; - }; - } + return true; + } + bool fstat(Sysio &sysio) override + { /* - * The 'dirent' function for the root directory only (the - * 'Dir_file_system::open()' function handles all requests referring - * to directories). Hence, '_path' is the absolute path of the - * directory to inspect. + * 'sysio.stat_in' is not used in '_fh->ds().stat()', + * so no 'sysio' member translation is needed here */ - bool dirent(Sysio *sysio) override - { - /* - * Return artificial dir entries for "." and ".." - */ - unsigned const index = _fh->seek() / sizeof(Sysio::Dirent); - if (index < 2) { - sysio->dirent_out.entry.type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY; - strncpy(sysio->dirent_out.entry.name, - index ? ".." : ".", - sizeof(sysio->dirent_out.entry.name)); + Vfs::Directory_service::Stat stat; + sysio.error.stat = _fh->ds().stat(_leaf_path.base(), stat); + sysio.fstat_out.st = stat; - sysio->dirent_out.entry.fileno = 1; - _fh->advance_seek(sizeof(Sysio::Dirent)); - return true; - } + return (sysio.error.stat == Vfs::Directory_service::STAT_OK); - /* - * Delegate remaining dir-entry request to the actual file system. - * Align index range to zero when calling the directory service. - */ + } - Vfs::Directory_service::Dirent dirent; - if (!_fh->ds().dirent(_path.base(), index - 2, dirent)) - return false; - sysio->dirent_out.entry = dirent; + bool ftruncate(Sysio &sysio) override + { + sysio.error.ftruncate = _fh->fs().ftruncate(_fh, sysio.ftruncate_in.length); + + return (sysio.error.ftruncate == Vfs::File_io_service::FTRUNCATE_OK); + } + + bool fcntl(Sysio &sysio) override + { + switch (sysio.fcntl_in.cmd) { + + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: + + sysio.fcntl_out.result = _fh->status_flags(); + return true; + + case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: + _fh->status_flags(sysio.fcntl_in.long_arg); + return true; + + default: + + PWRN("invalid fcntl command %d", sysio.fcntl_in.cmd); + sysio.error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; + return false; + }; + } + + /* + * The 'dirent' function for the root directory only (the + * 'Dir_file_system::open()' function handles all requests referring + * to directories). Hence, '_path' is the absolute path of the + * directory to inspect. + */ + bool dirent(Sysio &sysio) override + { + /* + * Return artificial dir entries for "." and ".." + */ + unsigned const index = _fh->seek() / sizeof(Sysio::Dirent); + if (index < 2) { + sysio.dirent_out.entry.type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY; + strncpy(sysio.dirent_out.entry.name, + index ? ".." : ".", + sizeof(sysio.dirent_out.entry.name)); + + sysio.dirent_out.entry.fileno = 1; _fh->advance_seek(sizeof(Sysio::Dirent)); return true; } - /** - * Return size of file that the I/O channel refers to - * - * Note that this function overwrites the 'sysio' argument. Do not - * call it prior saving all input arguments from the original sysio - * structure. + /* + * Delegate remaining dir-entry request to the actual file system. + * Align index range to zero when calling the directory service. */ - size_t size(Sysio *sysio) - { - if (fstat(sysio)) - return sysio->fstat_out.st.size; - return 0; + Vfs::Directory_service::Dirent dirent; + if (!_fh->ds().dirent(_path.base(), index - 2, dirent)) + return false; + sysio.dirent_out.entry = dirent; + + _fh->advance_seek(sizeof(Sysio::Dirent)); + return true; + } + + /** + * Return size of file that the I/O channel refers to + * + * Note that this function overwrites the 'sysio' argument. Do not + * call it prior saving all input arguments from the original sysio + * structure. + */ + size_t size(Sysio &sysio) + { + if (fstat(sysio)) + return sysio.fstat_out.st.size; + + return 0; + } + + bool ioctl(Sysio &sysio) override + { + Vfs::File_system::Ioctl_arg arg = (Vfs::File_system::Ioctl_arg)sysio.ioctl_in.argp; + + sysio.error.ioctl = _fh->fs().ioctl(_fh, sysio.ioctl_in.request, arg, sysio.ioctl_out); + + return (sysio.error.ioctl == Vfs::File_io_service::IOCTL_OK); + } + + bool lseek(Sysio &sysio) override + { + switch (sysio.lseek_in.whence) { + case Sysio::LSEEK_SET: _fh->seek(sysio.lseek_in.offset); break; + case Sysio::LSEEK_CUR: _fh->advance_seek(sysio.lseek_in.offset); break; + case Sysio::LSEEK_END: + off_t offset = sysio.lseek_in.offset; + sysio.fstat_in.fd = sysio.lseek_in.fd; + _fh->seek(size(sysio) + offset); + break; } + sysio.lseek_out.offset = _fh->seek(); + return true; + } - bool ioctl(Sysio *sysio) override - { - Vfs::File_system::Ioctl_arg arg = (Vfs::File_system::Ioctl_arg)sysio->ioctl_in.argp; + bool check_unblock(bool rd, bool wr, bool ex) const override + { + return _fh->fs().check_unblock(_fh, rd, wr, ex); + } - sysio->error.ioctl = _fh->fs().ioctl(_fh, sysio->ioctl_in.request, arg, sysio->ioctl_out); + bool path(char *path, size_t len) override + { + strncpy(path, _path.base(), len); + path[len - 1] = '\0'; - return (sysio->error.ioctl == Vfs::File_io_service::IOCTL_OK); - } - - bool lseek(Sysio *sysio) override - { - switch (sysio->lseek_in.whence) { - case Sysio::LSEEK_SET: _fh->seek(sysio->lseek_in.offset); break; - case Sysio::LSEEK_CUR: _fh->advance_seek(sysio->lseek_in.offset); break; - case Sysio::LSEEK_END: - off_t offset = sysio->lseek_in.offset; - sysio->fstat_in.fd = sysio->lseek_in.fd; - _fh->seek(size(sysio) + offset); - break; - } - sysio->lseek_out.offset = _fh->seek(); - return true; - } - - bool check_unblock(bool rd, bool wr, bool ex) const override - { - return _fh->fs().check_unblock(_fh, rd, wr, ex); - } - - bool path(char *path, size_t len) override - { - strncpy(path, _path.base(), len); - path[len - 1] = '\0'; - - return true; - } - - - /************************************** - ** Signal_dispatcher_base interface ** - **************************************/ - - /** - * Called by Noux main loop on the occurrence of new input - */ - void dispatch(unsigned) override - { - Io_channel::invoke_all_notifiers(); - } - }; -} + return true; + } +}; #endif /* _NOUX__VFS_IO_CHANNEL_H_ */ diff --git a/repos/ports/src/noux/wake_up_notifier.h b/repos/ports/src/noux/wake_up_notifier.h index 002616172d..58c2ddd8dc 100644 --- a/repos/ports/src/noux/wake_up_notifier.h +++ b/repos/ports/src/noux/wake_up_notifier.h @@ -18,21 +18,16 @@ #include #include -namespace Noux { +namespace Noux { struct Wake_up_notifier; } - struct Wake_up_notifier : List::Element - { - Lock *lock; - Wake_up_notifier(Lock *lock = 0) - : lock(lock) { } +struct Noux::Wake_up_notifier : List::Element +{ + Lock *lock; - void wake_up() - { - if (lock) - lock->unlock(); - } - }; + Wake_up_notifier(Lock *lock = nullptr) : lock(lock) { } + + void wake_up() { if (lock) lock->unlock(); } }; #endif /* _NOUX__WAKE_UP_NOTIFIER__H_ */