Support for suspendable read in VFS and libC

The support has two parts. First, a VFS plugin now gets passed an
I/O-response handler callback on construction, which informs users of the
VFS that an I/O event occurred. This enables, for example, the libC to
check if blocking read can be completed. Further, the VFS file I/O
interface provides now functions for suspendable reads, i.e.,
queue_read() and complete_read().
This commit is contained in:
Christian Helmuth 2017-01-31 16:38:23 +01:00 committed by Norman Feske
parent e5d6c06f58
commit c0d61858c3
25 changed files with 199 additions and 71 deletions

View File

@ -43,6 +43,7 @@ namespace Libc {
class Timer_accessor;
class Timeout;
class Timeout_handler;
class Io_response_handler;
using Microseconds = Genode::Time_source::Microseconds;
}
@ -79,10 +80,11 @@ class Libc::Env_implementation : public Libc::Env
public:
Env_implementation(Genode::Env &env, Genode::Allocator &alloc)
Env_implementation(Genode::Env &env, Genode::Allocator &alloc,
Vfs::Io_response_handler &io_response_handler)
:
_env(env),
_vfs(_env, alloc, _vfs_config(),
_vfs(_env, alloc, _vfs_config(), io_response_handler,
Vfs::global_file_system_factory())
{ }
@ -301,6 +303,15 @@ struct Libc::Pthreads
};
struct Libc::Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response() override
{
Libc::resume_all();
}
};
/* internal utility */
static void resumed_callback();
static void suspended_callback();
@ -320,10 +331,11 @@ struct Libc::Kernel
{
private:
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
Env_implementation _libc_env { _env, _heap };
Vfs_plugin _vfs { _libc_env, _heap };
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
Io_response_handler _io_response_handler;
Env_implementation _libc_env { _env, _heap, _io_response_handler };
Vfs_plugin _vfs { _libc_env, _heap };
jmp_buf _kernel_context;
jmp_buf _user_context;

View File

@ -38,6 +38,7 @@
/* libc-internal includes */
#include <libc_mem_alloc.h>
#include "libc_errno.h"
#include "task.h"
static Vfs::Vfs_handle *vfs_handle(Libc::File_descriptor *fd)
@ -287,15 +288,28 @@ ssize_t Libc::Vfs_plugin::read(Libc::File_descriptor *fd, void *buf,
Vfs::Vfs_handle *handle = vfs_handle(fd);
Vfs::file_size out_count = 0;
Vfs::file_size out_count = 0;
Result out_result = Result::READ_OK;
switch (handle->fs().read(handle, (char *)buf, count, out_count)) {
case Result::READ_ERR_AGAIN: errno = EAGAIN; return -1;
case Result::READ_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; return -1;
case Result::READ_ERR_INVALID: errno = EINVAL; return -1;
case Result::READ_ERR_IO: errno = EIO; return -1;
case Result::READ_ERR_INTERRUPT: errno = EINTR; return -1;
case Result::READ_OK: break;
while (!handle->fs().queue_read(handle, (char *)buf, count,
out_result, out_count))
Libc::suspend();
while (out_result == Result::READ_QUEUED) {
out_result = handle->fs().complete_read(handle, (char *)buf, count, out_count);
if (out_result == Result::READ_QUEUED)
Libc::suspend();
}
switch (out_result) {
case Result::READ_ERR_AGAIN: return Errno(EAGAIN);
case Result::READ_ERR_WOULD_BLOCK: return Errno(EWOULDBLOCK);
case Result::READ_ERR_INVALID: return Errno(EINVAL);
case Result::READ_ERR_IO: return Errno(EIO);
case Result::READ_ERR_INTERRUPT: return Errno(EINTR);
case Result::READ_OK: break;
case Result::READ_QUEUED: /* handled above, so never reached */ break;
}
handle->advance_seek(out_count);

View File

@ -209,6 +209,7 @@ class Vfs::Dir_file_system : public File_system
Dir_file_system(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node node,
Io_response_handler &io_handler,
File_system_factory &fs_factory)
:
_first_file_system(0)
@ -228,11 +229,11 @@ class Vfs::Dir_file_system : public File_system
/* traverse into <dir> nodes */
if (sub_node.has_type("dir")) {
_append_file_system(new (alloc)
Dir_file_system(env, alloc, sub_node, fs_factory));
Dir_file_system(env, alloc, sub_node, io_handler, fs_factory));
continue;
}
File_system *fs = fs_factory.create(env, alloc, sub_node);
File_system *fs = fs_factory.create(env, alloc, sub_node, io_handler);
if (fs) {
_append_file_system(fs);
continue;

View File

@ -1,11 +1,13 @@
/*
* \brief Interface for operations provided by file I/O service
* \author Norman Feske
* \author Emery Hemingway
* \author Christian Helmuth
* \date 2011-02-17
*/
/*
* Copyright (C) 2011-2014 Genode Labs GmbH
* Copyright (C) 2011-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.
@ -16,10 +18,17 @@
namespace Vfs {
class Vfs_handle;
struct Io_response_handler;
struct File_io_service;
}
struct Vfs::Io_response_handler
{
virtual void handle_io_response() = 0;
};
struct Vfs::File_io_service
{
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
@ -44,11 +53,29 @@ struct Vfs::File_io_service
enum Read_result { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
READ_ERR_INVALID, READ_ERR_IO,
READ_ERR_INTERRUPT, READ_OK };
READ_ERR_INTERRUPT, READ_QUEUED,
READ_OK };
virtual Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) = 0;
/**
* Read from handle with potential queueing of operation
*
* \return false if queue is full
*/
virtual bool queue_read(Vfs_handle *vfs_handle, char *dst, file_size count,
Read_result &out_result, file_size &out_count)
{
out_result = read(vfs_handle, dst, count, out_count);
return true;
}
virtual Read_result complete_read(Vfs_handle *vfs_handle,
char *dst, file_size count,
file_size &out_count)
{ return read(vfs_handle, dst, count, out_count); }
/***************
** Ftruncate **

View File

@ -39,7 +39,8 @@ struct Vfs::File_system_factory
*/
virtual File_system *create(Genode::Env &env,
Genode::Allocator &alloc,
Xml_node config) = 0;
Xml_node config,
Io_response_handler &io_handler) = 0;
};

View File

@ -21,7 +21,6 @@
#include <base/lock.h>
#include <base/env.h>
#include <base/signal.h>
#include <base/printf.h>
#include <dataspace/client.h>
#include <os/path.h>

View File

@ -149,8 +149,13 @@ struct Cli_monitor::Main
Heap _heap { _env.ram(), _env.rm() };
struct Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response() { }
} io_response_handler;
/* initialize virtual file system */
Vfs::Dir_file_system _root_dir { _env, _heap, _vfs_config(),
Vfs::Dir_file_system _root_dir { _env, _heap, _vfs_config(), io_response_handler,
Vfs::global_file_system_factory() };
Subsystem_config_registry _subsystem_config_registry { _root_dir, _heap };

View File

@ -114,7 +114,8 @@ class Vfs::Block_file_system : public Single_file_system
Block_file_system(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_BLOCK_DEVICE, name(), config),
_alloc(alloc),

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-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.
@ -30,6 +30,9 @@
#include "zero_file_system.h"
using Vfs::Io_response_handler;
class Default_file_system_factory : public Vfs::Global_file_system_factory
{
private:
@ -57,9 +60,10 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
Vfs::File_system *create(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node node) override
Genode::Xml_node node,
Io_response_handler &io_handler) override
{
return new (alloc) FILE_SYSTEM(env, alloc, node);
return new (alloc) FILE_SYSTEM(env, alloc, node, io_handler);
}
};
@ -74,8 +78,9 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
Vfs::File_system *create(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node node) override {
return _fs_factory.create(env, alloc, node); }
Genode::Xml_node node,
Io_response_handler &io_handler) override {
return _fs_factory.create(env, alloc, node, io_handler); }
};
Genode::List<Entry_base> _list;
@ -88,11 +93,12 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
Vfs::File_system *_try_create(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node node)
Genode::Xml_node node,
Io_response_handler &io_handler)
{
for (Entry_base *e = _list.first(); e; e = e->next())
if (e->matches(node))
return e->create(env, alloc, node);
return e->create(env, alloc, node, io_handler);
return 0;
}
@ -151,12 +157,13 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
return *query_fn();
} catch (Genode::Shared_object::Invalid_rom_module) {
PWRN("could not open '%s'", lib_name.string());
Genode::warning("could not open '", lib_name, "'");
throw Factory_not_available();
} catch (Genode::Shared_object::Invalid_symbol) {
PWRN("could not find symbol '%s' in '%s'",
_factory_symbol(), lib_name.string());
Genode::warning("could not find symbol '",
Genode::Cstring(_factory_symbol()),
"' in '", lib_name, "'");
Genode::destroy(alloc, shared_object);
throw Factory_not_available();
@ -181,11 +188,12 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
Vfs::File_system *create(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node node) override
Genode::Xml_node node,
Io_response_handler &io_handler) override
{
try {
/* try if type is handled by the currently registered fs types */
if (Vfs::File_system *fs = _try_create(env, alloc, node))
if (Vfs::File_system *fs = _try_create(env, alloc, node, io_handler))
return fs;
/* if the builtin fails, do not try loading an external */
} catch (...) { return 0; }
@ -194,7 +202,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
/* probe for file system implementation available as shared lib */
if (_probe_external_factory(env, alloc, node)) {
/* try again with the new file system type loaded */
if (Vfs::File_system *fs = _try_create(env, alloc, node))
if (Vfs::File_system *fs = _try_create(env, alloc, node, io_handler))
return fs;
}
} catch (...) { }

View File

@ -153,16 +153,17 @@ class Vfs::Fs_file_system : public File_system
Fs_file_system(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
_env(env),
_fs_packet_alloc(&alloc),
_label(config.attribute_value("label", Label_string())),
_root( config.attribute_value("root", Root_string())),
_fs(_fs_packet_alloc,
::File_system::DEFAULT_TX_BUF_SIZE,
_fs(env, _fs_packet_alloc,
_label.string(), _root.string(),
config.attribute_value("writeable", true))
config.attribute_value("writeable", true),
::File_system::DEFAULT_TX_BUF_SIZE)
{ }

View File

@ -33,7 +33,8 @@ class Vfs::Inline_file_system : public Single_file_system
Inline_file_system(Genode::Env&,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_FILE, name(), config),
_base(config.content_base()),

View File

@ -50,7 +50,8 @@ class Vfs::Log_file_system : public Single_file_system
Log_file_system(Genode::Env &env,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
_label(config.attribute_value("label", Label())),

View File

@ -24,7 +24,8 @@ struct Vfs::Null_file_system : Single_file_system
{
Null_file_system(Genode::Env&,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config)
{ }

View File

@ -422,7 +422,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
Ram_file_system(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node)
Genode::Xml_node,
Io_response_handler &)
: _env(env), _alloc(alloc) { }
~Ram_file_system() { _root.empty(_alloc); }

View File

@ -50,7 +50,8 @@ class Vfs::Rom_file_system : public Single_file_system
Rom_file_system(Genode::Env &env,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_FILE, name(), config),
_label(config),

View File

@ -32,7 +32,8 @@ class Vfs::Rtc_file_system : public Single_file_system
Rtc_file_system(Genode::Env &env,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
_rtc(env)

View File

@ -33,7 +33,8 @@ class Vfs::Symlink_file_system : public Single_file_system
Symlink_file_system(Genode::Env&,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler&)
:
Single_file_system(NODE_TYPE_SYMLINK, "symlink", config),
_target(config.attribute_value("target", Target()))

View File

@ -344,7 +344,8 @@ class Vfs::Tar_file_system : public File_system
Tar_file_system(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
_env(env), _alloc(alloc),
_rom_name(config.attribute_value("name", Rom_name())),

View File

@ -2,11 +2,12 @@
* \brief Terminal file system
* \author Christian Prochaska
* \author Norman Feske
* \author Christian Helmuth
* \date 2012-05-23
*/
/*
* Copyright (C) 2012-2016 Genode Labs GmbH
* Copyright (C) 2012-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.
@ -17,6 +18,8 @@
#include <terminal_session/connection.h>
#include <vfs/single_file_system.h>
#include <base/signal.h>
namespace Vfs { class Terminal_file_system; }
@ -28,33 +31,40 @@ class Vfs::Terminal_file_system : public Single_file_system
typedef Genode::String<64> Label;
Label _label;
Terminal::Connection _terminal;
Genode::Env &_env;
Io_response_handler &_io_handler;
Terminal::Connection _terminal { _env, _label.string() };
Genode::Signal_handler<Terminal_file_system> _read_avail_handler {
_env.ep(), *this, &Terminal_file_system::_handle_read_avail };
void _handle_read_avail() { _io_handler.handle_io_response(); }
Read_result _read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count)
{
if (_terminal.avail()) {
out_count = _terminal.read(dst, count);
return READ_OK;
} else {
return READ_QUEUED;
}
}
public:
Terminal_file_system(Genode::Env &env,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &io_handler)
:
Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
_label(config.attribute_value("label", Label())),
_terminal(env, _label.string())
_env(env), _io_handler(io_handler)
{
/*
* Wait for connection-established signal
*/
/* create signal receiver, just for the single signal */
Genode::Signal_context sig_ctx;
Genode::Signal_receiver sig_rec;
Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
/* register signal handler */
_terminal.connected_sigh(sig_cap);
/* wati for signal */
sig_rec.wait_for_signal();
sig_rec.dissolve(&sig_ctx);
/* register for read-avail notification */
_terminal.read_avail_sigh(_read_avail_handler);
}
static const char *name() { return "terminal"; }
@ -78,6 +88,19 @@ class Vfs::Terminal_file_system : public Single_file_system
return READ_OK;
}
bool queue_read(Vfs_handle *vfs_handle, char *dst, file_size count,
Read_result &out_result, file_size &out_count) override
{
out_result = _read(vfs_handle, dst, count, out_count);
return true;
}
Read_result complete_read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
return _read(vfs_handle, dst, count, out_count);
}
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size) override
{
return FTRUNCATE_OK;

View File

@ -24,7 +24,8 @@ struct Vfs::Zero_file_system : Single_file_system
{
Zero_file_system(Genode::Env&,
Genode::Allocator&,
Genode::Xml_node config)
Genode::Xml_node config,
Io_response_handler &)
:
Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config)
{ }

View File

@ -35,6 +35,7 @@ namespace Vfs_server {
class Session_component;
class Root;
class Io_response_handler;
};
@ -464,6 +465,15 @@ class Vfs_server::Session_component :
};
struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response() override
{
Genode::log(__func__, " called");
}
};
class Vfs_server::Root :
public Genode::Root_component<Session_component>
{
@ -484,8 +494,11 @@ class Vfs_server::Root :
}
}
Vfs::Dir_file_system _vfs
{ _env, _heap, vfs_config(), Vfs::global_file_system_factory() };
Io_response_handler _io_response_handler;
Vfs::Dir_file_system _vfs {
_env, _heap, vfs_config(), _io_response_handler,
Vfs::global_file_system_factory() };
protected:

View File

@ -108,6 +108,8 @@ inline void assert_read(Vfs::File_io_service::Read_result r)
typedef Vfs::File_io_service::Read_result Result;
switch (r) {
case Result::READ_OK: return;
case Result::READ_QUEUED:
error("READ_QUEUED"); break;
case Result::READ_ERR_AGAIN:
error("READ_ERR_AGAIN"); break;
case Result::READ_ERR_WOULD_BLOCK:
@ -470,7 +472,13 @@ void Component::construct(Genode::Env &env)
Attached_rom_dataspace config_rom(env, "config");
Xml_node const config_xml = config_rom.xml();
struct Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response() override { Genode::log(__func__, " called"); }
} io_response_handler;
Vfs::Dir_file_system vfs_root(env, heap, config_xml.sub_node("vfs"),
io_response_handler,
Vfs::global_file_system_factory());
char path[Vfs::MAX_PATH_LEN];

View File

@ -68,7 +68,7 @@ class Noux::Child_env
try {
binary_addr = local_rm.attach(binary_ds);
} catch(...) {
PWRN("could not attach dataspace");
warning("could not attach dataspace");
interpretable = false;
}

View File

@ -212,7 +212,13 @@ struct Noux::Main
/* initialize virtual file system */
Vfs::Global_file_system_factory &_fs_factory = Vfs::global_file_system_factory();
struct Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response() override { Genode::log(__func__, " called"); }
} _io_response_handler;
Vfs::Dir_file_system _root_dir { _env, _heap, _config.xml().sub_node("fstab"),
_io_response_handler,
_fs_factory };
Pid_allocator _pid_allocator;

View File

@ -122,7 +122,7 @@ struct Noux::Vfs_io_channel : Io_channel
default:
PWRN("invalid fcntl command %d", sysio.fcntl_in.cmd);
warning("invalid fcntl command ", (int)sysio.fcntl_in.cmd);
sysio.error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID;
return false;
};