mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
parent
48739422ac
commit
afeb54ebed
@ -49,6 +49,8 @@ namespace Noux {
|
||||
SYSCALL_FORK,
|
||||
SYSCALL_GETPID,
|
||||
SYSCALL_WAIT4,
|
||||
SYSCALL_PIPE,
|
||||
SYSCALL_DUP2,
|
||||
SYSCALL_INVALID = -1
|
||||
};
|
||||
|
||||
@ -72,6 +74,8 @@ namespace Noux {
|
||||
NOUX_DECL_SYSCALL_NAME(FORK)
|
||||
NOUX_DECL_SYSCALL_NAME(GETPID)
|
||||
NOUX_DECL_SYSCALL_NAME(WAIT4)
|
||||
NOUX_DECL_SYSCALL_NAME(PIPE)
|
||||
NOUX_DECL_SYSCALL_NAME(DUP2)
|
||||
case SYSCALL_INVALID: return 0;
|
||||
}
|
||||
return 0;
|
||||
|
@ -256,6 +256,9 @@ namespace Noux {
|
||||
|
||||
SYSIO_DECL(wait4, { int pid; bool nohang; },
|
||||
{ int pid; int status; });
|
||||
SYSIO_DECL(pipe, { }, { int fd[2]; });
|
||||
|
||||
SYSIO_DECL(dup2, { int fd; int to_fd; }, { });
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -498,10 +498,12 @@ namespace {
|
||||
bool supports_chdir(const char *) { return true; }
|
||||
bool supports_open(const char *, int) { return true; }
|
||||
bool supports_stat(const char *) { return true; }
|
||||
bool supports_pipe() { return true; }
|
||||
|
||||
Libc::File_descriptor *open(const char *, int);
|
||||
ssize_t write(Libc::File_descriptor *, const void *, ::size_t);
|
||||
int close(Libc::File_descriptor *);
|
||||
int dup2(Libc::File_descriptor *, Libc::File_descriptor *);
|
||||
int fstat(Libc::File_descriptor *, struct stat *);
|
||||
int fstatfs(Libc::File_descriptor *, struct statfs *);
|
||||
int fcntl(Libc::File_descriptor *, int, long);
|
||||
@ -511,6 +513,7 @@ namespace {
|
||||
ssize_t read(Libc::File_descriptor *, void *, ::size_t);
|
||||
int stat(const char *, struct stat *);
|
||||
int ioctl(Libc::File_descriptor *, int request, char *argp);
|
||||
int pipe(Libc::File_descriptor *pipefd[2]);
|
||||
};
|
||||
|
||||
|
||||
@ -539,7 +542,7 @@ namespace {
|
||||
}
|
||||
|
||||
Libc::Plugin_context *context = noux_context(sysio()->open_out.fd);
|
||||
return Libc::file_descriptor_allocator()->alloc(this, context);
|
||||
return Libc::file_descriptor_allocator()->alloc(this, context, sysio()->open_out.fd);
|
||||
}
|
||||
|
||||
|
||||
@ -600,9 +603,6 @@ namespace {
|
||||
|
||||
Genode::memcpy(buf, sysio()->read_out.chunk, sysio()->read_out.count);
|
||||
|
||||
// for (int i = 0; i < sysio()->read_out.count; i++)
|
||||
// Genode::printf("read %d\n", ((char *)buf)[i]);
|
||||
|
||||
sum_read_count += sysio()->read_out.count;
|
||||
|
||||
if (sysio()->read_out.count < sysio()->read_in.count)
|
||||
@ -626,6 +626,7 @@ namespace {
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
}
|
||||
Libc::file_descriptor_allocator()->free(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -696,6 +697,44 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
int Plugin::pipe(Libc::File_descriptor *pipefd[2])
|
||||
{
|
||||
/* perform syscall */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_PIPE)) {
|
||||
PERR("pipe error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Libc::Plugin_context *context = noux_context(sysio()->pipe_out.fd[i]);
|
||||
pipefd[i] = Libc::file_descriptor_allocator()->alloc(this, context, sysio()->pipe_out.fd[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Plugin::dup2(Libc::File_descriptor *fd, Libc::File_descriptor *new_fd)
|
||||
{
|
||||
/*
|
||||
* We use a one-to-one mapping of libc fds and Noux fds.
|
||||
*/
|
||||
new_fd->context = noux_context(new_fd->libc_fd);
|
||||
|
||||
sysio()->dup2_in.fd = noux_fd(fd->context);
|
||||
sysio()->dup2_in.to_fd = noux_fd(new_fd->context);
|
||||
|
||||
/* perform syscall */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_DUP2)) {
|
||||
PERR("dup2 error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Plugin::fstat(Libc::File_descriptor *fd, struct stat *buf)
|
||||
{
|
||||
sysio()->fstat_in.fd = noux_fd(fd->context);
|
||||
|
@ -90,6 +90,14 @@ namespace Noux {
|
||||
|
||||
/* trigger exit of main event loop */
|
||||
init_process_exited();
|
||||
} else {
|
||||
/* destroy 'Noux::Child' */
|
||||
destroy(Genode::env()->heap(), _child);
|
||||
|
||||
PINF("destroy %p", _child);
|
||||
PINF("quota: avail=%zd, used=%zd",
|
||||
Genode::env()->ram_session()->avail(),
|
||||
Genode::env()->ram_session()->used());
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -110,7 +118,6 @@ namespace Noux {
|
||||
|
||||
void dispatch()
|
||||
{
|
||||
PINF("execve cleanup dispatcher called");
|
||||
destroy(env()->heap(), _child);
|
||||
}
|
||||
};
|
||||
@ -240,6 +247,14 @@ namespace Noux {
|
||||
child->add_io_channel(io_channel_by_fd(fd), fd);
|
||||
}
|
||||
|
||||
void _block_for_io_channel(Shared_pointer<Io_channel> &io)
|
||||
{
|
||||
Wake_up_notifier notifier(&_blocker);
|
||||
io->register_wake_up_notifier(¬ifier);
|
||||
_blocker.down();
|
||||
io->unregister_wake_up_notifier(¬ifier);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -316,6 +331,11 @@ namespace Noux {
|
||||
_resources.cpu.start_main_thread(ip, sp);
|
||||
}
|
||||
|
||||
void submit_exit_signal()
|
||||
{
|
||||
Signal_transmitter(_exit_context_cap).submit();
|
||||
}
|
||||
|
||||
Ram_session_capability ram() const { return _resources.ram.cap(); }
|
||||
Rm_session_capability rm() const { return _resources.rm.cap(); }
|
||||
Dataspace_registry &ds_registry() { return _resources.ds_registry; }
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
namespace Noux {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* Input/output channel interface
|
||||
*/
|
||||
@ -39,18 +41,20 @@ namespace Noux {
|
||||
* List of notifiers (i.e., processes) used by threads that block
|
||||
* for an I/O-channel event
|
||||
*/
|
||||
Genode::List<Wake_up_notifier> _notifiers;
|
||||
Genode::Lock _notifiers_lock;
|
||||
List<Wake_up_notifier> _notifiers;
|
||||
Lock _notifiers_lock;
|
||||
|
||||
public:
|
||||
|
||||
virtual bool write(Sysio *sysio) { return false; }
|
||||
virtual bool read(Sysio *sysio) { return false; }
|
||||
virtual bool fstat(Sysio *sysio) { return false; }
|
||||
virtual bool fcntl(Sysio *sysio) { return false; }
|
||||
virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
|
||||
virtual bool dirent(Sysio *sysio) { return false; }
|
||||
virtual bool ioctl(Sysio *sysio) { return false; }
|
||||
virtual ~Io_channel() { }
|
||||
|
||||
virtual bool write(Sysio *sysio, size_t &count) { return false; }
|
||||
virtual bool read(Sysio *sysio) { return false; }
|
||||
virtual bool fstat(Sysio *sysio) { return false; }
|
||||
virtual bool fcntl(Sysio *sysio) { return false; }
|
||||
virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
|
||||
virtual bool dirent(Sysio *sysio) { return false; }
|
||||
virtual bool ioctl(Sysio *sysio) { return false; }
|
||||
|
||||
/**
|
||||
* Return true if an unblocking condition of the channel is satisfied
|
||||
@ -62,8 +66,6 @@ namespace Noux {
|
||||
virtual bool check_unblock(bool rd, bool wr, bool ex) const {
|
||||
return false; }
|
||||
|
||||
virtual ~Io_channel() { };
|
||||
|
||||
/**
|
||||
* Register blocker for getting waked up on an I/O channel event
|
||||
*
|
||||
@ -72,7 +74,7 @@ namespace Noux {
|
||||
*/
|
||||
void register_wake_up_notifier(Wake_up_notifier *notifier)
|
||||
{
|
||||
Genode::Lock::Guard guard(_notifiers_lock);
|
||||
Lock::Guard guard(_notifiers_lock);
|
||||
|
||||
_notifiers.insert(notifier);
|
||||
}
|
||||
@ -86,13 +88,13 @@ namespace Noux {
|
||||
*/
|
||||
void unregister_wake_up_notifier(Wake_up_notifier *notifier)
|
||||
{
|
||||
Genode::Lock::Guard guard(_notifiers_lock);
|
||||
Lock::Guard guard(_notifiers_lock);
|
||||
|
||||
_notifiers.remove(notifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell all registered notifiers about an occurred I/O channel
|
||||
* 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
|
||||
@ -100,7 +102,7 @@ namespace Noux {
|
||||
*/
|
||||
void invoke_all_notifiers()
|
||||
{
|
||||
Genode::Lock::Guard guard(_notifiers_lock);
|
||||
Lock::Guard guard(_notifiers_lock);
|
||||
|
||||
for (Wake_up_notifier *n = _notifiers.first(); n; n = n->next())
|
||||
n->wake_up();
|
||||
|
@ -29,9 +29,9 @@
|
||||
* ;- run 'cat' (read syscall)
|
||||
* ;- execve
|
||||
* ;- fork
|
||||
* - pipe
|
||||
* ;- pipe
|
||||
* ;- read init binary from vfs
|
||||
* - import env into child (execve and fork)
|
||||
* ;- import env into child (execve and fork)
|
||||
* ;- shell
|
||||
* - debug 'find'
|
||||
* - stacked file system infrastructure
|
||||
@ -48,6 +48,7 @@
|
||||
#include <vfs_io_channel.h>
|
||||
#include <terminal_io_channel.h>
|
||||
#include <dummy_input_io_channel.h>
|
||||
#include <pipe_io_channel.h>
|
||||
#include <root_file_system.h>
|
||||
#include <tar_file_system.h>
|
||||
|
||||
@ -86,14 +87,36 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
sizeof(_sysio->getcwd_out.path));
|
||||
return true;
|
||||
|
||||
|
||||
case SYSCALL_WRITE:
|
||||
{
|
||||
size_t const count_in = _sysio->write_in.count;
|
||||
|
||||
return _lookup_channel(_sysio->write_in.fd)->write(_sysio);
|
||||
for (size_t count = 0; count != count_in; ) {
|
||||
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->write_in.fd);
|
||||
|
||||
if (!io->check_unblock(false, true, false))
|
||||
_block_for_io_channel(io);
|
||||
|
||||
/*
|
||||
* 'io->write' is expected to update 'write_out.count'
|
||||
*/
|
||||
if (io->write(_sysio, count) == false)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSCALL_READ:
|
||||
{
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->read_in.fd);
|
||||
|
||||
return _lookup_channel(_sysio->read_in.fd)->read(_sysio);
|
||||
while (!io->check_unblock(true, false, false))
|
||||
_block_for_io_channel(io);
|
||||
|
||||
io->read(_sysio);
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSCALL_STAT:
|
||||
case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */
|
||||
@ -113,7 +136,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
{
|
||||
Absolute_path absolute_path(_sysio->open_in.path, _env.pwd());
|
||||
|
||||
PWRN("open pwd=%s path=%s", _env.pwd(), _sysio->open_in.path);
|
||||
PINF("open pwd=%s path=%s", _env.pwd(), _sysio->open_in.path);
|
||||
|
||||
/* remember mode only for debug output */
|
||||
int const mode = _sysio->open_in.mode;
|
||||
@ -123,7 +146,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
return false;
|
||||
|
||||
Shared_pointer<Io_channel> channel(new Vfs_io_channel(absolute_path.base(), _vfs, vfs_handle),
|
||||
Genode::env()->heap());
|
||||
Genode::env()->heap());
|
||||
|
||||
_sysio->open_out.fd = add_io_channel(channel);
|
||||
|
||||
@ -134,8 +157,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
case SYSCALL_CLOSE:
|
||||
{
|
||||
int const fd = _sysio->close_in.fd;
|
||||
PINF("close fd %d", fd);
|
||||
remove_io_channel(_sysio->close_in.fd);
|
||||
return true;
|
||||
}
|
||||
@ -208,7 +229,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_assign_io_channels_to(child);
|
||||
|
||||
/* signal main thread to remove ourself */
|
||||
PINF("submit signal to _execve_cleanup_context_cap");
|
||||
Genode::Signal_transmitter(_execve_cleanup_context_cap).submit();
|
||||
|
||||
/* start executing the new process */
|
||||
@ -373,12 +393,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->wait4_out.status = exited->exit_status();
|
||||
Family_member::remove(exited);
|
||||
|
||||
/* destroy 'Noux::Child' */
|
||||
destroy(Genode::env()->heap(), exited);
|
||||
|
||||
PINF("quota: avail=%zd, used=%zd",
|
||||
Genode::env()->ram_session()->avail(),
|
||||
Genode::env()->ram_session()->used());
|
||||
PINF("submit exit signal for PID %d", exited->pid());
|
||||
static_cast<Child *>(exited)->submit_exit_signal();
|
||||
|
||||
} else {
|
||||
_sysio->wait4_out.pid = 0;
|
||||
@ -387,6 +403,28 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSCALL_PIPE:
|
||||
{
|
||||
Shared_pointer<Pipe> pipe(new Pipe, Genode::env()->heap());
|
||||
|
||||
Shared_pointer<Io_channel> pipe_sink(new Pipe_sink_io_channel(pipe, *_sig_rec),
|
||||
Genode::env()->heap());
|
||||
Shared_pointer<Io_channel> pipe_source(new Pipe_source_io_channel(pipe, *_sig_rec),
|
||||
Genode::env()->heap());
|
||||
|
||||
_sysio->pipe_out.fd[0] = add_io_channel(pipe_source);
|
||||
_sysio->pipe_out.fd[1] = add_io_channel(pipe_sink);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSCALL_DUP2:
|
||||
{
|
||||
add_io_channel(io_channel_by_fd(_sysio->dup2_in.fd),
|
||||
_sysio->dup2_in.to_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSCALL_INVALID: break;
|
||||
}
|
||||
}
|
||||
@ -588,9 +626,8 @@ int main(int argc, char **argv)
|
||||
Signal_dispatcher *dispatcher =
|
||||
static_cast<Signal_dispatcher *>(signal.context());
|
||||
|
||||
if (dispatcher)
|
||||
for (int i = 0; i < signal.num(); i++)
|
||||
dispatcher->dispatch();
|
||||
for (int i = 0; i < signal.num(); i++)
|
||||
dispatcher->dispatch();
|
||||
}
|
||||
|
||||
PINF("-- exiting noux ---");
|
||||
|
339
ports/src/noux/pipe_io_channel.h
Normal file
339
ports/src/noux/pipe_io_channel.h
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* \brief I/O channels for pipe input/output
|
||||
* \author Norman Feske
|
||||
* \date 2012-03-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 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__PIPE_IO_CHANNEL_H_
|
||||
#define _NOUX__PIPE_IO_CHANNEL_H_
|
||||
|
||||
/* Noux includes */
|
||||
#include <io_channel.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Pipe : public Reference_counter
|
||||
{
|
||||
private:
|
||||
|
||||
Lock mutable _lock;
|
||||
|
||||
enum { BUFFER_SIZE = 4096 };
|
||||
char _buffer[BUFFER_SIZE];
|
||||
|
||||
unsigned _read_offset;
|
||||
unsigned _write_offset;
|
||||
|
||||
Signal_context_capability _read_ready_sigh;
|
||||
Signal_context_capability _write_ready_sigh;
|
||||
|
||||
bool _writer_is_gone;
|
||||
|
||||
/**
|
||||
* Return space available in the buffer for writing, in bytes
|
||||
*/
|
||||
size_t _avail_buffer_space() const
|
||||
{
|
||||
if (_read_offset < _write_offset)
|
||||
return (BUFFER_SIZE - _write_offset) + _read_offset - 1;
|
||||
|
||||
if (_read_offset > _write_offset)
|
||||
return _read_offset - _write_offset - 1;
|
||||
|
||||
/* _read_offset == _write_offset */
|
||||
return BUFFER_SIZE - 1;
|
||||
}
|
||||
|
||||
bool _any_space_avail_for_writing() const
|
||||
{
|
||||
return _avail_buffer_space() > 0;;
|
||||
}
|
||||
|
||||
void _wake_up_reader()
|
||||
{
|
||||
if (_read_ready_sigh.valid())
|
||||
Signal_transmitter(_read_ready_sigh).submit();
|
||||
}
|
||||
|
||||
void _wake_up_writer()
|
||||
{
|
||||
if (_write_ready_sigh.valid())
|
||||
Signal_transmitter(_write_ready_sigh).submit();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Pipe()
|
||||
: _read_offset(0), _write_offset(0), _writer_is_gone(false) { }
|
||||
|
||||
~Pipe()
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
}
|
||||
|
||||
void writer_close()
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
_writer_is_gone = true;
|
||||
_write_ready_sigh = Signal_context_capability();
|
||||
_wake_up_reader();
|
||||
}
|
||||
|
||||
void reader_close()
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
_read_ready_sigh = Signal_context_capability();
|
||||
}
|
||||
|
||||
bool writer_is_gone() const
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
return _writer_is_gone;
|
||||
}
|
||||
|
||||
bool any_space_avail_for_writing() const
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
return _any_space_avail_for_writing();
|
||||
}
|
||||
|
||||
bool data_avail_for_reading() const
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
return _read_offset != _write_offset;
|
||||
}
|
||||
|
||||
size_t read(char *dst, size_t dst_len)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (_read_offset < _write_offset) {
|
||||
|
||||
size_t len = min(dst_len, _write_offset - _read_offset);
|
||||
memcpy(dst, &_buffer[_read_offset], len);
|
||||
|
||||
_read_offset += len;
|
||||
_wake_up_writer();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
if (_read_offset > _write_offset) {
|
||||
|
||||
size_t const upper_len = min(dst_len, BUFFER_SIZE - _read_offset);
|
||||
memcpy(dst, &_buffer[_read_offset], upper_len);
|
||||
|
||||
size_t const lower_len = min(dst_len - upper_len, _write_offset);
|
||||
memcpy(dst + upper_len, &_buffer[0], lower_len);
|
||||
|
||||
_read_offset = lower_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
|
||||
{
|
||||
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
|
||||
{
|
||||
return wr && _pipe->any_space_avail_for_writing();
|
||||
}
|
||||
|
||||
bool write(Sysio *sysio, size_t &count)
|
||||
{
|
||||
/*
|
||||
* 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 + count,
|
||||
sysio->write_in.count - count);
|
||||
count += curr_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fstat(Sysio *sysio)
|
||||
{
|
||||
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
** Signal_dispatcher interface **
|
||||
*********************************/
|
||||
|
||||
/**
|
||||
* Called by Noux main loop on the occurrence of new STDIN input
|
||||
*/
|
||||
void dispatch()
|
||||
{
|
||||
Io_channel::invoke_all_notifiers();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Pipe_source_io_channel : public Io_channel, public Signal_dispatcher
|
||||
{
|
||||
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
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
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 fstat(Sysio *sysio)
|
||||
{
|
||||
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
** Signal_dispatcher interface **
|
||||
*********************************/
|
||||
|
||||
/**
|
||||
* Called by Noux main loop on the occurrence of new STDIN input
|
||||
*/
|
||||
void dispatch()
|
||||
{
|
||||
Io_channel::invoke_all_notifiers();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _NOUX__PIPE_IO_CHANNEL_H_ */
|
@ -37,9 +37,7 @@ namespace Noux {
|
||||
return old_value;
|
||||
}
|
||||
|
||||
operator T () {
|
||||
PDBG("value=%d", (int)value);
|
||||
return value; }
|
||||
operator T () { return value; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,14 @@ namespace Noux {
|
||||
|
||||
struct Terminal_io_channel : Io_channel, Signal_dispatcher
|
||||
{
|
||||
Terminal::Session &terminal;
|
||||
Terminal::Session &terminal;
|
||||
Genode::Signal_receiver &sig_rec;
|
||||
|
||||
enum Type { STDIN, STDOUT, STDERR } type;
|
||||
|
||||
Terminal_io_channel(Terminal::Session &terminal, Type type,
|
||||
Genode::Signal_receiver &sig_rec)
|
||||
: terminal(terminal), type(type)
|
||||
: terminal(terminal), sig_rec(sig_rec), type(type)
|
||||
{
|
||||
/*
|
||||
* Enable wake up STDIN channel on the presence of new input
|
||||
@ -51,9 +52,12 @@ namespace Noux {
|
||||
}
|
||||
}
|
||||
|
||||
bool write(Sysio *sysio)
|
||||
~Terminal_io_channel() { sig_rec.dissolve(this); }
|
||||
|
||||
bool write(Sysio *sysio, size_t &count)
|
||||
{
|
||||
terminal.write(sysio->write_in.chunk, sysio->write_in.count);
|
||||
count = sysio->write_in.count;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -86,6 +90,9 @@ namespace Noux {
|
||||
|
||||
bool check_unblock(bool rd, bool wr, bool ex) const
|
||||
{
|
||||
/* 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.
|
||||
|
@ -96,6 +96,15 @@ namespace Noux {
|
||||
sysio->dirent_in.index -= 2;
|
||||
return _fh->ds()->dirent(sysio, _path.base());
|
||||
}
|
||||
|
||||
bool check_unblock(bool rd, bool wr, bool ex) const
|
||||
{
|
||||
/*
|
||||
* XXX For now, we use the TAR fs only, which never blocks.
|
||||
* However, real file systems may block.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,8 @@ namespace Noux {
|
||||
{
|
||||
Genode::Semaphore *semaphore;
|
||||
|
||||
Wake_up_notifier() : semaphore(0) { }
|
||||
Wake_up_notifier(Genode::Semaphore *semaphore = 0)
|
||||
: semaphore(semaphore) { }
|
||||
|
||||
void wake_up()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user