From afeb54ebedd44fd5fe784041e35cd1fa0bb97eee Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 19 Mar 2012 22:52:26 +0100 Subject: [PATCH] Add pipe and dup2 syscalls to Noux Fixes #133. --- ports/include/noux_session/noux_session.h | 4 + ports/include/noux_session/sysio.h | 3 + ports/src/lib/libc_noux/plugin.cc | 47 ++- ports/src/noux/child.h | 22 +- ports/src/noux/io_channel.h | 32 +- ports/src/noux/main.cc | 75 +++-- ports/src/noux/pipe_io_channel.h | 339 ++++++++++++++++++++++ ports/src/noux/range_checked_index.h | 4 +- ports/src/noux/terminal_io_channel.h | 13 +- ports/src/noux/vfs_io_channel.h | 9 + ports/src/noux/wake_up_notifier.h | 3 +- 11 files changed, 505 insertions(+), 46 deletions(-) create mode 100644 ports/src/noux/pipe_io_channel.h diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index 0f36659096..bd76b8fa6f 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -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; diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index 449ec9eb22..4183ccf8bf 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -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; }, { }); }; }; }; diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index e3bc250ba8..2f8061b8fe 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -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); diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h index 23e3368c65..afd420ca85 100644 --- a/ports/src/noux/child.h +++ b/ports/src/noux/child.h @@ -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) + { + 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; } diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h index 2352c1b39f..a6de7cb2ba 100644 --- a/ports/src/noux/io_channel.h +++ b/ports/src/noux/io_channel.h @@ -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 _notifiers; - Genode::Lock _notifiers_lock; + List _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(); diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index af74eb02ac..9a387201f8 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -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 #include #include +#include #include #include @@ -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 = _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 = _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 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(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(new Pipe, Genode::env()->heap()); + + Shared_pointer pipe_sink(new Pipe_sink_io_channel(pipe, *_sig_rec), + Genode::env()->heap()); + Shared_pointer pipe_source(new Pipe_source_io_channel(pipe, *_sig_rec), + Genode::env()->heap()); + + _sysio->pipe_out.fd[0] = add_io_channel(pipe_source); + _sysio->pipe_out.fd[1] = add_io_channel(pipe_sink); + + 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.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 ---"); diff --git a/ports/src/noux/pipe_io_channel.h b/ports/src/noux/pipe_io_channel.h new file mode 100644 index 0000000000..d5d630f1a2 --- /dev/null +++ b/ports/src/noux/pipe_io_channel.h @@ -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 + +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; + Signal_receiver &_sig_rec; + + public: + + Pipe_sink_io_channel(Shared_pointer pipe, + Signal_receiver &sig_rec) + : _pipe(pipe), _sig_rec(sig_rec) + { + pipe->register_write_ready_sigh(_sig_rec.manage(this)); + } + + ~Pipe_sink_io_channel() + { + _sig_rec.dissolve(this); + _pipe->writer_close(); + } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + 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; + Signal_receiver &_sig_rec; + + public: + + Pipe_source_io_channel(Shared_pointer pipe, Signal_receiver &sig_rec) + : _pipe(pipe), _sig_rec(sig_rec) + { + _pipe->register_read_ready_sigh(sig_rec.manage(this)); + } + + ~Pipe_source_io_channel() + { + _sig_rec.dissolve(this); + _pipe->reader_close(); + } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + /* 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_ */ diff --git a/ports/src/noux/range_checked_index.h b/ports/src/noux/range_checked_index.h index 01e9bb94fb..02066d6860 100644 --- a/ports/src/noux/range_checked_index.h +++ b/ports/src/noux/range_checked_index.h @@ -37,9 +37,7 @@ namespace Noux { return old_value; } - operator T () { - PDBG("value=%d", (int)value); - return value; } + operator T () { return value; } }; } diff --git a/ports/src/noux/terminal_io_channel.h b/ports/src/noux/terminal_io_channel.h index b91d1526d6..30dbe3f876 100644 --- a/ports/src/noux/terminal_io_channel.h +++ b/ports/src/noux/terminal_io_channel.h @@ -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. diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h index 1685a6cab0..09c534f86a 100644 --- a/ports/src/noux/vfs_io_channel.h +++ b/ports/src/noux/vfs_io_channel.h @@ -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; + } }; } diff --git a/ports/src/noux/wake_up_notifier.h b/ports/src/noux/wake_up_notifier.h index 975fcf8bcd..3c46c3d5b1 100644 --- a/ports/src/noux/wake_up_notifier.h +++ b/ports/src/noux/wake_up_notifier.h @@ -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() {