mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
vfs,libc: support write fds in select
By adding a 'write_ready' interface following the lines of the existing 'read_ready', VFS plugins become able to propagate the (de-)saturation of I/O buffers to the VFS user. This information is important when using a non-blocking file descriptor for writing into a TCP socket. Once the application observes EAGAIN, it expects a subsequent 'select' call to return as soon as new I/O buffer space becomes available. Before this patch, the select call would always return under this condition, causing an unnecessarily busy write loop. Issue #4697
This commit is contained in:
parent
5ad98f2b7c
commit
ff2176a586
@ -2001,6 +2001,12 @@ class Vfs::Lxip_file_system : public Vfs::File_system,
|
||||
return handle.read_ready();
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &vfs_handle) const override
|
||||
{
|
||||
/* wakeup from WRITE_ERR_WOULD_BLOCK not supported */
|
||||
return true;
|
||||
}
|
||||
|
||||
Sync_result complete_sync(Vfs_handle *vfs_handle)
|
||||
{
|
||||
Vfs::Lxip_vfs_handle *handle =
|
||||
|
@ -809,6 +809,8 @@ class Vfs::Rump_file_system : public File_system
|
||||
|
||||
bool read_ready(Vfs_handle *) override { return true; }
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override { return true; }
|
||||
|
||||
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) override
|
||||
{
|
||||
Rump_vfs_file_handle *handle =
|
||||
|
@ -275,6 +275,12 @@ class Vfs_audit::File_system : public Vfs::File_system
|
||||
return h.audit->fs().read_ready(h.audit);
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &vfs_handle) const override
|
||||
{
|
||||
Handle const &h = static_cast<Handle const &>(vfs_handle);
|
||||
return h.audit->fs().write_ready(*h.audit);
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
Handle &h = *static_cast<Handle*>(vfs_handle);
|
||||
|
@ -2021,6 +2021,8 @@ class Vfs_cbe::Data_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
Data_file_system(Wrapper &w, uint32_t snap_id)
|
||||
@ -2190,6 +2192,8 @@ class Vfs_cbe::Extend_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -2373,6 +2377,8 @@ class Vfs_cbe::Rekey_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -2556,6 +2562,8 @@ class Vfs_cbe::Deinitialize_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -2692,6 +2700,8 @@ class Vfs_cbe::Create_snapshot_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -2790,6 +2800,8 @@ class Vfs_cbe::Discard_snapshot_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -3148,7 +3160,6 @@ class Vfs_cbe::Snapshots_file_system : public Vfs::File_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
};
|
||||
|
||||
struct Dir_snap_vfs_handle : Vfs::Vfs_handle
|
||||
@ -3451,6 +3462,11 @@ class Vfs_cbe::Snapshots_file_system : public Vfs::File_system
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs::Vfs_handle const &) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Ftruncate_result ftruncate(Vfs::Vfs_handle *vfs_handle,
|
||||
file_size len) override
|
||||
{
|
||||
|
@ -124,6 +124,8 @@ class Vfs_cbe_crypto::Encrypt_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -256,6 +258,8 @@ class Vfs_cbe_crypto::Decrypt_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -893,6 +897,12 @@ class Vfs_cbe_crypto::Keys_file_system : public Vfs::File_system
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs::Vfs_handle const &) const override
|
||||
{
|
||||
/* wakeup from WRITE_ERR_WOULD_BLOCK not supported */
|
||||
return true;
|
||||
}
|
||||
|
||||
Ftruncate_result ftruncate(Vfs::Vfs_handle *, file_size ) override
|
||||
{
|
||||
return FTRUNCATE_OK;
|
||||
@ -997,6 +1007,8 @@ class Vfs_cbe_crypto::Management_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
char const *_type_name;
|
||||
|
@ -1370,6 +1370,8 @@ class Vfs_cbe_trust_anchor::Hashsum_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -1476,6 +1478,8 @@ class Vfs_cbe_trust_anchor::Generate_key_file_system : public Vfs::Single_file_s
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -1604,6 +1608,8 @@ class Vfs_cbe_trust_anchor::Encrypt_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -1731,6 +1737,8 @@ class Vfs_cbe_trust_anchor::Decrypt_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
@ -1851,6 +1859,8 @@ class Vfs_cbe_trust_anchor::Initialize_file_system : public Vfs::Single_file_sys
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -81,6 +81,8 @@ struct Vfs_gpu::File_system : Single_file_system
|
||||
|
||||
bool read_ready() override { return _complete; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
|
||||
Id_space::Id id() const { return _elem.id(); }
|
||||
};
|
||||
|
||||
|
@ -287,6 +287,9 @@ class Vfs_import::File_system : public Vfs::File_system
|
||||
bool read_ready(Vfs_handle*) override {
|
||||
return true; }
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override {
|
||||
return true; }
|
||||
|
||||
bool notify_read_ready(Vfs_handle*) override {
|
||||
return false; }
|
||||
|
||||
|
@ -77,6 +77,7 @@ struct Vfs_pipe::Pipe_handle : Vfs::Vfs_handle, private Pipe_handle_registry_ele
|
||||
file_size &out_count);
|
||||
|
||||
bool read_ready();
|
||||
bool write_ready() const;
|
||||
bool notify_read_ready();
|
||||
};
|
||||
|
||||
@ -280,13 +281,21 @@ Vfs_pipe::Pipe_handle::read(char *buf,
|
||||
return Pipe_handle::pipe.read(*this, buf, count, out_count); }
|
||||
|
||||
|
||||
bool
|
||||
Vfs_pipe::Pipe_handle::read_ready() {
|
||||
bool Vfs_pipe::Pipe_handle::read_ready() {
|
||||
return !writer && !pipe.buffer.empty(); }
|
||||
|
||||
|
||||
bool
|
||||
Vfs_pipe::Pipe_handle::notify_read_ready()
|
||||
bool Vfs_pipe::Pipe_handle::write_ready() const
|
||||
{
|
||||
/*
|
||||
* Unconditionally return true for the writer side because
|
||||
* WRITE_ERR_WOULD_BLOCK is not yet supported.
|
||||
*/
|
||||
return writer;
|
||||
}
|
||||
|
||||
|
||||
bool Vfs_pipe::Pipe_handle::notify_read_ready()
|
||||
{
|
||||
if (!writer && !read_ready_elem.enqueued())
|
||||
pipe.read_ready_waiters.enqueue(read_ready_elem);
|
||||
@ -597,6 +606,13 @@ class Vfs_pipe::File_system : public Vfs::File_system
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &vfs_handle) const override
|
||||
{
|
||||
if (Pipe_handle const *handle = dynamic_cast<Pipe_handle const *>(&vfs_handle))
|
||||
return handle->write_ready();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
if (Pipe_handle *handle = dynamic_cast<Pipe_handle*>(vfs_handle))
|
||||
|
@ -148,6 +148,8 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
Trace_buffer_file_system(Vfs::Env &env,
|
||||
|
@ -107,6 +107,8 @@ class Vfs::Glyphs_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
typedef Registered<Vfs_watch_handle> Registered_watch_handle;
|
||||
|
@ -48,6 +48,7 @@
|
||||
namespace Libc {
|
||||
extern char const *config_socket();
|
||||
bool read_ready_from_kernel(File_descriptor *);
|
||||
bool write_ready_from_kernel(File_descriptor *);
|
||||
}
|
||||
|
||||
|
||||
@ -199,6 +200,14 @@ struct Libc::Socket_fs::Context : Plugin_context
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _fd_write_ready(Fd type)
|
||||
{
|
||||
if (_fd[type].file)
|
||||
return Libc::write_ready_from_kernel(_fd[type].file);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Context(Proto proto, int handle_fd)
|
||||
@ -260,8 +269,7 @@ struct Libc::Socket_fs::Context : Plugin_context
|
||||
if (_state == CONNECTING)
|
||||
return connect_read_ready();
|
||||
|
||||
/* XXX ask if "data" is writeable */
|
||||
return true;
|
||||
return _fd_write_ready(Fd::DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -950,7 +958,13 @@ static ssize_t do_sendto(File_descriptor *fd,
|
||||
break;
|
||||
|
||||
case Socket_fs::Context::Proto::TCP:
|
||||
if (out_len == 0) return Errno(EAGAIN);
|
||||
|
||||
/*
|
||||
* Non-blocking write stalled
|
||||
*/
|
||||
if ((out_len == -1) && (errno == EAGAIN))
|
||||
return Errno(EAGAIN);
|
||||
|
||||
/*
|
||||
* Write errors to TCP-data files are reflected as EPIPE, which
|
||||
* means the connection-mode socket is no longer connected. This
|
||||
@ -961,7 +975,8 @@ static ssize_t do_sendto(File_descriptor *fd,
|
||||
* TODO If the MSG_NOSIGNAL flag is not set, the SIGPIPE signal is
|
||||
* generated to the calling thread.
|
||||
*/
|
||||
if (out_len == -1) return Errno(EPIPE);
|
||||
if (out_len == -1)
|
||||
return Errno(EPIPE);
|
||||
break;
|
||||
}
|
||||
return out_len;
|
||||
@ -1358,7 +1373,6 @@ int Socket_fs::Plugin::select(int nfds,
|
||||
if (fd_in_writefds) {
|
||||
try {
|
||||
Socket_fs::Context *context = dynamic_cast<Socket_fs::Context *>(fdo->context);
|
||||
|
||||
if (context->write_ready()) {
|
||||
FD_SET(fd, writefds);
|
||||
++nready;
|
||||
|
@ -221,6 +221,15 @@ namespace Libc {
|
||||
|
||||
return handle->fs().read_ready(handle);
|
||||
}
|
||||
|
||||
bool write_ready_from_kernel(File_descriptor *fd)
|
||||
{
|
||||
Vfs::Vfs_handle const *handle = vfs_handle(fd);
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
return handle->fs().write_ready(*handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -839,10 +848,8 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
|
||||
|
||||
Vfs::file_size out_count = 0;
|
||||
Result out_result = Result::WRITE_OK;
|
||||
bool const nonblocking = (fd->flags & O_NONBLOCK);
|
||||
|
||||
if (nonblocking) {
|
||||
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
monitor().monitor([&] {
|
||||
out_result = handle->fs().write(handle, (char const *)buf, count, out_count);
|
||||
return Fn::COMPLETE;
|
||||
@ -946,11 +953,6 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
|
||||
handle->advance_seek(out_count);
|
||||
fd->modified = true;
|
||||
|
||||
/* notify remote peers once our VFS' local I/O buffers are saturated */
|
||||
bool const nonblocking_write_stalled = nonblocking && count && !out_count;
|
||||
if (nonblocking_write_stalled)
|
||||
Libc::Kernel::kernel().wakeup_remote_peers();
|
||||
|
||||
return out_count;
|
||||
}
|
||||
|
||||
@ -2731,7 +2733,7 @@ int Libc::Vfs_plugin::select(int nfds,
|
||||
}
|
||||
|
||||
if (fd_in_writefds) {
|
||||
if (true /* XXX always writeable */) {
|
||||
if (handle->fs().write_ready(*handle)) {
|
||||
FD_SET(fd, writefds);
|
||||
++nready;
|
||||
}
|
||||
|
@ -779,6 +779,14 @@ class Fatfs::File_system : public Vfs::File_system
|
||||
|
||||
bool read_ready(Vfs_handle *) override { return true; }
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override
|
||||
{
|
||||
/*
|
||||
* Wakeup from WRITE_ERR_WOULD_BLOCK not supported.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify other handles if this handle has modified its file.
|
||||
*
|
||||
|
@ -94,7 +94,9 @@ class Jitterentropy_file_system : public Vfs::Single_file_system
|
||||
return WRITE_ERR_IO;
|
||||
}
|
||||
|
||||
bool read_ready() { return true; }
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -88,6 +88,11 @@ class Libusb_file_system : public Vfs::Single_file_system
|
||||
return READ_ERR_IO;
|
||||
}
|
||||
|
||||
bool write_ready() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Write_result write(char const *src, Vfs::file_size count,
|
||||
Vfs::file_size &out_count) override
|
||||
{
|
||||
|
@ -88,6 +88,8 @@ class Lwip::Nic_netif
|
||||
|
||||
Wakeup_scheduler &_wakeup_scheduler;
|
||||
|
||||
bool _tx_saturated = false;
|
||||
|
||||
enum {
|
||||
PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
|
||||
BUF_SIZE = 1024*PACKET_SIZE,
|
||||
@ -202,6 +204,7 @@ class Lwip::Nic_netif
|
||||
/* flush acknowledgements */
|
||||
while (tx.ack_avail()) {
|
||||
tx.release_packet(tx.try_get_acked_packet());
|
||||
_tx_saturated = false;
|
||||
progress = true;
|
||||
}
|
||||
|
||||
@ -309,6 +312,8 @@ class Lwip::Nic_netif
|
||||
|
||||
Lwip::netif& lwip_netif() { return _netif; }
|
||||
|
||||
bool tx_saturated() const { return _tx_saturated; }
|
||||
|
||||
/**
|
||||
* Status callback to override in subclass
|
||||
*/
|
||||
@ -372,11 +377,14 @@ class Lwip::Nic_netif
|
||||
auto &tx = *_nic.tx();
|
||||
|
||||
/* flush acknowledgements */
|
||||
while (tx.ack_avail())
|
||||
while (tx.ack_avail()) {
|
||||
tx.release_packet(tx.get_acked_packet());
|
||||
_tx_saturated = false;
|
||||
}
|
||||
|
||||
if (!tx.ready_to_submit()) {
|
||||
Genode::error("lwIP: Nic packet queue congested, cannot send packet");
|
||||
_tx_saturated = true;
|
||||
return ERR_WOULDBLOCK;
|
||||
}
|
||||
|
||||
@ -384,6 +392,7 @@ class Lwip::Nic_netif
|
||||
try { packet = tx.alloc_packet(p->tot_len); }
|
||||
catch (...) {
|
||||
Genode::error("lwIP: Nic packet allocation failed, cannot send packet");
|
||||
_tx_saturated = true;
|
||||
return ERR_WOULDBLOCK;
|
||||
}
|
||||
|
||||
|
@ -428,6 +428,8 @@ struct Lwip::Socket_dir : Lwip::Directory
|
||||
|
||||
virtual bool read_ready(Lwip_file_handle&) = 0;
|
||||
|
||||
virtual bool write_ready(Lwip_file_handle const &) const = 0;
|
||||
|
||||
/**
|
||||
* Notify handles waiting for this PCB / socket to be ready
|
||||
*/
|
||||
@ -987,6 +989,11 @@ class Lwip::Udp_socket_dir final :
|
||||
return result;
|
||||
}
|
||||
|
||||
bool write_ready(Lwip_file_handle const &) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Write_result write(Lwip_file_handle &handle,
|
||||
char const *src, file_size count,
|
||||
file_size &out_count) override
|
||||
@ -1453,6 +1460,30 @@ class Lwip::Tcp_socket_dir final :
|
||||
return Read_result::READ_ERR_INVALID;
|
||||
}
|
||||
|
||||
bool write_ready(Lwip_file_handle const &handle) const override
|
||||
{
|
||||
switch (handle.kind) {
|
||||
case Lwip_file_handle::DATA:
|
||||
|
||||
return tcp_sndbuf(_pcb);
|
||||
|
||||
case Lwip_file_handle::PEEK:
|
||||
case Lwip_file_handle::ACCEPT:
|
||||
case Lwip_file_handle::PENDING:
|
||||
case Lwip_file_handle::BIND:
|
||||
case Lwip_file_handle::REMOTE:
|
||||
case Lwip_file_handle::CONNECT:
|
||||
case Lwip_file_handle::LOCATION:
|
||||
case Lwip_file_handle::LOCAL:
|
||||
return true;
|
||||
|
||||
case Lwip_file_handle::INVALID:
|
||||
case Lwip_file_handle::LISTEN:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Write_result write(Lwip_file_handle &handle,
|
||||
char const *src, file_size count,
|
||||
file_size &out_count) override
|
||||
@ -1704,21 +1735,43 @@ void tcp_err_callback(void *arg, err_t)
|
||||
** VFS file-system **
|
||||
*********************/
|
||||
|
||||
class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory,
|
||||
private Vfs::Remote_io
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Entrypoint &_ep;
|
||||
|
||||
struct Wakeup_scheduler : Lwip::Nic_netif::Wakeup_scheduler
|
||||
{
|
||||
Vfs::Env::User &_vfs_user;
|
||||
|
||||
Remote_io::Peer _peer;
|
||||
|
||||
/**
|
||||
* Lwip::Nic_netif::Wakeup_scheduler interface
|
||||
*
|
||||
* Called from Lwip::Nic_netif.
|
||||
*/
|
||||
void schedule_nic_server_wakeup() override
|
||||
{
|
||||
_vfs_user.wakeup_vfs_user();
|
||||
_peer.schedule_wakeup();
|
||||
}
|
||||
|
||||
Wakeup_scheduler(Vfs::Env &vfs_env, Remote_io &remote_io)
|
||||
:
|
||||
_vfs_user(vfs_env.user()),
|
||||
_peer(vfs_env.deferred_wakeups(), remote_io)
|
||||
{ }
|
||||
|
||||
} _wakeup_scheduler;
|
||||
|
||||
/**
|
||||
* LwIP connection to Nic service
|
||||
*/
|
||||
struct Vfs_netif : Lwip::Nic_netif,
|
||||
private Vfs::Remote_io,
|
||||
private Lwip::Nic_netif::Wakeup_scheduler
|
||||
struct Vfs_netif : Lwip::Nic_netif
|
||||
{
|
||||
Remote_io::Peer _peer;
|
||||
|
||||
Tcp_proto_dir tcp_dir;
|
||||
Udp_proto_dir udp_dir;
|
||||
|
||||
@ -1729,10 +1782,11 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
|
||||
Handle_queue blocked_handles { };
|
||||
|
||||
Vfs_netif(Vfs::Env &vfs_env, Genode::Xml_node config)
|
||||
Vfs_netif(Vfs::Env &vfs_env, Genode::Xml_node config,
|
||||
Lwip::Nic_netif::Wakeup_scheduler &wakeup_scheduler)
|
||||
:
|
||||
Lwip::Nic_netif(vfs_env.env(), vfs_env.alloc(), config, *this),
|
||||
_peer(vfs_env.deferred_wakeups(), *this),
|
||||
Lwip::Nic_netif(vfs_env.env(), vfs_env.alloc(), config,
|
||||
wakeup_scheduler),
|
||||
tcp_dir(vfs_env), udp_dir(vfs_env)
|
||||
{ }
|
||||
|
||||
@ -1742,26 +1796,6 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
status_callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lwip::Nic_netif::Wakeup_scheduler interface
|
||||
*
|
||||
* Called from Lwip::Nic_netif.
|
||||
*/
|
||||
void schedule_nic_server_wakeup() override
|
||||
{
|
||||
_peer.schedule_wakeup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote_io interface
|
||||
*
|
||||
* Called from VFS user when going idle.
|
||||
*/
|
||||
void wakeup_remote_peer() override
|
||||
{
|
||||
Lwip::Nic_netif::wakeup_nic_server();
|
||||
}
|
||||
|
||||
void enqueue(Vfs_handle &handle)
|
||||
{
|
||||
Handle_element *elem = new (handle.alloc())
|
||||
@ -1797,9 +1831,18 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} _netif;
|
||||
|
||||
/**
|
||||
* Remote_io interface
|
||||
*
|
||||
* Called from VFS user when going idle.
|
||||
*/
|
||||
void wakeup_remote_peer() override
|
||||
{
|
||||
_netif.wakeup_nic_server();
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk a path to a protocol directory and apply procedure
|
||||
*/
|
||||
@ -1828,7 +1871,9 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
|
||||
File_system(Vfs::Env &vfs_env, Genode::Xml_node config)
|
||||
:
|
||||
_ep(vfs_env.env().ep()), _netif(vfs_env, config)
|
||||
_ep(vfs_env.env().ep()),
|
||||
_wakeup_scheduler(vfs_env, *this),
|
||||
_netif(vfs_env, config, _wakeup_scheduler)
|
||||
{ }
|
||||
|
||||
/**
|
||||
@ -1850,6 +1895,7 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
return Read_result::READ_ERR_INVALID;
|
||||
};
|
||||
|
||||
|
||||
/***********************
|
||||
** Directory_service **
|
||||
***********************/
|
||||
@ -2079,6 +2125,20 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &vfs_handle) const override
|
||||
{
|
||||
if (_netif.tx_saturated())
|
||||
return false;
|
||||
|
||||
Lwip_file_handle const *handle_ptr =
|
||||
dynamic_cast<Lwip_file_handle const *>(&vfs_handle);
|
||||
|
||||
if (handle_ptr && handle_ptr->socket)
|
||||
return handle_ptr->socket->write_ready(*handle_ptr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
if (Lwip_file_handle *handle = dynamic_cast<Lwip_file_handle*>(vfs_handle))
|
||||
|
@ -290,6 +290,12 @@ struct Vfs::Oss_file_system::Audio
|
||||
return _info.ifrag_bytes > 0;
|
||||
}
|
||||
|
||||
bool write_ready() const
|
||||
{
|
||||
/* wakeup from WRITE_ERR_WOULD_BLOCK not yet supported */
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_info_ofrag_avail_from_optr_fifo_samples()
|
||||
{
|
||||
_info.ofrag_bytes = (_info.ofrag_total * _info.ofrag_size) -
|
||||
@ -679,6 +685,11 @@ class Vfs::Oss_file_system::Data_file_system : public Single_file_system
|
||||
{
|
||||
return _audio.read_ready();
|
||||
}
|
||||
|
||||
bool write_ready() const override
|
||||
{
|
||||
return _audio.write_ready();
|
||||
}
|
||||
};
|
||||
|
||||
using Registered_handle = Genode::Registered<Oss_vfs_handle>;
|
||||
|
@ -973,6 +973,14 @@ class Vfs::Dir_file_system : public File_system
|
||||
return handle->fs().read_ready(handle);
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &handle) const override
|
||||
{
|
||||
if (&handle.fs() == this)
|
||||
return false;
|
||||
|
||||
return handle.fs().write_ready(handle);
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *handle) override
|
||||
{
|
||||
if (&handle->fs() == this)
|
||||
|
@ -69,6 +69,11 @@ struct Vfs::File_io_service : Interface
|
||||
*/
|
||||
virtual bool read_ready(Vfs_handle *) = 0;
|
||||
|
||||
/**
|
||||
* Return true if the handle might accept a write operation
|
||||
*/
|
||||
virtual bool write_ready(Vfs_handle const &) const = 0;
|
||||
|
||||
/**
|
||||
* Explicitly indicate interest in read-ready for a handle
|
||||
*
|
||||
|
@ -73,6 +73,8 @@ class Vfs::Readonly_value_file_system : public Vfs::Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
typedef Genode::String<200> Config;
|
||||
|
@ -30,14 +30,14 @@ class Vfs::Simple_env : public Vfs::Env, private Vfs::Env::Io, private Vfs::Env:
|
||||
Genode::Allocator &_alloc;
|
||||
Vfs::Env::User &_user;
|
||||
|
||||
Global_file_system_factory _fs_factory { _alloc };
|
||||
|
||||
Dir_file_system _root_dir;
|
||||
|
||||
using Deferred_wakeups = Remote_io::Deferred_wakeups;
|
||||
|
||||
Deferred_wakeups _deferred_wakeups { };
|
||||
|
||||
Global_file_system_factory _fs_factory { _alloc };
|
||||
|
||||
Dir_file_system _root_dir;
|
||||
|
||||
public:
|
||||
|
||||
Simple_env(Genode::Env &env,
|
||||
|
@ -50,6 +50,8 @@ class Vfs::Single_file_system : public File_system
|
||||
|
||||
virtual bool read_ready() = 0;
|
||||
|
||||
virtual bool write_ready() const = 0;
|
||||
|
||||
virtual bool notify_read_ready() { return true; }
|
||||
};
|
||||
|
||||
@ -131,6 +133,8 @@ class Vfs::Single_file_system : public File_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
bool _root(const char *path)
|
||||
@ -288,6 +292,14 @@ class Vfs::Single_file_system : public File_system
|
||||
return false;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &vfs_handle) const override
|
||||
{
|
||||
Single_vfs_handle const &handle =
|
||||
static_cast<Single_vfs_handle const &>(vfs_handle);
|
||||
|
||||
return handle.write_ready();
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
Single_vfs_handle *handle =
|
||||
|
@ -86,6 +86,8 @@ class Vfs::Value_file_system : public Vfs::Single_file_system
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
|
||||
private:
|
||||
|
||||
Vfs_handle(Vfs_handle const &);
|
||||
|
@ -120,6 +120,8 @@ class Vfs::Vfs_handle
|
||||
File_io_service &fs() { return _fs; }
|
||||
Allocator &alloc() { return _alloc; }
|
||||
|
||||
File_io_service const &fs() const { return _fs; }
|
||||
|
||||
int status_flags() const { return _status_flags; }
|
||||
void status_flags(int flags) { _status_flags = flags; }
|
||||
|
||||
|
@ -338,6 +338,8 @@ class Vfs::Block_file_system::Data_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -67,8 +67,9 @@ class Vfs_capture::Data_file_system : public Single_file_system
|
||||
_capture(capture), _capture_ds(capture_ds)
|
||||
{ }
|
||||
|
||||
bool read_ready() override {
|
||||
return true; }
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
|
||||
Read_result read(char *dst, file_size count,
|
||||
file_size &out_count) override
|
||||
|
@ -39,6 +39,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
|
||||
|
||||
::File_system::Connection _fs;
|
||||
|
||||
bool _write_would_block = false;
|
||||
|
||||
typedef Genode::Id_space<::File_system::Node> Handle_space;
|
||||
|
||||
Handle_space _handle_space { };
|
||||
@ -524,6 +526,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
|
||||
if (!source.ready_to_submit()) {
|
||||
if (!handle.enqueued())
|
||||
_congested_handles.enqueue(handle);
|
||||
|
||||
_write_would_block = true;
|
||||
return Write_result::WRITE_ERR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
@ -541,6 +545,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
|
||||
catch (::File_system::Session::Tx::Source::Packet_alloc_failed) {
|
||||
if (!handle.enqueued())
|
||||
_congested_handles.enqueue(handle);
|
||||
|
||||
_write_would_block = true;
|
||||
return Write_result::WRITE_ERR_WOULD_BLOCK;
|
||||
}
|
||||
catch (...) {
|
||||
@ -559,6 +565,7 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
|
||||
while (source.ack_avail()) {
|
||||
|
||||
Packet_descriptor const packet = source.try_get_acked_packet();
|
||||
_write_would_block = false;
|
||||
_peer.schedule_wakeup();
|
||||
|
||||
Handle_space::Id const id(packet.handle());
|
||||
@ -1007,6 +1014,11 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
|
||||
return handle->read_ready_state == Handle_state::Read_ready_state::READY;
|
||||
}
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override
|
||||
{
|
||||
return !_write_would_block;
|
||||
}
|
||||
|
||||
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
Fs_vfs_handle *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
||||
|
@ -90,6 +90,8 @@ class Vfs::Inline_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -128,6 +128,8 @@ class Vfs::Log_file_system : public Single_file_system
|
||||
|
||||
bool read_ready() override { return false; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
|
||||
Sync_result sync() override
|
||||
{
|
||||
if (_line_pos > 0)
|
||||
|
@ -54,6 +54,8 @@ struct Vfs::Null_file_system : Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return false; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
/*********************************
|
||||
@ -61,8 +63,8 @@ struct Vfs::Null_file_system : Single_file_system
|
||||
*********************************/
|
||||
|
||||
Open_result open(char const *path, unsigned,
|
||||
Vfs_handle **out_handle,
|
||||
Allocator &alloc) override
|
||||
Vfs_handle **out_handle,
|
||||
Allocator &alloc) override
|
||||
{
|
||||
if (!_single_file(path))
|
||||
return OPEN_ERR_UNACCESSIBLE;
|
||||
|
@ -968,6 +968,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
|
||||
bool read_ready(Vfs_handle *) override { return true; }
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override { return true; }
|
||||
|
||||
Ftruncate_result ftruncate(Vfs_handle * const vfs_handle, file_size len) override
|
||||
{
|
||||
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
|
||||
|
@ -113,6 +113,8 @@ class Vfs::Rom_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
typedef Genode::Registered<Vfs_watch_handle> Registered_watch_handle;
|
||||
|
@ -82,6 +82,8 @@ class Vfs::Rtc_file_system : public Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
typedef Genode::Registered<Vfs_watch_handle> Registered_watch_handle;
|
||||
|
@ -54,6 +54,8 @@ class Vfs::Symlink_file_system : public Single_file_system
|
||||
return WRITE_ERR_INVALID; }
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return false; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -134,6 +134,12 @@ class Vfs::Nic_file_system::Nic_vfs_handle : public Single_vfs_handle
|
||||
bool read_ready() override {
|
||||
return _link_state && _nic.rx()->packet_avail() && _nic.rx()->ready_to_ack(); }
|
||||
|
||||
bool write_ready() const override
|
||||
{
|
||||
/* wakeup from WRITE_ERR_WOULD_BLOCK not supported */
|
||||
return _link_state;
|
||||
}
|
||||
|
||||
Read_result read(char *dst, file_size count,
|
||||
file_size &out_count) override
|
||||
{
|
||||
|
@ -124,6 +124,12 @@ class Vfs::Uplink_file_system::Uplink_vfs_handle : public Single_vfs_handle,
|
||||
bool read_ready() override {
|
||||
return _drv_link_state && _conn->rx()->packet_avail() && _conn->rx()->ready_to_ack(); }
|
||||
|
||||
bool write_ready() const override
|
||||
{
|
||||
/* wakeup from WRITE_ERR_WOULD_BLOCK not supported */
|
||||
return _drv_link_state;
|
||||
}
|
||||
|
||||
Read_result read(char *dst, file_size count,
|
||||
file_size &out_count) override
|
||||
{
|
||||
|
@ -776,6 +776,8 @@ class Vfs::Tar_file_system : public File_system
|
||||
}
|
||||
|
||||
bool read_ready(Vfs_handle *) override { return true; }
|
||||
|
||||
bool write_ready(Vfs_handle const &) const override { return false; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VFS__TAR_FILE_SYSTEM_H_ */
|
||||
|
@ -137,6 +137,8 @@ class Vfs::Terminal_file_system::Data_file_system : public Single_file_system
|
||||
bool read_ready() override {
|
||||
return !_read_buffer.empty(); }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
|
||||
bool notify_read_ready() override
|
||||
{
|
||||
notifying = true;
|
||||
|
@ -82,6 +82,8 @@ struct Vfs::Zero_file_system : Single_file_system
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
||||
bool write_ready() const override { return true; }
|
||||
};
|
||||
|
||||
/*********************************
|
||||
|
Loading…
Reference in New Issue
Block a user