mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
Introduce notifications to file-system interface
This patch extends the file-system interface with the ability to monitor changes of files or directories. The new 'File_system::sigh' function can be used to install a signal handler for an open node. The 'ram_fs' server has been enhanced to support the new interface. So any file or directory changes can now be observed by 'ram_fs' clients. Fixes #607
This commit is contained in:
parent
7318c5d7d4
commit
fca8994584
@ -846,7 +846,11 @@ namespace File_system {
|
||||
PERR("f_rename() returned an unexpected error code");
|
||||
throw Lookup_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void sigh(Node_handle, Genode::Signal_context_capability)
|
||||
{
|
||||
PWRN("File_system::Session::sigh not supported");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -100,6 +100,10 @@ namespace File_system {
|
||||
call<Rpc_move>(from_dir, from_name, to_dir, to_name);
|
||||
}
|
||||
|
||||
void sigh(Node_handle node, Signal_context_capability sigh)
|
||||
{
|
||||
call<Rpc_sigh>(node, sigh);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace File_system {
|
||||
:
|
||||
Genode::Connection<Session>(
|
||||
session("ram_quota=%zd, tx_buf_size=%zd, label=\"%s\"",
|
||||
3*4096 + tx_buf_size, tx_buf_size, label)),
|
||||
4*4096 + tx_buf_size, tx_buf_size, label)),
|
||||
Session_client(cap(), tx_block_alloc) { }
|
||||
};
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ namespace File_system {
|
||||
|
||||
Node_handle() : value(-1) { }
|
||||
Node_handle(int v) : value(v) { }
|
||||
|
||||
bool valid() const { return value != -1; }
|
||||
};
|
||||
|
||||
|
||||
@ -273,6 +275,11 @@ namespace File_system {
|
||||
virtual void move(Dir_handle, Name const &from,
|
||||
Dir_handle, Name const &to) = 0;
|
||||
|
||||
/**
|
||||
* Register handler that should be notified on node changes
|
||||
*/
|
||||
virtual void sigh(Node_handle, Signal_context_capability sigh) = 0;
|
||||
|
||||
|
||||
/*******************
|
||||
** RPC interface **
|
||||
@ -307,6 +314,9 @@ namespace File_system {
|
||||
GENODE_RPC_THROW(Rpc_move, void, move,
|
||||
GENODE_TYPE_LIST(Permission_denied, Invalid_name, Lookup_failed),
|
||||
Dir_handle, Name const &, Dir_handle, Name const &);
|
||||
GENODE_RPC_THROW(Rpc_sigh, void, sigh,
|
||||
GENODE_TYPE_LIST(Invalid_handle),
|
||||
Node_handle, Signal_context_capability);
|
||||
|
||||
/*
|
||||
* Manual type-list definition, needed because the RPC interface
|
||||
@ -324,8 +334,9 @@ namespace File_system {
|
||||
Meta::Type_tuple<Rpc_unlink,
|
||||
Meta::Type_tuple<Rpc_truncate,
|
||||
Meta::Type_tuple<Rpc_move,
|
||||
Meta::Type_tuple<Rpc_sigh,
|
||||
Meta::Empty>
|
||||
> > > > > > > > > > Rpc_functions;
|
||||
> > > > > > > > > > > Rpc_functions;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,16 @@ namespace File_system {
|
||||
*/
|
||||
_entries.insert(node);
|
||||
_num_entries++;
|
||||
|
||||
mark_as_updated();
|
||||
}
|
||||
|
||||
void discard_unsynchronized(Node *node)
|
||||
{
|
||||
_entries.remove(node);
|
||||
_num_entries--;
|
||||
|
||||
mark_as_updated();
|
||||
}
|
||||
|
||||
Node *lookup_and_lock(char const *path, bool return_parent = false)
|
||||
|
@ -84,6 +84,8 @@ namespace File_system {
|
||||
* by zero chunks, which do not contribute to 'used_size()'.
|
||||
*/
|
||||
_length = max(_length, seek_offset + len);
|
||||
|
||||
mark_as_updated();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -95,6 +97,8 @@ namespace File_system {
|
||||
_chunk.truncate(size);
|
||||
|
||||
_length = size;
|
||||
|
||||
mark_as_updated();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -387,7 +387,27 @@ namespace File_system {
|
||||
|
||||
from_dir->discard_unsynchronized(node);
|
||||
to_dir->adopt_unsynchronized(node);
|
||||
|
||||
/*
|
||||
* If the file was moved from one directory to another we
|
||||
* need to inform the new directory 'to_dir'. The original
|
||||
* directory 'from_dir' will always get notified (i.e.,
|
||||
* when just the file name was changed) below.
|
||||
*/
|
||||
to_dir->mark_as_updated();
|
||||
to_dir->notify_listeners();
|
||||
}
|
||||
|
||||
from_dir->mark_as_updated();
|
||||
from_dir->notify_listeners();
|
||||
|
||||
node->mark_as_updated();
|
||||
node->notify_listeners();
|
||||
}
|
||||
|
||||
void sigh(Node_handle node_handle, Signal_context_capability sigh)
|
||||
{
|
||||
_handle_registry.sigh(node_handle, sigh);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,9 +10,46 @@
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
#include <base/lock.h>
|
||||
#include <base/signal.h>
|
||||
|
||||
namespace File_system {
|
||||
|
||||
class Listener : public List<Listener>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
Lock _lock;
|
||||
Signal_context_capability _sigh;
|
||||
bool _marked_as_updated;
|
||||
|
||||
public:
|
||||
|
||||
Listener() : _marked_as_updated(false) { }
|
||||
|
||||
Listener(Signal_context_capability sigh)
|
||||
: _sigh(sigh), _marked_as_updated(false) { }
|
||||
|
||||
void notify()
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (_marked_as_updated && _sigh.valid())
|
||||
Signal_transmitter(_sigh).submit();
|
||||
|
||||
_marked_as_updated = false;
|
||||
}
|
||||
|
||||
void mark_as_updated()
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
_marked_as_updated = true;
|
||||
}
|
||||
|
||||
bool valid() const { return _sigh.valid(); }
|
||||
};
|
||||
|
||||
|
||||
class Node : public List<Node>::Element
|
||||
{
|
||||
public:
|
||||
@ -25,6 +62,8 @@ namespace File_system {
|
||||
int _ref_count;
|
||||
Name _name;
|
||||
unsigned long const _inode;
|
||||
List<Listener> _listeners;
|
||||
bool _modified;
|
||||
|
||||
/**
|
||||
* Generate unique inode number
|
||||
@ -37,9 +76,19 @@ namespace File_system {
|
||||
|
||||
public:
|
||||
|
||||
Node() : _ref_count(0), _inode(_unique_inode()) { _name[0] = 0; }
|
||||
Node()
|
||||
: _ref_count(0), _inode(_unique_inode()), _modified(false)
|
||||
{ _name[0] = 0; }
|
||||
|
||||
virtual ~Node() { }
|
||||
virtual ~Node()
|
||||
{
|
||||
/* propagate event to listeners */
|
||||
mark_as_updated();
|
||||
notify_listeners();
|
||||
|
||||
while (_listeners.first())
|
||||
_listeners.remove(_listeners.first());
|
||||
}
|
||||
|
||||
unsigned long inode() const { return _inode; }
|
||||
char const *name() const { return _name; }
|
||||
@ -55,6 +104,27 @@ namespace File_system {
|
||||
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
|
||||
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
|
||||
|
||||
void add_listener(Listener *listener)
|
||||
{
|
||||
_listeners.insert(listener);
|
||||
}
|
||||
|
||||
void remove_listener(Listener *listener)
|
||||
{
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
void notify_listeners()
|
||||
{
|
||||
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
|
||||
curr->notify();
|
||||
}
|
||||
|
||||
void mark_as_updated()
|
||||
{
|
||||
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
|
||||
curr->mark_as_updated();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -45,6 +45,12 @@ namespace File_system {
|
||||
|
||||
Node *_nodes[MAX_NODE_HANDLES];
|
||||
|
||||
/**
|
||||
* Each open node handle can act as a listener to be informed about
|
||||
* node changes.
|
||||
*/
|
||||
Listener _listeners[MAX_NODE_HANDLES];
|
||||
|
||||
/**
|
||||
* Allocate node handle
|
||||
*
|
||||
@ -90,8 +96,30 @@ namespace File_system {
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (_in_range(handle.value))
|
||||
_nodes[handle.value] = 0;
|
||||
if (!_in_range(handle.value))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Notify listeners about the changed file.
|
||||
*/
|
||||
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
|
||||
if (!node) { return; }
|
||||
|
||||
node->lock();
|
||||
node->notify_listeners();
|
||||
|
||||
/*
|
||||
* De-allocate handle
|
||||
*/
|
||||
Listener &listener = _listeners[handle.value];
|
||||
|
||||
if (listener.valid())
|
||||
node->remove_listener(&listener);
|
||||
|
||||
_nodes[handle.value] = 0;
|
||||
listener = Listener();
|
||||
|
||||
node->unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,11 +150,48 @@ namespace File_system {
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (!_in_range(h1.value) || !_in_range(h2.value))
|
||||
if (!_in_range(h1.value) || !_in_range(h2.value)) {
|
||||
PDBG("refer_to_same_node -> Invalid_handle");
|
||||
throw Invalid_handle();
|
||||
}
|
||||
|
||||
return _nodes[h1.value] == _nodes[h2.value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register signal handler to be notified of node changes
|
||||
*/
|
||||
void sigh(Node_handle handle, Signal_context_capability sigh)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (!_in_range(handle.value))
|
||||
throw Invalid_handle();
|
||||
|
||||
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
|
||||
if (!node) {
|
||||
PDBG("Invalid_handle");
|
||||
throw Invalid_handle();
|
||||
}
|
||||
|
||||
node->lock();
|
||||
Node_lock_guard node_lock_guard(*node);
|
||||
|
||||
Listener &listener = _listeners[handle.value];
|
||||
|
||||
/*
|
||||
* If there was already a handler registered for the node,
|
||||
* remove the old handler.
|
||||
*/
|
||||
if (listener.valid())
|
||||
node->remove_listener(&listener);
|
||||
|
||||
/*
|
||||
* Register new handler
|
||||
*/
|
||||
listener = Listener(sigh);
|
||||
node->add_listener(&listener);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -419,6 +419,11 @@ namespace File_system {
|
||||
|
||||
throw Permission_denied();
|
||||
}
|
||||
|
||||
void sigh(Node_handle, Genode::Signal_context_capability)
|
||||
{
|
||||
PWRN("File_system::Session::sigh not supported");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user