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
This commit is contained in:
Norman Feske 2017-01-06 12:12:39 +01:00
parent f957fcdd98
commit 82e6d7cf52
40 changed files with 4666 additions and 5174 deletions

View File

@ -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<enum Signal, SIGNAL_QUEUE_SIZE,
Ring_buffer_unsynchronized> 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<enum Signal, SIGNAL_QUEUE_SIZE,
Ring_buffer_unsynchronized> 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; });
};
};

View File

@ -15,102 +15,105 @@
#define _NOUX__ARGS_H_
/* Genode includes */
#include <os/attached_ram_dataspace.h>
#include <base/attached_ram_dataspace.h>
#include <util/string.h>
#include <base/log.h>
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<char>(), 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<char>(), size)
{
if (from.len() > size - 2)
throw Overrun();
memcpy(_buf, from.base(), from.len() + 1);
}
using Attached_ram_dataspace::cap;
};
#endif /* _NOUX__ARGS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -23,140 +23,142 @@
#include <range_checked_index.h>
namespace Noux {
template <size_t> class Child_env;
using namespace Genode;
/**
* \param ARGS_SIZE size of the argument buffer given
* to the constructor
*/
template <size_t ARGS_SIZE>
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<unsigned int>
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<unsigned int>
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 <Noux::size_t ARGS_SIZE>
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<unsigned int>
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<unsigned int>
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_ */

View File

@ -33,161 +33,164 @@ namespace Noux {
typedef Local_service<Cpu_session_component> Cpu_service;
typedef Local_service<Rpc_object<Session> > 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 <typename T>
static Genode::Service *_find_service(Genode::Registry<T> &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_session_component &>(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 <typename T>
static Genode::Service *_find_service(Genode::Registry<T> &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_session_component &>(pd).address_space_region_map();
}
};
#endif /* _NOUX__CHILD_POLICY_H_ */

View File

@ -34,137 +34,140 @@
#include <pd_session_component.h>
namespace Noux {
class Cpu_session_component;
using namespace Genode;
class Cpu_session_component : public Rpc_object<Cpu_session>
{
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 &registry)
: _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<Cpu_thread> 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_session> 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> native_cpu() override {
return _cpu.native_cpu(); }
};
}
class Noux::Cpu_session_component : public Rpc_object<Cpu_session>
{
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<Static_dataspace_info> _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 &registry)
:
_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<Cpu_thread> 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_session> 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> native_cpu() override {
return _cpu.native_cpu(); }
};
#endif /* _NOUX__CPU_SESSION_COMPONENT_H_ */

View File

@ -19,163 +19,186 @@
#include <dataspace/client.h>
namespace Noux {
class Dataspace_registry;
class Dataspace_user;
class Dataspace_info;
class Dataspace_registry;
struct Static_dataspace_info;
struct Dataspace_user : List<Dataspace_user>::Element
{
virtual void dissolve(Dataspace_info &ds) = 0;
};
class Dataspace_info : public Object_pool<Dataspace_info>::Entry
{
private:
size_t _size;
Dataspace_capability _ds_cap;
Lock _users_lock;
List<Dataspace_user> _users;
public:
Dataspace_info(Dataspace_capability ds_cap)
:
Object_pool<Dataspace_info>::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<Region_map> lookup_region_map(addr_t const addr)
{
/* by default a dataspace is no sub region map, so return invalid */
return Capability<Region_map>();
}
};
class Dataspace_registry : public Object_pool<Dataspace_info>
{
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<Dataspace_user>::Element
{
virtual void dissolve(Dataspace_info &ds) = 0;
};
class Noux::Dataspace_info : public Object_pool<Dataspace_info>::Entry
{
private:
size_t _size;
Dataspace_capability _ds_cap;
Lock _users_lock;
List<Dataspace_user> _users;
public:
Dataspace_info(Dataspace_capability ds_cap)
:
Object_pool<Dataspace_info>::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<Region_map> lookup_region_map(addr_t const addr)
{
/* by default a dataspace is no sub region map, so return invalid */
return Capability<Region_map>();
}
};
class Noux::Dataspace_registry : public Object_pool<Dataspace_info>
{
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_ */

View File

@ -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 <base/signal.h>
/* Noux includes */
#include <destruct_queue.h>
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_ */

View File

@ -18,77 +18,81 @@
#include <base/allocator.h>
#include <util/list.h>
namespace Noux {
namespace Noux { class Destruct_queue; }
class Destruct_queue
{
public:
struct Element_base : Genode::List<Element_base>::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 <typename T>
class Element : public Element_base
{
private:
struct Element_base : Genode::List<Element_base>::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 <typename T>
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<T*>(this));
}
};
virtual ~Element() { };
private:
Genode::List<Element_base> _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<T*>(this));
}
}
};
};
}
private:
Genode::List<Element_base> _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_ */

View File

@ -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 <io_channel.h>
namespace Noux {
class Sysio;
struct Dummy_input_io_channel : public Io_channel
{ };
}
#endif /* _NOUX__DUMMY_INPUT_IO_CHANNEL_H_ */

View File

@ -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 <util/string.h>
#include <os/attached_ram_dataspace.h>
#include <base/printf.h>
#include <base/attached_ram_dataspace.h>
/* Noux includes */
#include <path.h>
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<Sysio::Env>())
{
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<Sysio::Env>())
{
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_ */

View File

@ -22,159 +22,156 @@
#include <parent_exit.h>
#include <parent_execve.h>
namespace Noux {
namespace Noux { class Family_member; }
class Family_member : public List<Family_member>::Element,
public Parent_exit,
public Parent_execve
{
private:
int const _pid;
Lock _lock;
List<Family_member> _list;
bool _has_exited;
int _exit_status;
class Noux::Family_member : public List<Family_member>::Element,
public Parent_exit,
public Parent_execve
{
private:
protected:
int const _pid;
Lock _lock;
List<Family_member> _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_ */

View File

@ -17,105 +17,105 @@
/* Noux includes */
#include <io_channel.h>
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> 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> 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> &io_channel)
{
_fds[fd].io_channel = io_channel;
_fds[fd].allocated = true;
}
void _reset_fd(int fd)
{
_fds[fd].io_channel = Shared_pointer<Io_channel>();
_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> 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> &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<Io_channel>();
_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> 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> io_channel_by_fd(int fd) const
{
if (!fd_in_use(fd))
return Shared_pointer<Io_channel>();
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> io_channel_by_fd(int fd) const
{
if (!fd_in_use(fd))
return Shared_pointer<Io_channel>();
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_ */

View File

@ -28,174 +28,176 @@
#include <io_channel_listener.h>
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<Wake_up_notifier> _notifiers;
Lock _notifiers_lock;
List<Io_channel_listener> _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<Wake_up_notifier> _notifiers;
Lock _notifiers_lock;
List<Io_channel_listener> _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_ */

View File

@ -20,9 +20,7 @@
/* Noux includes */
#include <interrupt_handler.h>
namespace Noux {
typedef List_element<Interrupt_handler> Io_channel_listener;
}
namespace Noux { typedef List_element<Interrupt_handler> Io_channel_listener; }
#endif /* _NOUX__IO_CHANNEL_LISTENER__H_ */

View File

@ -20,63 +20,62 @@
namespace Noux {
struct Io_receptor : List<Io_receptor>::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<Io_receptor> _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<Io_receptor>::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<Io_receptor> _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_ */

View File

@ -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 &registry)
:
_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);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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> io_channel(socket_io_channel, Genode::env()->heap());
Shared_pointer<Io_channel> 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> io_channel(socket_io_channel, Genode::env()->heap());
Socket_io_channel *socket_io_channel = new (_heap) Socket_io_channel(socket);
Shared_pointer<Io_channel> 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;
}
}

View File

@ -32,492 +32,470 @@
#include <fcntl.h>
#include <errno.h>
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_ */

View File

@ -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)

View File

@ -18,18 +18,17 @@
#include <noux_session/sysio.h>
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_ */

View File

@ -42,13 +42,14 @@ class Noux::Pd_session_component : public Rpc_object<Pd_session>
/**
* 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>
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<Region_map> lookup_region_map(addr_t const addr)
@ -76,13 +77,15 @@ class Noux::Pd_session_component : public Rpc_object<Pd_session>
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();

View File

@ -18,350 +18,330 @@
#include <io_channel.h>
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> _pipe;
Signal_receiver &_sig_rec;
public:
Pipe_sink_io_channel(Shared_pointer<Pipe> 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> _pipe;
Signal_receiver &_sig_rec;
public:
Pipe_source_io_channel(Shared_pointer<Pipe> 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<Pipe_sink_io_channel> _write_ready_handler;
void _handle_write_ready() { Io_channel::invoke_all_notifiers(); }
Shared_pointer<Pipe> _pipe;
public:
Pipe_sink_io_channel(Shared_pointer<Pipe> 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<Pipe_source_io_channel> _read_avail_handler;
void _handle_read_avail() { Io_channel::invoke_all_notifiers(); }
Shared_pointer<Pipe> _pipe;
public:
Pipe_source_io_channel(Shared_pointer<Pipe> 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_ */

View File

@ -26,163 +26,164 @@
/* Genode includes */
#include <ram_session/client.h>
#include <base/rpc_server.h>
#include <base/env.h>
/* Noux includes */
#include <dataspace_registry.h>
namespace Noux {
struct Ram_dataspace_info : Dataspace_info,
List<Ram_dataspace_info>::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<Ram_session>
{
private:
Rpc_entrypoint &_ep;
List<Ram_dataspace_info> _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 &registry)
: _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<Ram_dataspace>(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<Ram_dataspace_info>::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<char>(), src_ds.local_addr<char>(), 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<char>() + dst_offset, src, len);
} catch (...) { warning("poke: failed to attach RAM dataspace"); }
}
};
class Noux::Ram_session_component : public Rpc_object<Ram_session>
{
private:
Ram_session &_ram;
Allocator &_alloc;
Rpc_entrypoint &_ep;
List<Ram_dataspace_info> _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 &registry)
:
_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<Ram_dataspace>(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_ */

View File

@ -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 <base/printf.h>
#include <base/stdint.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <vfs/single_file_system.h>
/*-
* Copyright (c) 2010, 2012
* Thorsten Glaser <tg@mirbsd.org>
* Copyright (c) 2012
* Josef Soentgen <cnuke@mirbsd.org>
*
* 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_ */

View File

@ -17,28 +17,29 @@
namespace Noux {
class Index_out_of_range { };
template <typename T>
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 <typename> struct Range_checked_index;
}
template <typename T>
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_ */

View File

@ -36,6 +36,8 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
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<Region_map>,
* 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<Region_map> 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<Region_map>,
*/
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<Region_map>,
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_map>,
}
}
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<Region_map>,
_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<Region_map>,
******************************/
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<Region_map>,
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<Region_map>,
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);
});
}
};

View File

@ -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<Rom_session>
*/
Constructible<Rom_connection> _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<Rom_session>
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<Rom_session>
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()

View File

@ -23,135 +23,137 @@
#include <noux_session/sysio.h>
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 <typename T>
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<typename To>
Shared_pointer<To> dynamic_pointer_cast()
{
return Shared_pointer<To>(dynamic_cast<To *>(_ptr), _alloc);
}
};
template <typename T> 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 <typename T>
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<typename To>
Shared_pointer<To> dynamic_pointer_cast()
{
return Shared_pointer<To>(dynamic_cast<To *>(_ptr), _alloc);
}
};
#endif /* _NOUX__SHARED_POINTER_H_ */

View File

@ -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 <base/log.h>
#include <util/string.h>
#include <vfs/single_file_system.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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_ */

View File

@ -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 <child.h>
#include <child_env.h>
#include <vfs_io_channel.h>
#include <pipe_io_channel.h>
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<const unsigned char*>(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_channel> 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_channel> 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_channel> 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_channel> 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<Io_channel>
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<sizeof(_sysio.execve_in.args)>
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_channel> io = io_channel_by_fd(fd);
notifiers[i].lock = &_blocker;
io->register_wake_up_notifier(&notifiers[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_channel> 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_channel> io = io_channel_by_fd(fd);
io->unregister_wake_up_notifier(&notifiers[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<Child *>(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> pipe (new (_heap) Pipe, _heap);
Shared_pointer<Io_channel> pipe_sink (new (_heap) Pipe_sink_io_channel (pipe, _env.ep()), _heap);
Shared_pointer<Io_channel> 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;
}

View File

@ -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 <base/printf.h>
#include <base/lock.h>
#include <terminal_session/connection.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <vfs/file_system.h>
namespace Noux { Terminal::Connection *terminal(); }
#endif /* _NOUX__TERMINAL_CONNECTION_H_ */

View File

@ -24,210 +24,201 @@
#include <io_channel.h>
#include <noux_session/sysio.h>
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<Terminal_io_channel> _read_avail_handler;
bool eof = false;
enum Type { STDIN, STDOUT, STDERR } type;
Ring_buffer<char, Sysio::CHUNK_SIZE + 1> 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<char, Sysio::CHUNK_SIZE + 1> 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_ */

View File

@ -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 <timer_session/connection.h>
#include <os/alarm.h>
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<Timeout_scheduler> _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_ */

View File

@ -1,6 +1,7 @@
/*
* \brief User information
* \author Josef Soentgen
* \author Norman Feske
* \date 2012-07-23
*/
@ -22,49 +23,54 @@
#include <noux_session/sysio.h>
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<Sysio::MAX_USERNAME_LEN> Name;
typedef String<Sysio::MAX_SHELL_LEN> Shell;
typedef String<Sysio::MAX_HOME_LEN> Home;
private:
unsigned const _uid;
unsigned const _gid;
Name const _name;
Shell const _shell;
Home const _home;
template <typename S>
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_ */

View File

@ -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 <util/noncopyable.h>
#include <util/xml_node.h>
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_ */

View File

@ -18,212 +18,204 @@
#include <io_channel.h>
#include <vfs/dir_file_system.h>
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<Vfs_io_channel> _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_ */

View File

@ -18,21 +18,16 @@
#include <util/list.h>
#include <base/lock.h>
namespace Noux {
namespace Noux { struct Wake_up_notifier; }
struct Wake_up_notifier : List<Wake_up_notifier>::Element
{
Lock *lock;
Wake_up_notifier(Lock *lock = 0)
: lock(lock) { }
struct Noux::Wake_up_notifier : List<Wake_up_notifier>::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_ */