mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
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:
parent
f957fcdd98
commit
82e6d7cf52
@ -30,479 +30,480 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
using namespace Genode;
|
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 */
|
Vfs::file_size size;
|
||||||
enum Signal {
|
unsigned mode;
|
||||||
SIG_INT = 2,
|
unsigned uid;
|
||||||
SIG_CHLD = 20,
|
unsigned gid;
|
||||||
};
|
unsigned long inode;
|
||||||
|
unsigned long device;
|
||||||
|
|
||||||
enum { SIGNAL_QUEUE_SIZE = 32 };
|
Stat & operator= (Vfs::Directory_service::Stat const &stat)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
Vfs::file_size size;
|
size = stat.size;
|
||||||
unsigned mode;
|
mode = stat.mode;
|
||||||
unsigned uid;
|
uid = stat.uid;
|
||||||
unsigned gid;
|
gid = stat.gid;
|
||||||
unsigned long inode;
|
inode = stat.inode;
|
||||||
unsigned long device;
|
device = stat.device;
|
||||||
|
|
||||||
Stat & operator= (Vfs::Directory_service::Stat const &stat)
|
return *this;
|
||||||
{
|
}
|
||||||
size = stat.size;
|
};
|
||||||
mode = stat.mode;
|
|
||||||
uid = stat.uid;
|
|
||||||
gid = stat.gid;
|
|
||||||
inode = stat.inode;
|
|
||||||
device = stat.device;
|
|
||||||
|
|
||||||
return *this;
|
/**
|
||||||
}
|
* Argument structure used for ioctl syscall
|
||||||
};
|
*/
|
||||||
|
struct Ioctl_in
|
||||||
|
{
|
||||||
|
typedef Vfs::File_io_service::Ioctl_opcode Opcode;
|
||||||
|
|
||||||
/**
|
typedef Vfs::File_io_service::Ioctl_value Value;
|
||||||
* Argument structure used for ioctl syscall
|
|
||||||
*/
|
Opcode request;
|
||||||
struct Ioctl_in
|
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;
|
enum Fcntl_cmd {
|
||||||
int argp;
|
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 };
|
/**
|
||||||
|
* Array containing the file descriptors, starting with those
|
||||||
enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::DIRENT_MAX_NAME_LEN };
|
* referring to rd, followed by wr, and finally ex
|
||||||
|
|
||||||
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
|
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;
|
* Note that even though the corner case of num_rd + num_wr +
|
||||||
char name[DIRENT_MAX_NAME_LEN];
|
* num_ex == MAX_FDS is technically valid, this condition hints
|
||||||
|
* at a possible attempt to over popupate the array (see the
|
||||||
Dirent & operator= (Vfs::Directory_service::Dirent const &dirent)
|
* implementation of 'select' in the Noux libc plugin). Hence,
|
||||||
{
|
* we regard this case as an error, too.
|
||||||
fileno = dirent.fileno;
|
*/
|
||||||
type = dirent.type;
|
return total_fds() >= MAX_FDS;
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input and output argument type of select syscall
|
* Return true of fd set index should be watched for reading
|
||||||
*/
|
*/
|
||||||
struct Select_fds
|
bool watch_for_rd(unsigned i) const { return i < num_rd; }
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 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); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket related structures
|
* Return true if fd set index should be watched for writing
|
||||||
*/
|
*/
|
||||||
enum { MAX_HOSTNAME_LEN = 255 };
|
bool watch_for_wr(unsigned i) const {
|
||||||
typedef char Hostname[MAX_HOSTNAME_LEN];
|
return (i >= num_rd) && (i < num_rd + num_wr); }
|
||||||
|
|
||||||
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];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 };
|
bool watch_for_ex(unsigned i) const {
|
||||||
enum { MAX_USERNAME_LEN = 32 };
|
return (i >= num_rd + num_wr) && (i < total_fds()); }
|
||||||
typedef char User[MAX_USERNAME_LEN];
|
};
|
||||||
enum { MAX_SHELL_LEN = 16 };
|
|
||||||
typedef char Shell[MAX_SHELL_LEN];
|
struct Select_timeout
|
||||||
enum { MAX_HOME_LEN = 128 };
|
{
|
||||||
typedef char Home[MAX_HOME_LEN];
|
long sec, usec;
|
||||||
typedef unsigned int Uid;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* time/clock definitions
|
* Set timeout to infinity
|
||||||
*/
|
*/
|
||||||
enum Clock_Id { CLOCK_ID_SECOND };
|
void set_infinite() { sec = -1; usec = -1; }
|
||||||
|
|
||||||
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 };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket related errors
|
* Return true if the timeout is infinite
|
||||||
*/
|
*/
|
||||||
enum Accept_error { ACCEPT_ERR_AGAIN, ACCEPT_ERR_WOULD_BLOCK,
|
bool infinite() const { return (sec == -1) && (usec == -1); }
|
||||||
ACCEPT_ERR_INVALID, ACCEPT_ERR_NO_MEMORY,
|
|
||||||
ACCEPT_ERR_NOT_SUPPORTED };
|
|
||||||
|
|
||||||
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,
|
* Socket related structures
|
||||||
CONNECT_ERR_NO_PERM, CONNECT_ERR_ADDR_IN_USE,
|
*/
|
||||||
CONNECT_ERR_IN_PROGRESS, CONNECT_ERR_IS_CONNECTED,
|
enum { MAX_HOSTNAME_LEN = 255 };
|
||||||
CONNECT_ERR_RESET, CONNECT_ERR_ABORTED,
|
typedef char Hostname[MAX_HOSTNAME_LEN];
|
||||||
CONNECT_ERR_NO_ROUTE };
|
|
||||||
|
|
||||||
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,
|
enum { MAX_ADDRINFO_RESULTS = 4 };
|
||||||
RECV_ERR_CONN_REFUSED, RECV_ERR_INVALID,
|
|
||||||
RECV_ERR_NOT_CONNECTED, RECV_ERR_NO_MEMORY };
|
|
||||||
|
|
||||||
enum Send_error { SEND_ERR_AGAIN, SEND_ERR_WOULD_BLOCK,
|
struct in_addr
|
||||||
SEND_ERR_CONNECTION_RESET, SEND_ERR_INVALID,
|
{
|
||||||
SEND_ERR_IS_CONNECTED, SEND_ERR_NO_MEMORY };
|
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,
|
struct sockaddr_in {
|
||||||
SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY };
|
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,
|
struct addrinfo {
|
||||||
UTIMES_ERR_NAME_TOO_LONG, UTIMES_ERR_NO_ENTRY,
|
int ai_flags;
|
||||||
UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM,
|
int ai_family;
|
||||||
UTIMES_ERR_READ_ONLY };
|
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;
|
* time/clock definitions
|
||||||
Vfs::Directory_service::Stat_result stat;
|
*/
|
||||||
Vfs::File_io_service::Ftruncate_result ftruncate;
|
enum Clock_Id { CLOCK_ID_SECOND };
|
||||||
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;
|
|
||||||
|
|
||||||
Fcntl_error fcntl;
|
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = Vfs::Directory_service::NUM_GENERAL_ERRORS };
|
||||||
Execve_error execve;
|
enum Execve_error { EXECVE_NONEXISTENT = Vfs::Directory_service::NUM_GENERAL_ERRORS, EXECVE_NOMEM };
|
||||||
Select_error select;
|
enum Fork_error { FORK_NOMEM = Vfs::Directory_service::NUM_GENERAL_ERRORS };
|
||||||
Accept_error accept;
|
enum Select_error { SELECT_ERR_INTERRUPT };
|
||||||
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;
|
|
||||||
|
|
||||||
} 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; },
|
enum Connect_error { CONNECT_ERR_ACCESS, CONNECT_ERR_AGAIN,
|
||||||
{ size_t count; });
|
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; },
|
enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT,
|
||||||
{ int result; });
|
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; },
|
enum Kill_error { KILL_ERR_SRCH };
|
||||||
{ off_t offset; });
|
|
||||||
|
|
||||||
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; },
|
Fcntl_error fcntl;
|
||||||
{ Chunk chunk; size_t count; });
|
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; },
|
} error;
|
||||||
{ Chunk chunk; size_t count; });
|
|
||||||
|
|
||||||
SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { });
|
union {
|
||||||
|
|
||||||
SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; },
|
SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; },
|
||||||
{ Select_fds fds; });
|
{ size_t count; });
|
||||||
|
|
||||||
SYSIO_DECL(fork, { addr_t ip; addr_t sp;
|
SYSIO_DECL(stat, { Path path; }, { Stat st; });
|
||||||
addr_t parent_cap_addr; },
|
|
||||||
{ int pid; });
|
|
||||||
|
|
||||||
SYSIO_DECL(getpid, { }, { int pid; });
|
SYSIO_DECL(symlink, { Path oldpath; Path newpath; }, { });
|
||||||
|
|
||||||
SYSIO_DECL(wait4, { int pid; bool nohang; },
|
SYSIO_DECL(fstat, { int fd; }, { Stat st; });
|
||||||
{ int pid; int status; });
|
|
||||||
SYSIO_DECL(pipe, { }, { int fd[2]; });
|
|
||||||
|
|
||||||
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; },
|
SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { });
|
||||||
{ int fd; });
|
|
||||||
|
|
||||||
/* XXX for now abuse Chunk for passing optval */
|
SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; },
|
||||||
SYSIO_DECL(getsockopt, { int fd; int level; int optname; Chunk optval;
|
{ off_t offset; });
|
||||||
socklen_t optlen; }, { int result; });
|
|
||||||
|
|
||||||
SYSIO_DECL(setsockopt, { int fd; int level;
|
SYSIO_DECL(dirent, { int fd; }, { Dirent entry; });
|
||||||
int optname; Chunk optval;
|
|
||||||
socklen_t optlen; }, { });
|
|
||||||
|
|
||||||
SYSIO_DECL(accept, { int fd; struct sockaddr addr; socklen_t addrlen; },
|
SYSIO_DECL(read, { int fd; size_t count; },
|
||||||
{ int fd; });
|
{ Chunk chunk; size_t count; });
|
||||||
|
|
||||||
SYSIO_DECL(bind, { int fd; struct sockaddr addr;
|
SYSIO_DECL(readlink, { Path path; size_t bufsiz; },
|
||||||
socklen_t addrlen; }, { int result; });
|
{ Chunk chunk; size_t count; });
|
||||||
|
|
||||||
SYSIO_DECL(getpeername, { int fd; struct sockaddr addr;
|
SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { });
|
||||||
socklen_t addrlen; }, { });
|
|
||||||
|
|
||||||
SYSIO_DECL(listen, { int fd; int type; int backlog; },
|
SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; },
|
||||||
{ int result; });
|
{ Select_fds fds; });
|
||||||
|
|
||||||
SYSIO_DECL(send, { int fd; Chunk buf; size_t len; int flags; },
|
SYSIO_DECL(fork, { addr_t ip; addr_t sp;
|
||||||
{ ssize_t len; });
|
addr_t parent_cap_addr; },
|
||||||
|
{ int pid; });
|
||||||
|
|
||||||
SYSIO_DECL(sendto, { int fd; Chunk buf; size_t len; int flags;
|
SYSIO_DECL(getpid, { }, { int pid; });
|
||||||
struct sockaddr dest_addr; socklen_t addrlen; },
|
|
||||||
{ ssize_t len; });
|
|
||||||
|
|
||||||
SYSIO_DECL(recv, { int fd; Chunk buf; size_t len; int flags; },
|
SYSIO_DECL(wait4, { int pid; bool nohang; },
|
||||||
{ size_t len; });
|
{ int pid; int status; });
|
||||||
|
SYSIO_DECL(pipe, { }, { int fd[2]; });
|
||||||
|
|
||||||
SYSIO_DECL(recvfrom, { int fd; Chunk buf; size_t len; int flags;
|
SYSIO_DECL(dup2, { int fd; int to_fd; }, { int fd; });
|
||||||
struct sockaddr src_addr; socklen_t addrlen; },
|
|
||||||
{ size_t len; });
|
|
||||||
|
|
||||||
SYSIO_DECL(shutdown, { int fd; int how; }, { });
|
SYSIO_DECL(unlink, { Path path; }, { });
|
||||||
|
|
||||||
SYSIO_DECL(connect, { int fd; struct sockaddr addr; socklen_t addrlen; },
|
SYSIO_DECL(rename, { Path from_path; Path to_path; }, { });
|
||||||
{ int result; });
|
|
||||||
|
|
||||||
SYSIO_DECL(userinfo, { int request; Uid uid; },
|
SYSIO_DECL(mkdir, { Path path; int mode; }, { });
|
||||||
{ User name; Uid uid; Uid gid; Shell shell;
|
|
||||||
Home home; });
|
|
||||||
|
|
||||||
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; },
|
/* XXX for now abuse Chunk for passing optval */
|
||||||
{ unsigned long sec; unsigned long nsec; });
|
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; });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,102 +15,105 @@
|
|||||||
#define _NOUX__ARGS_H_
|
#define _NOUX__ARGS_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <os/attached_ram_dataspace.h>
|
#include <base/attached_ram_dataspace.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Args;
|
||||||
class Args
|
class Args_dataspace;
|
||||||
{
|
|
||||||
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 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_ */
|
#endif /* _NOUX__ARGS_H_ */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,140 +23,142 @@
|
|||||||
#include <range_checked_index.h>
|
#include <range_checked_index.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
template <size_t> class Child_env;
|
||||||
using namespace Genode;
|
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_ */
|
#endif /* _NOUX__CHILD_ENV_H_ */
|
||||||
|
@ -33,161 +33,164 @@ namespace Noux {
|
|||||||
typedef Local_service<Cpu_session_component> Cpu_service;
|
typedef Local_service<Cpu_session_component> Cpu_service;
|
||||||
typedef Local_service<Rpc_object<Session> > Noux_service;
|
typedef Local_service<Rpc_object<Session> > Noux_service;
|
||||||
|
|
||||||
class Child_policy : public Genode::Child_policy
|
class 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 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_ */
|
#endif /* _NOUX__CHILD_POLICY_H_ */
|
||||||
|
@ -34,137 +34,140 @@
|
|||||||
#include <pd_session_component.h>
|
#include <pd_session_component.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Cpu_session_component;
|
||||||
using namespace Genode;
|
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 ®istry)
|
|
||||||
: _ep(ep), _forked(forked), _cpu(label.string()), _registry(registry)
|
|
||||||
{ _ep.manage(this); }
|
|
||||||
|
|
||||||
~Cpu_session_component()
|
|
||||||
{
|
|
||||||
_ep.dissolve(this);
|
|
||||||
|
|
||||||
if (!_trace_control.valid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto lambda = [&] (Static_dataspace_info *rdi) { return rdi; };
|
|
||||||
Static_dataspace_info *ds_info = _registry.apply(_trace_control, lambda);
|
|
||||||
if (ds_info)
|
|
||||||
destroy(env()->heap(), ds_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Explicitly start main thread, only meaningful when
|
|
||||||
* 'forked' is true
|
|
||||||
*/
|
|
||||||
void start_main_thread(addr_t ip, addr_t sp)
|
|
||||||
{
|
|
||||||
Capability<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 ®istry)
|
||||||
|
:
|
||||||
|
_ep(ep), _forked(forked), _cpu(env, label.string()), _registry(registry)
|
||||||
|
{
|
||||||
|
_ep.manage(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cpu_session_component()
|
||||||
|
{
|
||||||
|
_ep.dissolve(this);
|
||||||
|
|
||||||
|
if (!_trace_control.valid())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly start main thread, only meaningful when
|
||||||
|
* 'forked' is true
|
||||||
|
*/
|
||||||
|
void start_main_thread(addr_t ip, addr_t sp)
|
||||||
|
{
|
||||||
|
Capability<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_ */
|
#endif /* _NOUX__CPU_SESSION_COMPONENT_H_ */
|
||||||
|
@ -19,163 +19,186 @@
|
|||||||
#include <dataspace/client.h>
|
#include <dataspace/client.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Dataspace_user;
|
||||||
class Dataspace_registry;
|
|
||||||
class Dataspace_info;
|
class Dataspace_info;
|
||||||
|
class Dataspace_registry;
|
||||||
|
|
||||||
|
struct Static_dataspace_info;
|
||||||
|
|
||||||
struct Dataspace_user : List<Dataspace_user>::Element
|
using namespace Genode;
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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_ */
|
#endif /* _NOUX__DATASPACE_REGISTRY_H_ */
|
||||||
|
@ -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_ */
|
|
@ -18,77 +18,81 @@
|
|||||||
#include <base/allocator.h>
|
#include <base/allocator.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux { class Destruct_queue; }
|
||||||
|
|
||||||
class Destruct_queue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct Element_base : Genode::List<Element_base>::Element
|
class Noux::Destruct_queue
|
||||||
{
|
{
|
||||||
virtual void destroy() = 0;
|
public:
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
struct Element_base : Genode::List<Element_base>::Element
|
||||||
* When a pointer to an object which inherits 'Element' among other
|
{
|
||||||
* base classes gets static-casted to a pointer to the 'Element'
|
virtual void destroy() = 0;
|
||||||
* 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:
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param alloc the allocator which was used to allocate
|
|
||||||
* the element
|
|
||||||
*/
|
|
||||||
Element(Genode::Allocator *alloc) : _alloc(alloc) { }
|
|
||||||
|
|
||||||
virtual ~Element() { };
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param alloc the allocator which was used to allocate
|
||||||
|
* the element
|
||||||
|
*/
|
||||||
|
Element(Genode::Allocator &alloc) : _alloc(alloc) { }
|
||||||
|
|
||||||
void destroy()
|
virtual ~Element() { };
|
||||||
{
|
|
||||||
Genode::destroy(_alloc, static_cast<T*>(this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
void destroy()
|
||||||
|
{
|
||||||
Genode::List<Element_base> _destruct_list;
|
Genode::destroy(_alloc, static_cast<T*>(this));
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
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_ */
|
#endif /* _NOUX__DESTRUCT_QUEUE_H_ */
|
||||||
|
@ -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_ */
|
|
@ -11,39 +11,49 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _NOUX__ENVIRONMENT_H_
|
||||||
|
#define _NOUX__ENVIRONMENT_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <os/attached_ram_dataspace.h>
|
#include <base/attached_ram_dataspace.h>
|
||||||
#include <base/printf.h>
|
|
||||||
|
|
||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <path.h>
|
#include <path.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Environment;
|
||||||
class Environment : private Attached_ram_dataspace
|
using namespace Genode;
|
||||||
{
|
|
||||||
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 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_ */
|
||||||
|
@ -22,159 +22,156 @@
|
|||||||
#include <parent_exit.h>
|
#include <parent_exit.h>
|
||||||
#include <parent_execve.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;
|
class Noux::Family_member : public List<Family_member>::Element,
|
||||||
Lock _lock;
|
public Parent_exit,
|
||||||
List<Family_member> _list;
|
public Parent_execve
|
||||||
bool _has_exited;
|
{
|
||||||
int _exit_status;
|
private:
|
||||||
|
|
||||||
protected:
|
int const _pid;
|
||||||
|
Lock _lock;
|
||||||
|
List<Family_member> _list;
|
||||||
|
bool _has_exited;
|
||||||
|
int _exit_status;
|
||||||
|
|
||||||
/**
|
protected:
|
||||||
* Lock used for implementing blocking syscalls,
|
|
||||||
* i.e., select, wait4, ...
|
|
||||||
*/
|
|
||||||
Lock _blocker;
|
|
||||||
|
|
||||||
public:
|
/**
|
||||||
|
* Lock used for implementing blocking syscalls,
|
||||||
|
* i.e., select, wait4, ...
|
||||||
|
*/
|
||||||
|
Lock _blocker;
|
||||||
|
|
||||||
Family_member(int pid)
|
public:
|
||||||
: _pid(pid), _has_exited(false), _exit_status(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
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; }
|
||||||
|
|
||||||
/**
|
int exit_status() const { return _exit_status; }
|
||||||
* Called by the parent at creation time of the process
|
|
||||||
*/
|
/**
|
||||||
void insert(Family_member *member)
|
* Called by the parent at creation time of the process
|
||||||
{
|
*/
|
||||||
Lock::Guard guard(_lock);
|
void insert(Family_member *member)
|
||||||
_list.insert(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool result = false;
|
||||||
* Called by the parent from the return path of the wait4 syscall
|
|
||||||
*/
|
for (Family_member *child = _list.first(); child; child = child->next())
|
||||||
void remove(Family_member *member)
|
if (child->deliver_kill(pid, sig))
|
||||||
{
|
result = true;
|
||||||
Lock::Guard guard(_lock);
|
|
||||||
_list.remove(member);
|
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;
|
/**
|
||||||
|
* Wait for the exit of any of our children
|
||||||
/**
|
*/
|
||||||
* Called by the parent (originates from Kill_broadcaster)
|
Family_member *wait4()
|
||||||
*/
|
{
|
||||||
bool deliver_kill(int pid, Noux::Sysio::Signal sig)
|
/* reset the blocker lock to the 'locked' state */
|
||||||
{
|
_blocker.unlock();
|
||||||
Lock::Guard guard(_lock);
|
_blocker.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;
|
|
||||||
|
|
||||||
|
Family_member *result = poll4();
|
||||||
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
_blocker.lock();
|
||||||
* Parent_exit interface
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Called by the child on the parent (via Parent_exit) */
|
/* either a child exited or a signal occurred */
|
||||||
void exit_child()
|
return poll4();
|
||||||
{
|
}
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _NOUX__FAMILY_MEMBER_H_ */
|
#endif /* _NOUX__FAMILY_MEMBER_H_ */
|
||||||
|
@ -17,105 +17,105 @@
|
|||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <io_channel.h>
|
#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 {
|
private:
|
||||||
bool allocated;
|
|
||||||
Shared_pointer<Io_channel> io_channel;
|
|
||||||
} _fds[MAX_FILE_DESCRIPTORS];
|
|
||||||
|
|
||||||
bool _valid_fd(int fd) const
|
struct {
|
||||||
{
|
bool allocated;
|
||||||
return (fd >= 0) && (fd < MAX_FILE_DESCRIPTORS);
|
Shared_pointer<Io_channel> io_channel;
|
||||||
}
|
} _fds[MAX_FILE_DESCRIPTORS];
|
||||||
|
|
||||||
bool _find_available_fd(int *fd) const
|
bool _valid_fd(int fd) const
|
||||||
{
|
{
|
||||||
/* allocate the first free file descriptor */
|
return (fd >= 0) && (fd < MAX_FILE_DESCRIPTORS);
|
||||||
for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++)
|
}
|
||||||
if (_fds[i].allocated == false) {
|
|
||||||
*fd = i;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _assign_fd(int fd, Shared_pointer<Io_channel> &io_channel)
|
bool _find_available_fd(int *fd) const
|
||||||
{
|
{
|
||||||
_fds[fd].io_channel = io_channel;
|
/* allocate the first free file descriptor */
|
||||||
_fds[fd].allocated = true;
|
for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++)
|
||||||
}
|
if (_fds[i].allocated == false) {
|
||||||
|
*fd = i;
|
||||||
void _reset_fd(int fd)
|
return true;
|
||||||
{
|
|
||||||
_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;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_valid_fd(fd)) {
|
void _assign_fd(int fd, Shared_pointer<Io_channel> &io_channel)
|
||||||
error("file descriptor ", fd, " is out of range");
|
{
|
||||||
return -2;
|
_fds[fd].io_channel = io_channel;
|
||||||
}
|
_fds[fd].allocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
_assign_fd(fd, io_channel);
|
void _reset_fd(int fd)
|
||||||
return 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");
|
||||||
if (!_valid_fd(fd))
|
return -2;
|
||||||
error("file descriptor ", fd, " is out of range");
|
|
||||||
else
|
|
||||||
_reset_fd(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fd_in_use(int fd) const
|
_assign_fd(fd, io_channel);
|
||||||
{
|
return fd;
|
||||||
return (_valid_fd(fd) && _fds[fd].io_channel);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Shared_pointer<Io_channel> io_channel_by_fd(int fd) const
|
virtual void remove_io_channel(int fd)
|
||||||
{
|
{
|
||||||
if (!fd_in_use(fd))
|
if (!_valid_fd(fd))
|
||||||
return Shared_pointer<Io_channel>();
|
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()
|
Shared_pointer<Io_channel> io_channel_by_fd(int fd) const
|
||||||
{
|
{
|
||||||
/* close all file descriptors */
|
if (!fd_in_use(fd))
|
||||||
for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++)
|
return Shared_pointer<Io_channel>();
|
||||||
_reset_fd(i);
|
|
||||||
}
|
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_ */
|
#endif /* _NOUX__FILE_DESCRIPTOR_REGISTRY_H_ */
|
||||||
|
@ -28,174 +28,176 @@
|
|||||||
#include <io_channel_listener.h>
|
#include <io_channel_listener.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
class Terminal_io_channel;
|
|
||||||
|
|
||||||
extern Genode::Lock &signal_lock();
|
extern Genode::Lock &signal_lock();
|
||||||
|
|
||||||
/**
|
class Io_channel_backend;
|
||||||
* Input/output channel backend that is used for calling
|
class Io_channel;
|
||||||
* different methos which does not belong to the original
|
|
||||||
* interface, e.g. network methods.
|
|
||||||
*/
|
|
||||||
class Io_channel_backend
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual ~Io_channel_backend() { }
|
class Terminal_io_channel;
|
||||||
|
|
||||||
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; }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_ */
|
#endif /* _NOUX__IO_CHANNEL_H_ */
|
||||||
|
@ -20,9 +20,7 @@
|
|||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <interrupt_handler.h>
|
#include <interrupt_handler.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux { typedef List_element<Interrupt_handler> Io_channel_listener; }
|
||||||
typedef List_element<Interrupt_handler> Io_channel_listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _NOUX__IO_CHANNEL_LISTENER__H_ */
|
#endif /* _NOUX__IO_CHANNEL_LISTENER__H_ */
|
||||||
|
|
||||||
|
@ -20,63 +20,62 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
struct Io_receptor;
|
||||||
struct Io_receptor : List<Io_receptor>::Element
|
struct Io_receptor_registry;
|
||||||
{
|
|
||||||
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 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_ */
|
#endif /* _NOUX__IO_RECEPTOR_REGISTRY_H_ */
|
||||||
|
@ -36,16 +36,19 @@ class Noux::Local_rom_factory : public Local_rom_service::Factory
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
Allocator &_alloc;
|
||||||
|
Env &_env;
|
||||||
Rpc_entrypoint &_ep;
|
Rpc_entrypoint &_ep;
|
||||||
Vfs::Dir_file_system &_root_dir;
|
Vfs::Dir_file_system &_root_dir;
|
||||||
Dataspace_registry &_registry;
|
Dataspace_registry &_registry;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Local_rom_factory(Rpc_entrypoint &ep, Vfs::Dir_file_system &root_dir,
|
Local_rom_factory(Allocator &alloc, Env &env, Rpc_entrypoint &ep,
|
||||||
|
Vfs::Dir_file_system &root_dir,
|
||||||
Dataspace_registry ®istry)
|
Dataspace_registry ®istry)
|
||||||
:
|
:
|
||||||
_ep(ep), _root_dir(root_dir), _registry(registry)
|
_alloc(alloc), _env(env), _ep(ep), _root_dir(root_dir), _registry(registry)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Rom_session_component &create(Args const &args, Affinity) override
|
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 =
|
Rom_session_component::Name const rom_name =
|
||||||
label_from_args(args.string()).last_element();
|
label_from_args(args.string()).last_element();
|
||||||
|
|
||||||
return *new (env()->heap())
|
return *new (_alloc)
|
||||||
Rom_session_component(_ep, _root_dir, _registry, rom_name);
|
Rom_session_component(_alloc, _env, _ep, _root_dir, _registry, rom_name);
|
||||||
}
|
}
|
||||||
catch (Rom_connection::Rom_connection_failed) { throw Denied(); }
|
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
|
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
@ -1,8 +1,9 @@
|
|||||||
TARGET = noux
|
TARGET = noux
|
||||||
LIBS = alarm vfs
|
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)
|
||||||
INC_DIR += $(PRG_DIR)/../
|
INC_DIR += $(PRG_DIR)/../
|
||||||
|
|
||||||
vpath main.cc $(PRG_DIR)/..
|
vpath main.cc $(PRG_DIR)/..
|
||||||
|
vpath syscall.cc $(PRG_DIR)/..
|
||||||
vpath dummy_net.cc $(PRG_DIR)
|
vpath dummy_net.cc $(PRG_DIR)
|
||||||
|
@ -72,6 +72,7 @@ void init_network()
|
|||||||
libc_select_notify = select_notify;
|
libc_select_notify = select_notify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Noux net syscall dispatcher **
|
** Noux net syscall dispatcher **
|
||||||
*********************************/
|
*********************************/
|
||||||
@ -117,16 +118,16 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
break;
|
break;
|
||||||
case SYSCALL_SOCKET:
|
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);
|
GET_SOCKET_IO_CHANNEL_BACKEND(socket_io_channel->backend(), backend);
|
||||||
|
|
||||||
if (!backend->socket(&_sysio)) {
|
if (!backend->socket(_sysio)) {
|
||||||
delete socket_io_channel;
|
delete socket_io_channel;
|
||||||
return false;
|
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);
|
_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);
|
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
||||||
|
|
||||||
return backend->getsockopt(&_sysio);
|
return backend->getsockopt(_sysio);
|
||||||
}
|
}
|
||||||
case SYSCALL_SETSOCKOPT:
|
case SYSCALL_SETSOCKOPT:
|
||||||
{
|
{
|
||||||
@ -146,7 +147,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
||||||
|
|
||||||
return backend->setsockopt(&_sysio);
|
return backend->setsockopt(_sysio);
|
||||||
}
|
}
|
||||||
case SYSCALL_ACCEPT:
|
case SYSCALL_ACCEPT:
|
||||||
{
|
{
|
||||||
@ -154,12 +155,12 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
||||||
|
|
||||||
int socket = backend->accept(&_sysio);
|
int socket = backend->accept(_sysio);
|
||||||
if (socket == -1)
|
if (socket == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Socket_io_channel *socket_io_channel = new Socket_io_channel(socket);
|
Socket_io_channel *socket_io_channel = new (_heap) Socket_io_channel(socket);
|
||||||
Shared_pointer<Io_channel> io_channel(socket_io_channel, Genode::env()->heap());
|
Shared_pointer<Io_channel> io_channel(socket_io_channel, _heap);
|
||||||
|
|
||||||
_sysio.accept_out.fd = add_io_channel(io_channel);
|
_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);
|
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:
|
case SYSCALL_LISTEN:
|
||||||
{
|
{
|
||||||
@ -179,7 +180,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_SEND:
|
||||||
{
|
{
|
||||||
@ -187,7 +188,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_SENDTO:
|
||||||
{
|
{
|
||||||
@ -195,7 +196,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_RECV:
|
||||||
{
|
{
|
||||||
@ -203,7 +204,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_RECVFROM:
|
||||||
{
|
{
|
||||||
@ -211,7 +212,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_GETPEERNAME:
|
||||||
{
|
{
|
||||||
@ -219,7 +220,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_SHUTDOWN:
|
||||||
{
|
{
|
||||||
@ -227,7 +228,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
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:
|
case SYSCALL_CONNECT:
|
||||||
{
|
{
|
||||||
@ -235,7 +236,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend);
|
||||||
|
|
||||||
return (backend->connect(&_sysio) == -1) ? false : true;
|
return (backend->connect(_sysio) == -1) ? false : true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,492 +32,470 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Noux {
|
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()
|
public:
|
||||||
:
|
|
||||||
_socket(-1)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
Socket_io_channel_backend(int s)
|
Socket_io_channel_backend()
|
||||||
:
|
:
|
||||||
_socket(s)
|
_socket(-1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~Socket_io_channel_backend()
|
Socket_io_channel_backend(int s)
|
||||||
{
|
:
|
||||||
if (_socket != -1) {
|
_socket(s)
|
||||||
::shutdown(_socket, SHUT_RDWR);
|
{ }
|
||||||
::close(_socket);
|
|
||||||
}
|
~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)
|
bool write(Sysio &sysio, ::size_t &count)
|
||||||
{
|
{
|
||||||
ssize_t result = ::write(_socket, sysio->write_in.chunk,
|
ssize_t result = ::write(_socket, sysio.write_in.chunk,
|
||||||
sysio->write_in.count);
|
sysio.write_in.count);
|
||||||
|
|
||||||
if (result > -1) {
|
if (result > -1) {
|
||||||
sysio->write_out.count = result;
|
sysio.write_out.count = result;
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dirent(Sysio *sysio) { return false; }
|
switch (errno) {
|
||||||
|
/* case EAGAIN: sysio.error.read = Sysio::READ_ERR_AGAIN; break; */
|
||||||
bool ioctl(Sysio *sysio)
|
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;
|
||||||
int request;
|
case EIO: sysio.error.read = Vfs::File_io_service::READ_ERR_IO; break;
|
||||||
|
default:
|
||||||
switch (sysio->ioctl_in.request) {
|
log(__func__, ": unhandled errno: ", (int)errno);
|
||||||
|
break;
|
||||||
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
|
return false;
|
||||||
{
|
}
|
||||||
fd_set readfds;
|
|
||||||
fd_set writefds;
|
|
||||||
fd_set exceptfds;
|
|
||||||
int ready;
|
|
||||||
|
|
||||||
/**
|
bool read(Sysio &sysio)
|
||||||
* The timeout will be overriden in libc's select() function
|
{
|
||||||
* but we still need a valid pointer because libc's select()
|
::size_t const max_count = Genode::min(sysio.read_in.count, sizeof(sysio.read_out.chunk));
|
||||||
* will block forever otherwise.
|
|
||||||
*/
|
|
||||||
struct timeval timeout = { 0, 0 };
|
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
ssize_t result = ::read(_socket, sysio.read_out.chunk, max_count);
|
||||||
FD_ZERO(&writefds);
|
|
||||||
FD_ZERO(&exceptfds);
|
|
||||||
|
|
||||||
FD_SET(_socket, &readfds);
|
if (result > -1) {
|
||||||
FD_SET(_socket, &writefds);
|
sysio.read_out.count = result;
|
||||||
FD_SET(_socket, &exceptfds);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ready = ::select(_socket + 1, &readfds, &writefds, &exceptfds, &timeout);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (ready > 0) {
|
return false;
|
||||||
if (rd) {
|
}
|
||||||
if (FD_ISSET(_socket, &readfds))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wr) {
|
bool fcntl(Sysio &sysio)
|
||||||
if (FD_ISSET(_socket, &writefds))
|
{
|
||||||
return true;
|
int cmd = -1;
|
||||||
}
|
switch (sysio.fcntl_in.cmd) {
|
||||||
|
|
||||||
if (ex) {
|
|
||||||
if (FD_ISSET(_socket, &exceptfds))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
|
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;
|
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 };
|
||||||
|
|
||||||
int accept(Sysio *sysio)
|
FD_ZERO(&readfds);
|
||||||
{
|
FD_ZERO(&writefds);
|
||||||
int result;
|
FD_ZERO(&exceptfds);
|
||||||
|
|
||||||
if (sysio->accept_in.addrlen == 0) {
|
FD_SET(_socket, &readfds);
|
||||||
result = ::accept(_socket, NULL, NULL);
|
FD_SET(_socket, &writefds);
|
||||||
}
|
FD_SET(_socket, &exceptfds);
|
||||||
else {
|
|
||||||
result = ::accept(_socket, (sockaddr *)&sysio->accept_in.addr,
|
ready = ::select(_socket + 1, &readfds, &writefds, &exceptfds, &timeout);
|
||||||
&sysio->accept_in.addrlen);
|
|
||||||
|
if (ready > 0) {
|
||||||
|
if (rd) {
|
||||||
|
if (FD_ISSET(_socket, &readfds))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == -1) {
|
if (wr) {
|
||||||
switch (errno) {
|
if (FD_ISSET(_socket, &writefds))
|
||||||
/* case EAGAIN: sysio->error.accept = Sysio::ACCEPT_ERR_AGAIN; break; */
|
return true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
if (ex) {
|
||||||
}
|
if (FD_ISSET(_socket, &exceptfds))
|
||||||
|
return true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
/**
|
||||||
{
|
* Socket methods
|
||||||
return _backend->write(sysio, count);
|
*/
|
||||||
|
|
||||||
|
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)
|
if (result == -1) {
|
||||||
{
|
switch (errno) {
|
||||||
return _backend->read(sysio);
|
/* 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 result;
|
||||||
{
|
}
|
||||||
return _backend->fcntl(sysio);
|
|
||||||
|
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 result;
|
||||||
{
|
}
|
||||||
return _backend->ioctl(sysio);
|
|
||||||
|
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 result;
|
||||||
{
|
}
|
||||||
return _backend->check_unblock(rd, wr, ex);
|
|
||||||
|
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_ */
|
#endif /* _NOUX__SOCKET_IO_CHANNEL_H_ */
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
TARGET = noux_net
|
TARGET = noux_net
|
||||||
LIBS += alarm libc libc_lwip_nic_dhcp vfs
|
LIBS += alarm libc libc_lwip_nic_dhcp vfs
|
||||||
|
SRC_CC = main.cc syscall.cc net.cc
|
||||||
SRC_CC = main.cc net.cc
|
|
||||||
|
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
INC_DIR += $(PRG_DIR)/../
|
INC_DIR += $(PRG_DIR)/../
|
||||||
|
|
||||||
vpath main.cc $(PRG_DIR)/..
|
vpath main.cc $(PRG_DIR)/..
|
||||||
vpath net.cc $(PRG_DIR)
|
vpath syscall.cc $(PRG_DIR)/..
|
||||||
|
vpath net.cc $(PRG_DIR)
|
||||||
|
@ -18,18 +18,17 @@
|
|||||||
#include <noux_session/sysio.h>
|
#include <noux_session/sysio.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
struct Family_member;
|
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_ */
|
#endif /* _NOUX__PARENT_EXECVE__H_ */
|
||||||
|
@ -42,13 +42,14 @@ class Noux::Pd_session_component : public Rpc_object<Pd_session>
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* 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)
|
Dataspace_registry &ds_registry)
|
||||||
:
|
:
|
||||||
_ep(ep), _pd(name.string()),
|
_ep(ep), _pd(env, name.string()),
|
||||||
_address_space(_ep, ds_registry, _pd, _pd.address_space()),
|
_address_space(alloc, _ep, ds_registry, _pd, _pd.address_space()),
|
||||||
_stack_area (_ep, ds_registry, _pd, _pd.stack_area()),
|
_stack_area (alloc, _ep, ds_registry, _pd, _pd.stack_area()),
|
||||||
_linker_area (_ep, ds_registry, _pd, _pd.linker_area())
|
_linker_area (alloc, _ep, ds_registry, _pd, _pd.linker_area())
|
||||||
{
|
{
|
||||||
_ep.manage(this);
|
_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(); }
|
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)
|
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,
|
void replay(Ram_session &dst_ram,
|
||||||
Pd_session_component &dst_pd,
|
Pd_session_component &dst_pd,
|
||||||
|
Region_map &local_rm,
|
||||||
|
Allocator &alloc,
|
||||||
Dataspace_registry &ds_registry,
|
Dataspace_registry &ds_registry,
|
||||||
Rpc_entrypoint &ep)
|
Rpc_entrypoint &ep)
|
||||||
{
|
{
|
||||||
/* replay region map into new protection domain */
|
/* replay region map into new protection domain */
|
||||||
_stack_area .replay(dst_ram, dst_pd.stack_area_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(), 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(), 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_address_space = dst_pd.address_space_region_map();
|
||||||
Region_map &dst_stack_area = dst_pd.stack_area_region_map();
|
Region_map &dst_stack_area = dst_pd.stack_area_region_map();
|
||||||
|
@ -18,350 +18,330 @@
|
|||||||
#include <io_channel.h>
|
#include <io_channel.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Pipe;
|
||||||
class Pipe : public Reference_counter
|
class Pipe_sink_io_channel;
|
||||||
{
|
class Pipe_source_io_channel;
|
||||||
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 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_ */
|
#endif /* _NOUX__PIPE_IO_CHANNEL_H_ */
|
||||||
|
@ -26,163 +26,164 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <ram_session/client.h>
|
#include <ram_session/client.h>
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <base/env.h>
|
|
||||||
|
|
||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <dataspace_registry.h>
|
#include <dataspace_registry.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
struct Ram_dataspace_info;
|
||||||
struct Ram_dataspace_info : Dataspace_info,
|
struct Ram_session_component;
|
||||||
List<Ram_dataspace_info>::Element
|
using namespace Genode;
|
||||||
{
|
|
||||||
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 ®istry)
|
|
||||||
: _ep(ep), _used_quota(0), _registry(registry) { _ep.manage(this); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Ram_session_component()
|
|
||||||
{
|
|
||||||
_ep.dissolve(this);
|
|
||||||
Ram_dataspace_info *info = 0;
|
|
||||||
while ((info = _list.first()))
|
|
||||||
free(static_cap_cast<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 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 ®istry)
|
||||||
|
:
|
||||||
|
_ram(ram), _alloc(alloc), _ep(ep), _used_quota(0),
|
||||||
|
_registry(registry)
|
||||||
|
{
|
||||||
|
_ep.manage(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
~Ram_session_component()
|
||||||
|
{
|
||||||
|
_ep.dissolve(this);
|
||||||
|
Ram_dataspace_info *info = 0;
|
||||||
|
while ((info = _list.first()))
|
||||||
|
free(static_cap_cast<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_ */
|
#endif /* _NOUX__RAM_SESSION_COMPONENT_H_ */
|
||||||
|
@ -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_ */
|
|
@ -17,28 +17,29 @@
|
|||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
class Index_out_of_range { };
|
class Index_out_of_range { };
|
||||||
|
template <typename> struct Range_checked_index;
|
||||||
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 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_ */
|
#endif /* _NOUX__RANGE_CHECKED_INDEX_H_ */
|
||||||
|
@ -36,6 +36,8 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
|
|||||||
static constexpr bool verbose_attach = false;
|
static constexpr bool verbose_attach = false;
|
||||||
static constexpr bool verbose_replay = false;
|
static constexpr bool verbose_replay = false;
|
||||||
|
|
||||||
|
Allocator &_alloc;
|
||||||
|
|
||||||
Rpc_entrypoint &_ep;
|
Rpc_entrypoint &_ep;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,13 +106,13 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
|
|||||||
* quota upgrades
|
* quota upgrades
|
||||||
* \param rm region map at core
|
* \param rm region map at core
|
||||||
*/
|
*/
|
||||||
Region_map_component(Rpc_entrypoint &ep,
|
Region_map_component(Allocator &alloc, Rpc_entrypoint &ep,
|
||||||
Dataspace_registry &ds_registry,
|
Dataspace_registry &ds_registry,
|
||||||
Pd_connection &pd,
|
Pd_connection &pd,
|
||||||
Capability<Region_map> rm)
|
Capability<Region_map> rm)
|
||||||
:
|
:
|
||||||
Dataspace_info(Region_map_client(rm).dataspace()),
|
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);
|
_ep.manage(this);
|
||||||
_ds_registry.insert(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,
|
void replay(Ram_session &dst_ram,
|
||||||
Region_map &dst_rm,
|
Region_map &dst_rm,
|
||||||
|
Region_map &local_rm,
|
||||||
|
Allocator &alloc,
|
||||||
Dataspace_registry &ds_registry,
|
Dataspace_registry &ds_registry,
|
||||||
Rpc_entrypoint &ep)
|
Rpc_entrypoint &ep)
|
||||||
{
|
{
|
||||||
@ -170,7 +174,7 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
|
|||||||
Dataspace_capability ds;
|
Dataspace_capability ds;
|
||||||
if (info) {
|
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
|
* 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);
|
Region(*this, ds, size, offset, local_addr);
|
||||||
|
|
||||||
/* register region as user of RAM dataspaces */
|
/* 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) {
|
_ds_registry.apply(region->ds, [&] (Dataspace_info *info) {
|
||||||
if (info) info->unregister_user(*region); });
|
if (info) info->unregister_user(*region); });
|
||||||
|
|
||||||
destroy(env()->heap(), region);
|
destroy(_alloc, region);
|
||||||
|
|
||||||
_rm.detach(local_addr);
|
_rm.detach(local_addr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fault_handler(Signal_context_capability handler) override
|
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 &,
|
Dataspace_capability fork(Ram_session &,
|
||||||
|
Region_map &,
|
||||||
|
Allocator &,
|
||||||
Dataspace_registry &,
|
Dataspace_registry &,
|
||||||
Rpc_entrypoint &) override
|
Rpc_entrypoint &) override
|
||||||
{
|
{
|
||||||
@ -358,7 +363,7 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
|
|||||||
return _ds_registry.apply(region->ds, lambda);
|
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;
|
Dataspace_capability ds_cap;
|
||||||
addr_t local_addr;
|
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");
|
error("attempt to write to unknown dataspace type");
|
||||||
for (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
info->poke(dst_addr - local_addr, src, len);
|
info->poke(rm, dst_addr - local_addr, src, len);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -32,14 +32,16 @@ struct Noux::Rom_dataspace_info : Dataspace_info
|
|||||||
~Rom_dataspace_info() { }
|
~Rom_dataspace_info() { }
|
||||||
|
|
||||||
Dataspace_capability fork(Ram_session &,
|
Dataspace_capability fork(Ram_session &,
|
||||||
|
Region_map &,
|
||||||
|
Allocator &alloc,
|
||||||
Dataspace_registry &ds_registry,
|
Dataspace_registry &ds_registry,
|
||||||
Rpc_entrypoint &) override
|
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();
|
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");
|
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;
|
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] == '/') {
|
if (name.string()[0] == '/') {
|
||||||
_rom_from_vfs.construct(_root_dir, name);
|
_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())
|
if (name == forked_magic_binary_name())
|
||||||
return Dataspace_capability();
|
return Dataspace_capability();
|
||||||
|
|
||||||
_rom_from_parent.construct(name.string());
|
_rom_from_parent.construct(env, name.string());
|
||||||
Dataspace_capability ds = _rom_from_parent->dataspace();
|
Dataspace_capability ds = _rom_from_parent->dataspace();
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
@ -120,14 +122,15 @@ class Noux::Rom_session_component : public Rpc_object<Rom_session>
|
|||||||
|
|
||||||
public:
|
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)
|
Dataspace_registry &ds_registry, Name const &name)
|
||||||
:
|
:
|
||||||
_ep(ep), _root_dir(root_dir), _ds_registry(ds_registry),
|
_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);
|
_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()
|
~Rom_session_component()
|
||||||
|
@ -23,135 +23,137 @@
|
|||||||
#include <noux_session/sysio.h>
|
#include <noux_session/sysio.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class Reference_counter;
|
||||||
class Shared_pointer_base;
|
class Shared_pointer_base;
|
||||||
|
template <typename T> class Shared_pointer;
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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_ */
|
#endif /* _NOUX__SHARED_POINTER_H_ */
|
||||||
|
@ -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_ */
|
|
798
repos/ports/src/noux/syscall.cc
Normal file
798
repos/ports/src/noux/syscall.cc
Normal 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(¬ifiers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register ourself at the Io_receptor_registry
|
||||||
|
*
|
||||||
|
* Each entry in the registry will be unblocked if an external
|
||||||
|
* event has happend, e.g. network I/O.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Io_receptor receptor(&_blocker);
|
||||||
|
io_receptor_registry()->register_receptor(&receptor);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block for one action of the watched file descriptors
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check I/O channels of specified file descriptors for
|
||||||
|
* unblock condition. Return if one I/O channel satisfies
|
||||||
|
* the condition.
|
||||||
|
*/
|
||||||
|
size_t unblock_rd = 0;
|
||||||
|
size_t unblock_wr = 0;
|
||||||
|
size_t unblock_ex = 0;
|
||||||
|
|
||||||
|
/* process read fds */
|
||||||
|
for (Genode::size_t i = 0; i < in_fds_total; i++) {
|
||||||
|
|
||||||
|
int fd = in_fds.array[i];
|
||||||
|
if (!fd_in_use(fd)) continue;
|
||||||
|
|
||||||
|
Shared_pointer<Io_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(¬ifiers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unregister receptor
|
||||||
|
*/
|
||||||
|
io_receptor_registry()->unregister_receptor(&receptor);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SYSCALL_FORK:
|
||||||
|
{
|
||||||
|
Genode::addr_t ip = _sysio.fork_in.ip;
|
||||||
|
Genode::addr_t sp = _sysio.fork_in.sp;
|
||||||
|
Genode::addr_t parent_cap_addr = _sysio.fork_in.parent_cap_addr;
|
||||||
|
|
||||||
|
int const new_pid = _pid_allocator.alloc();
|
||||||
|
Child * child = nullptr;
|
||||||
|
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
* XXX To ease debugging, it would be useful to generate a
|
||||||
|
* unique name that includes the PID instead of just
|
||||||
|
* reusing the name of the parent.
|
||||||
|
*/
|
||||||
|
child = new (_heap) Child(_child_policy.name(),
|
||||||
|
_verbose,
|
||||||
|
_user_info,
|
||||||
|
this,
|
||||||
|
_kill_broadcaster,
|
||||||
|
_timeout_scheduler,
|
||||||
|
*this,
|
||||||
|
_pid_allocator,
|
||||||
|
new_pid,
|
||||||
|
_env,
|
||||||
|
_root_dir,
|
||||||
|
_args,
|
||||||
|
_sysio_env.env(),
|
||||||
|
_heap,
|
||||||
|
_ref_ram, _ref_ram_cap,
|
||||||
|
_parent_services,
|
||||||
|
true,
|
||||||
|
_destruct_queue);
|
||||||
|
} catch (Child::Insufficient_memory) {
|
||||||
|
_sysio.error.fork = Sysio::FORK_NOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Family_member::insert(child);
|
||||||
|
|
||||||
|
_assign_io_channels_to(child);
|
||||||
|
|
||||||
|
/* copy our address space into the new child */
|
||||||
|
try {
|
||||||
|
_pd.replay(child->ram(), child->pd(), _env.rm(), _heap,
|
||||||
|
child->ds_registry(), _ep);
|
||||||
|
|
||||||
|
/* start executing the main thread of the new process */
|
||||||
|
child->start_forked_main_thread(ip, sp, parent_cap_addr);
|
||||||
|
|
||||||
|
/* activate child entrypoint, thereby starting the new process */
|
||||||
|
child->start();
|
||||||
|
|
||||||
|
_sysio.fork_out.pid = new_pid;
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
catch (Region_map::Region_conflict) {
|
||||||
|
error("region conflict while replaying the address space"); }
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SYSCALL_GETPID:
|
||||||
|
{
|
||||||
|
_sysio.getpid_out.pid = pid();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SYSCALL_WAIT4:
|
||||||
|
{
|
||||||
|
Family_member *exited = _sysio.wait4_in.nohang ? poll4() : wait4();
|
||||||
|
|
||||||
|
if (exited) {
|
||||||
|
_sysio.wait4_out.pid = exited->pid();
|
||||||
|
_sysio.wait4_out.status = exited->exit_status();
|
||||||
|
Family_member::remove(exited);
|
||||||
|
|
||||||
|
static_cast<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;
|
||||||
|
}
|
@ -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_ */
|
|
@ -24,210 +24,201 @@
|
|||||||
#include <io_channel.h>
|
#include <io_channel.h>
|
||||||
#include <noux_session/sysio.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;
|
* Enable wake up STDIN channel on the presence of new input
|
||||||
bool eof;
|
*
|
||||||
|
* By registering our I/O channel as signal handler, the Noux
|
||||||
enum Type { STDIN, STDOUT, STDERR } type;
|
* main loop will be unblocked on the arrival of new input.
|
||||||
|
* It will check if the received signal belongs to an I/O channel
|
||||||
Ring_buffer<char, Sysio::CHUNK_SIZE + 1> read_buffer;
|
* and invokes the 'handle_signal' function of the I/O channel.
|
||||||
|
*
|
||||||
Terminal_io_channel(Terminal::Session &terminal, Type type,
|
* This gives us the opportunity to handle the unblocking of
|
||||||
Signal_receiver &sig_rec)
|
* blocking system calls such as 'select'.
|
||||||
: terminal(terminal), sig_rec(sig_rec), eof(false), type(type)
|
*/
|
||||||
{
|
if (type == STDIN) {
|
||||||
/*
|
terminal.read_avail_sigh(_read_avail_handler);
|
||||||
* 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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~Terminal_io_channel()
|
bool write(Sysio &sysio, size_t &offset) override
|
||||||
{
|
{
|
||||||
try { sig_rec.dissolve(this); }
|
size_t const count = min(sysio.write_in.count,
|
||||||
catch (Genode::Signal_receiver::Context_not_associated) { }
|
sizeof(sysio.write_in.chunk));
|
||||||
}
|
|
||||||
|
|
||||||
bool write(Sysio *sysio, size_t &offset) override
|
_terminal.write(sysio.write_in.chunk, count);
|
||||||
{
|
|
||||||
size_t const count = min(sysio->write_in.count,
|
|
||||||
sizeof(sysio->write_in.chunk));
|
|
||||||
|
|
||||||
terminal.write(sysio->write_in.chunk, count);
|
sysio.write_out.count = count;
|
||||||
|
offset = count;
|
||||||
|
|
||||||
sysio->write_out.count = count;
|
return true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool read(Sysio &sysio) override
|
||||||
|
{
|
||||||
|
if (type != STDIN) {
|
||||||
|
error("attempt to read from terminal output channel");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fstat(Sysio *sysio) override
|
/* deliver EOF observed by the previous 'read' call */
|
||||||
{
|
if (eof) {
|
||||||
/*
|
sysio.read_out.count = 0;
|
||||||
* Supply stat values such that libc is happy. I.e., the libc
|
eof = false;
|
||||||
* is checking for the file descriptor 1 being a character
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_unblock(bool rd, bool wr, bool ex) const override
|
size_t const max_count =
|
||||||
{
|
min(sysio.read_in.count,
|
||||||
/* never block for writing */
|
sizeof(sysio.read_out.chunk));
|
||||||
if (wr) return true;
|
|
||||||
|
|
||||||
/*
|
for (sysio.read_out.count = 0;
|
||||||
* Unblock I/O channel if the terminal has new user input. Channels
|
(sysio.read_out.count < max_count) && !read_buffer.empty();
|
||||||
* otther than STDIN will never unblock.
|
sysio.read_out.count++) {
|
||||||
*/
|
|
||||||
return (rd && (type == STDIN) && !read_buffer.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ioctl(Sysio *sysio) override
|
char c = read_buffer.get();
|
||||||
{
|
|
||||||
switch (sysio->ioctl_in.request) {
|
|
||||||
|
|
||||||
case Vfs::File_io_service::IOCTL_OP_TIOCGWINSZ:
|
enum { EOF = 4 };
|
||||||
{
|
|
||||||
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:
|
if (c == EOF) {
|
||||||
{
|
|
||||||
warning(__func__, ": OP_TIOCSETAF not implemented");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Vfs::File_io_service::IOCTL_OP_TIOCSETAW:
|
/*
|
||||||
{
|
* If EOF was the only character of the batch, the count
|
||||||
warning(__func__, ": OP_TIOCSETAW not implemented");
|
* has reached zero. In this case the read result indicates
|
||||||
return false;
|
* 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:
|
return true;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_ */
|
#endif /* _NOUX__TERMINAL_IO_CHANNEL_H_ */
|
||||||
|
102
repos/ports/src/noux/timeout_scheduler.h
Normal file
102
repos/ports/src/noux/timeout_scheduler.h
Normal 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_ */
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* \brief User information
|
* \brief User information
|
||||||
* \author Josef Soentgen
|
* \author Josef Soentgen
|
||||||
|
* \author Norman Feske
|
||||||
* \date 2012-07-23
|
* \date 2012-07-23
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -22,49 +23,54 @@
|
|||||||
#include <noux_session/sysio.h>
|
#include <noux_session/sysio.h>
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
class User_info;
|
||||||
using namespace Genode;
|
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_ */
|
#endif /* _NOUX__USER_INFO_H_ */
|
||||||
|
48
repos/ports/src/noux/verbose.h
Normal file
48
repos/ports/src/noux/verbose.h
Normal 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_ */
|
@ -18,212 +18,204 @@
|
|||||||
#include <io_channel.h>
|
#include <io_channel.h>
|
||||||
#include <vfs/dir_file_system.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;
|
Vfs::Vfs_handle *_fh;
|
||||||
Absolute_path _leaf_path;
|
|
||||||
|
|
||||||
Signal_receiver &_sig_rec;
|
Absolute_path _path;
|
||||||
|
Absolute_path _leaf_path;
|
||||||
|
|
||||||
Vfs_io_channel(char const *path, char const *leaf_path,
|
Vfs_io_channel(char const *path, char const *leaf_path,
|
||||||
Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle,
|
Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle,
|
||||||
Signal_receiver &sig_rec)
|
Entrypoint &ep)
|
||||||
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path),
|
:
|
||||||
_sig_rec(sig_rec)
|
_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, _sig_rec.manage(this));
|
{
|
||||||
}
|
_fh->fs().register_read_ready_sigh(_fh, _read_avail_handler);
|
||||||
|
}
|
||||||
|
|
||||||
~Vfs_io_channel()
|
~Vfs_io_channel()
|
||||||
{
|
{
|
||||||
_sig_rec.dissolve(this);
|
_fh->ds().close(_fh);
|
||||||
_fh->ds().close(_fh);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool write(Sysio *sysio, size_t &offset) override
|
bool write(Sysio &sysio, size_t &offset) override
|
||||||
{
|
{
|
||||||
Vfs::file_size out_count = 0;
|
Vfs::file_size out_count = 0;
|
||||||
|
|
||||||
sysio->error.write = _fh->fs().write(_fh, sysio->write_in.chunk,
|
sysio.error.write = _fh->fs().write(_fh, sysio.write_in.chunk,
|
||||||
sysio->write_in.count, out_count);
|
sysio.write_in.count, out_count);
|
||||||
if (sysio->error.write != Vfs::File_io_service::WRITE_OK)
|
if (sysio.error.write != Vfs::File_io_service::WRITE_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_fh->advance_seek(out_count);
|
_fh->advance_seek(out_count);
|
||||||
|
|
||||||
sysio->write_out.count = out_count;
|
sysio.write_out.count = out_count;
|
||||||
offset = out_count;
|
offset = out_count;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read(Sysio *sysio) override
|
bool read(Sysio &sysio) override
|
||||||
{
|
{
|
||||||
size_t count = min(sysio->read_in.count, sizeof(sysio->read_out.chunk));
|
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)
|
if (sysio.error.read != Vfs::File_io_service::READ_OK)
|
||||||
return false;
|
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;
|
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool fstat(Sysio &sysio) override
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* The 'dirent' function for the root directory only (the
|
* 'sysio.stat_in' is not used in '_fh->ds().stat()',
|
||||||
* 'Dir_file_system::open()' function handles all requests referring
|
* so no 'sysio' member translation is needed here
|
||||||
* to directories). Hence, '_path' is the absolute path of the
|
|
||||||
* directory to inspect.
|
|
||||||
*/
|
*/
|
||||||
bool dirent(Sysio *sysio) override
|
Vfs::Directory_service::Stat stat;
|
||||||
{
|
sysio.error.stat = _fh->ds().stat(_leaf_path.base(), stat);
|
||||||
/*
|
sysio.fstat_out.st = stat;
|
||||||
* 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;
|
return (sysio.error.stat == Vfs::Directory_service::STAT_OK);
|
||||||
_fh->advance_seek(sizeof(Sysio::Dirent));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
}
|
||||||
* 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;
|
bool ftruncate(Sysio &sysio) override
|
||||||
if (!_fh->ds().dirent(_path.base(), index - 2, dirent))
|
{
|
||||||
return false;
|
|
||||||
sysio->dirent_out.entry = dirent;
|
|
||||||
|
|
||||||
|
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));
|
_fh->advance_seek(sizeof(Sysio::Dirent));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Return size of file that the I/O channel refers to
|
* Delegate remaining dir-entry request to the actual file system.
|
||||||
*
|
* Align index range to zero when calling the directory service.
|
||||||
* 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;
|
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
|
bool check_unblock(bool rd, bool wr, bool ex) const override
|
||||||
{
|
{
|
||||||
Vfs::File_system::Ioctl_arg arg = (Vfs::File_system::Ioctl_arg)sysio->ioctl_in.argp;
|
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);
|
return true;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _NOUX__VFS_IO_CHANNEL_H_ */
|
#endif /* _NOUX__VFS_IO_CHANNEL_H_ */
|
||||||
|
@ -18,21 +18,16 @@
|
|||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
#include <base/lock.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)
|
struct Noux::Wake_up_notifier : List<Wake_up_notifier>::Element
|
||||||
: lock(lock) { }
|
{
|
||||||
|
Lock *lock;
|
||||||
|
|
||||||
void wake_up()
|
Wake_up_notifier(Lock *lock = nullptr) : lock(lock) { }
|
||||||
{
|
|
||||||
if (lock)
|
void wake_up() { if (lock) lock->unlock(); }
|
||||||
lock->unlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _NOUX__WAKE_UP_NOTIFIER__H_ */
|
#endif /* _NOUX__WAKE_UP_NOTIFIER__H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user