diff --git a/repos/os/src/server/trace_fs/README b/repos/os/src/server/trace_fs/README deleted file mode 100644 index f5dcd307a..000000000 --- a/repos/os/src/server/trace_fs/README +++ /dev/null @@ -1,61 +0,0 @@ -The new _trace_fs_ server provides access to a trace session by providing a -file-system session as front end. Combined with Noux, it allows for the -interactive exploration and tracing of Genode's process tree using -traditional Unix tools. - -Each trace subject is represented by a directory ('thread_name.subject') that -contains specific files, which are used to control the tracing process of the -thread as well as storing the content of its trace buffer: - -:'enable': The tracing of a thread is activated if there is a valid policy - installed and the intend to trace the subject was made clear by writing '1' - to the 'enable' file. The tracing of a thread may be deactivated by writing a - '0' to this file. - -:'policy': A policy may be changed by overwriting the currently used one in the - 'policy' file. In this case, the old policy is replaced by the new one and - automatically used by the framework. - -:'buffer_size': Writing a value to the 'buffer_size' file changes the size of - the trace buffer. This value is evaluated only when reactivating the tracing - of the thread. - -:'events': The trace-buffer contents may be accessed by reading from the - 'events' file. New trace events are appended to this file. - -:'active': Reading the file will return whether the tracing is active (1) or - not (0). - -:'cleanup': Nodes of untraced subjects are kept as long as they do not change - their tracing state to dead. Dead untraced nodes are automatically removed - from the file system. Subjects that were traced before and are now untraced - can be removed by writing '1' to the 'cleanup' file. - -To use the trace_fs, a configuration similar to the following may be used: - -! -! -! -! -! -! -! - -:'interval': sets the period the Trace_session is polled. The - time is given in milliseconds. - -:'subject_limit': specifies how many trace subjects should by acquired at - max when the Trace_session is polled. - -:'trace_quota': is the amount of quota the trace_fs should use for the - Trace_session connection. The remaining amount of RAM quota will be used - for the actual nodes of the file system and the 'policy' as well as the - 'events' files. - -In addition, there are 'buffer_size' and 'buffer_size_limit' that define -the initial and the upper limit of the size of a trace buffer. - -A ready-to-use run script can by found in 'ports/run/noux_trace_fs.run'. diff --git a/repos/os/src/server/trace_fs/buffer.h b/repos/os/src/server/trace_fs/buffer.h deleted file mode 100644 index 595df39e6..000000000 --- a/repos/os/src/server/trace_fs/buffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * \brief Buffer class - * \author Josef Soentgen - * \date 2014-01-15 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _BUFFER_H_ -#define _BUFFER_H_ - -/* Genode includes */ -#include - -namespace Util { - - typedef Genode::size_t size_t; - - - /** - * Buffer merely wrapps a simple char array - */ - template - class Buffer - { - public: - - class Out_of_range { }; - - private: - - char _buf[CAPACITY]; - size_t _length; - - public: - - static size_t capacity() { return CAPACITY; } - - Buffer() : _length(0) { } - - Buffer(char const *s) - : - _length(Genode::min(Genode::strlen(s) + 1, CAPACITY)) - { - Genode::strncpy(_buf, s, _length); - } - - char const *data() const { return (_buf[_length -1 ] == '\0') ? _buf : ""; } - - char *data() { return _buf; } - - size_t length() const { return _length; } - - char & operator[](size_t i) - { - if (i >= CAPACITY) - throw Out_of_range(); - - return _buf[i]; - } - - void replace(char p, char c) - { - char *s = _buf; - for (; *s; s++) { - if (*s == p) - *s = c; - } - } - }; - - /** - * This class walks along a label and returns the next element on request - */ - class Label_walker - { - private: - - Buffer<64> _buffer; - char const *_label; - - char const *_next() - { - size_t i = 0; - - for (; *_label && (i < _buffer.capacity()); _label++, i++) { - /* check seperator */ - if ((*_label == ' ') && - (*(_label + 1) == '-') && - (*(_label + 2) == '>') && - (*(_label + 3) == ' ')) - break; - _buffer[i] = *_label; - } - - _buffer[i] = '\0'; - - /* sanatize the element */ - _buffer.replace('/', '_'); - - /* omit seperator */ - if (*_label) - _label += 4; - - return _label; - } - - - public: - - Label_walker(char const *label) : _label(label) { } - - /** - * Walk to the next element of the label - * - * \return pointer to the remaing part of the label - */ - char const *next() { return _next(); } - - /** - * Get current element of the label - * - * \return pointer to current element - */ - char const *element() { return _buffer.data(); } - }; -} - -#endif /* _BUFFER_H_ */ diff --git a/repos/os/src/server/trace_fs/chunk.h b/repos/os/src/server/trace_fs/chunk.h deleted file mode 100644 index 79fcfaa55..000000000 --- a/repos/os/src/server/trace_fs/chunk.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * \brief Data structure for storing sparse files in RAM - * \author Norman Feske - * \date 2012-04-18 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _CHUNK_H_ -#define _CHUNK_H_ - -/* Genode includes */ -#include -#include -#include -#include - -namespace File_system { - - using namespace Genode; - - - /** - * Common base class of both 'Chunk' and 'Chunk_index' - */ - class Chunk_base : Noncopyable - { - public: - - class Index_out_of_range { }; - - protected: - - seek_off_t const _base_offset; - size_t _num_entries; /* corresponds to last used entry */ - - /** - * Test if specified range lies within the chunk - */ - void assert_valid_range(seek_off_t start, size_t len, - file_size_t chunk_size) const - { - if (zero()) return; - - if (start < _base_offset) - throw Index_out_of_range(); - - if (start + len > _base_offset + chunk_size) - throw Index_out_of_range(); - } - - Chunk_base(seek_off_t base_offset) - : _base_offset(base_offset), _num_entries(0) { } - - /** - * Construct zero chunk - * - * A zero chunk is a chunk that cannot be written to. When reading - * from it, it returns zeros. Because there is a single zero chunk - * for each chunk type, the base offset is meaningless. We use a - * base offset of ~0 as marker to identify zero chunks. - */ - Chunk_base() : _base_offset(~0L), _num_entries(0) { } - - public: - - /** - * Return absolute base offset of chunk in bytes - */ - seek_off_t base_offset() const { return _base_offset; } - - /** - * Return true if chunk is a read-only zero chunk - */ - bool zero() const { return _base_offset == (seek_off_t)(~0L); } - - /** - * Return true if chunk has no allocated sub chunks - */ - bool empty() const { return _num_entries == 0; } - }; - - - /** - * Chunk of bytes used as leaf in hierarchy of chunk indices - */ - template - class Chunk : public Chunk_base - { - private: - - char _data[CHUNK_SIZE]; - - public: - - enum { SIZE = CHUNK_SIZE }; - - /** - * Construct byte chunk - * - * \param base_offset absolute offset of chunk in bytes - * - * The first argument is unused. Its mere purpose is to make the - * signature of the constructor compatible to the constructor - * of 'Chunk_index'. - */ - Chunk(Allocator &, seek_off_t base_offset) - : - Chunk_base(base_offset) - { - memset(_data, 0, CHUNK_SIZE); - } - - /** - * Construct zero chunk - */ - Chunk() { } - - /** - * Return number of used entries - * - * The returned value corresponds to the index of the last used - * entry + 1. It does not correlate to the number of actually - * allocated entries (there may be ranges of zero blocks). - */ - file_size_t used_size() const { return _num_entries; } - - void write(char const *src, size_t len, seek_off_t seek_offset) - { - assert_valid_range(seek_offset, len, SIZE); - - /* offset relative to this chunk */ - seek_off_t const local_offset = seek_offset - base_offset(); - - memcpy(&_data[local_offset], src, len); - - _num_entries = max(_num_entries, local_offset + len); - } - - void read(char *dst, size_t len, seek_off_t seek_offset) const - { - assert_valid_range(seek_offset, len, SIZE); - - memcpy(dst, &_data[seek_offset - base_offset()], len); - } - - void truncate(file_size_t size) - { - assert_valid_range(size, 0, SIZE); - - /* - * Offset of the first free position (relative to the beginning - * this chunk). - */ - seek_off_t const local_offset = size - base_offset(); - - if (local_offset >= _num_entries) - return; - - memset(&_data[local_offset], 0, _num_entries - local_offset); - - _num_entries = local_offset; - } - }; - - - template - class Chunk_index : public Chunk_base - { - public: - - typedef ENTRY_TYPE Entry; - - enum { ENTRY_SIZE = ENTRY_TYPE::SIZE, - SIZE = ENTRY_SIZE*NUM_ENTRIES }; - - private: - - Allocator &_alloc; - - Entry * _entries[NUM_ENTRIES]; - - /** - * Return instance of a zero sub chunk - */ - static Entry const &_zero_chunk() - { - static Entry zero_chunk; - return zero_chunk; - } - - /** - * Return sub chunk at given index - * - * If there is no sub chunk at the specified index, this function - * transparently allocates one. Hence, the returned sub chunk - * is ready to be written to. - */ - Entry &_entry_for_writing(unsigned index) - { - if (index >= NUM_ENTRIES) - throw Index_out_of_range(); - - if (_entries[index]) - return *_entries[index]; - - seek_off_t entry_offset = base_offset() + index*ENTRY_SIZE; - - _entries[index] = new (&_alloc) Entry(_alloc, entry_offset); - - _num_entries = max(_num_entries, index + 1); - - return *_entries[index]; - } - - /** - * Return sub chunk at given index (for reading only) - * - * This function transparently provides a zero sub chunk for any - * index that is not populated by a real chunk. - */ - Entry const &_entry_for_reading(unsigned index) const - { - if (index >= NUM_ENTRIES) - throw Index_out_of_range(); - - if (_entries[index]) - return *_entries[index]; - - return _zero_chunk(); - } - - /** - * Return index of entry located at specified byte offset - * - * The caller of this function must make sure that the offset - * parameter is within the bounds of the chunk. - */ - unsigned _index_by_offset(seek_off_t offset) const - { - return (offset - base_offset()) / ENTRY_SIZE; - } - - /** - * Apply operation 'func' to a range of entries - */ - template - static void _range_op(THIS &obj, DATA *data, size_t len, - seek_off_t seek_offset, FUNC const &func) - { - /* - * Depending on whether this function is called for reading - * (const function) or writing (non-const function), the - * operand type is const or non-const Entry. The correct type - * is embedded as a trait in the 'FUNC' functor type. - */ - typedef typename FUNC::Entry Const_qualified_entry; - - obj.assert_valid_range(seek_offset, len, SIZE); - - while (len > 0) { - - unsigned const index = obj._index_by_offset(seek_offset); - - Const_qualified_entry &entry = FUNC::lookup(obj, index); - - /* - * Calculate byte offset relative to the chunk - * - * We cannot use 'entry.base_offset()' for this calculation - * because in the const case, the lookup might return a - * zero chunk, which has no defined base offset. Therefore, - * we calculate the base offset via index*ENTRY_SIZE. - */ - seek_off_t const local_seek_offset = - seek_offset - obj.base_offset() - index*ENTRY_SIZE; - - /* available capacity at 'entry' starting at seek offset */ - seek_off_t const capacity = ENTRY_SIZE - local_seek_offset; - seek_off_t const curr_len = min(len, capacity); - - /* apply functor (read or write) to entry */ - func(entry, data, curr_len, seek_offset); - - /* advance to next entry */ - len -= curr_len; - data += curr_len; - seek_offset += curr_len; - } - } - - struct Write_func - { - typedef ENTRY_TYPE Entry; - - static Entry &lookup(Chunk_index &chunk, unsigned i) { - return chunk._entry_for_writing(i); } - - void operator () (Entry &entry, char const *src, size_t len, - seek_off_t seek_offset) const - { - entry.write(src, len, seek_offset); - } - }; - - struct Read_func - { - typedef ENTRY_TYPE const Entry; - - static Entry &lookup(Chunk_index const &chunk, unsigned i) { - return chunk._entry_for_reading(i); } - - void operator () (Entry &entry, char *dst, size_t len, - seek_off_t seek_offset) const - { - if (entry.zero()) - memset(dst, 0, len); - else - entry.read(dst, len, seek_offset); - } - }; - - void _init_entries() - { - for (unsigned i = 0; i < NUM_ENTRIES; i++) - _entries[i] = 0; - } - - void _destroy_entry(unsigned i) - { - if (_entries[i] && (i < _num_entries)) { - destroy(&_alloc, _entries[i]); - _entries[i] = 0; - } - } - - public: - - /** - * Constructor - * - * \param alloc allocator to use for allocating sub-chunk - * indices and chunks - * \param base_offset absolute offset of the chunk in bytes - */ - Chunk_index(Allocator &alloc, seek_off_t base_offset) - : Chunk_base(base_offset), _alloc(alloc) { _init_entries(); } - - /** - * Construct zero chunk - */ - Chunk_index() : _alloc(*(Allocator *)0) { } - - /** - * Destructor - */ - ~Chunk_index() - { - for (unsigned i = 0; i < NUM_ENTRIES; i++) - _destroy_entry(i); - } - - /** - * Return size of chunk in bytes - * - * The returned value corresponds to the position after the highest - * offset that was written to. - */ - file_size_t used_size() const - { - if (_num_entries == 0) - return 0; - - /* size of entries that lie completely within the used range */ - file_size_t const size_whole_entries = ENTRY_SIZE*(_num_entries - 1); - - Entry *last_entry = _entries[_num_entries - 1]; - if (!last_entry) - return size_whole_entries; - - return size_whole_entries + last_entry->used_size(); - } - - /** - * Write data to chunk - */ - void write(char const *src, size_t len, seek_off_t seek_offset) - { - _range_op(*this, src, len, seek_offset, Write_func()); - } - - /** - * Read data from chunk - */ - void read(char *dst, size_t len, seek_off_t seek_offset) const - { - _range_op(*this, dst, len, seek_offset, Read_func()); - } - - /** - * Truncate chunk to specified size in bytes - * - * This function can be used to shrink a chunk only. Specifying a - * 'size' larger than 'used_size' has no effect. The value returned - * by 'used_size' refers always to the position of the last byte - * written to the chunk. - */ - void truncate(file_size_t size) - { - unsigned const trunc_index = _index_by_offset(size); - - if (trunc_index >= _num_entries) - return; - - for (unsigned i = trunc_index + 1; i < _num_entries; i++) - _destroy_entry(i); - - /* traverse into sub chunks */ - if (_entries[trunc_index]) - _entries[trunc_index]->truncate(size); - - _num_entries = trunc_index + 1; - - /* - * If the truncated at a chunk boundary, we can release the - * empty trailing chunk at 'trunc_index'. - */ - if (_entries[trunc_index] && _entries[trunc_index]->empty()) { - _destroy_entry(trunc_index); - _num_entries--; - } - } - }; -}; - -#endif /* _CHUNK_H_ */ diff --git a/repos/os/src/server/trace_fs/directory.h b/repos/os/src/server/trace_fs/directory.h deleted file mode 100644 index dfcda613a..000000000 --- a/repos/os/src/server/trace_fs/directory.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * \brief File-system directory node - * \author Norman Feske - * \date 2012-04-11 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _DIRECTORY_H_ -#define _DIRECTORY_H_ - -/* Genode includes */ -#include - -/* local includes */ -#include -#include -#include - -namespace Trace_fs { - class Directory; -} - -class Trace_fs::Directory : public Node -{ - private: - - List _entries; - size_t _num_entries; - - public: - - Directory(char const *name) : _num_entries(0) { Node::name(name); } - - - /** - * Check if the directory has the specified subnode - * - * \param name name of the searched subnode - * - * \return true if the subnode was found, either false - */ - bool has_sub_node_unsynchronized(char const *name) const - { - Node const *sub_node = _entries.first(); - for (; sub_node; sub_node = sub_node->next()) - if (strcmp(sub_node->name(), name) == 0) - return true; - - return false; - } - - - /** - * Add node to the list of subnodes - * - * \param pointer to node - */ - void adopt_unsynchronized(Node *node) - { - /* - * XXX inc ref counter - */ - _entries.insert(node); - _num_entries++; - - mark_as_updated(); - } - - /** - * Remove the node from the list of subnodes - * - * \param node pointer to node - */ - void discard_unsynchronized(Node *node) - { - _entries.remove(node); - _num_entries--; - - mark_as_updated(); - } - - /** - * Lookup node which belongs to the specified path - * - * \param path path to lookup - * \param return_parent if true return parent node, otherwise - * actual path node - * - * \return node node founc - * \throws Lookup_failed - */ - Node *lookup(char const *path, bool return_parent = false) override - { - if (strcmp(path, "") == 0) { - return this; - } - - if (!path || path[0] == '/') - throw Lookup_failed(); - - /* find first path delimiter */ - unsigned i = 0; - for (; path[i] && path[i] != '/'; i++); - - /* - * If no path delimiter was found, we are the parent of the - * specified path. - */ - if (path[i] == 0 && return_parent) { - return this; - } - - /* - * The offset 'i' corresponds to the end of the first path - * element, which can be either the end of the string or the - * first '/' character. - */ - - /* try to find entry that matches the first path element */ - Node *sub_node = _entries.first(); - for (; sub_node; sub_node = sub_node->next()) - if ((strlen(sub_node->name()) == i) && - (strcmp(sub_node->name(), path, i) == 0)) - break; - - if (!sub_node) - throw Lookup_failed(); - - if (!contains_path_delimiter(path)) { - - /* - * Because 'path' is a basename that corresponds to an - * existing sub_node, we have found what we were looking - * for. - */ - return sub_node; - } - - /* - * As 'path' contains one or more path delimiters, traverse - * into the sub directory names after the first path element. - */ - - /* - * We cannot traverse into anything other than a directory. - * - * XXX we might follow symlinks here - */ - Directory *sub_dir = dynamic_cast(sub_node); - if (!sub_dir) - throw Lookup_failed(); - - return sub_dir->lookup(path + i + 1, return_parent); - } - - /** - * Return number of subnodes - */ - size_t num_entries() const { return _num_entries; } - - - /******************** - ** Node interface ** - ********************/ - - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - if (len < sizeof(Directory_entry)) { - Genode::error("read buffer too small for directory entry"); - return 0; - } - - seek_off_t index = seek_offset / sizeof(Directory_entry); - - if (seek_offset % sizeof(Directory_entry)) { - Genode::error("seek offset not alighed to sizeof(Directory_entry)"); - return 0; - } - - /* find list element */ - Node *node = _entries.first(); - for (unsigned i = 0; i < index && node; node = node->next(), i++); - - /* index out of range */ - if (!node) - return 0; - - Directory_entry *e = (Directory_entry *)(dst); - - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_FILE; - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_DIRECTORY; - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_SYMLINK; - - strncpy(e->name, node->name(), sizeof(e->name)); - - return sizeof(Directory_entry); - } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - /* writing to directory nodes is not supported */ - return 0; - } - - Status status() const - { - Status s; - s.inode = inode(); - s.size = _num_entries * sizeof (Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - - return s; - } -}; - -#endif /* _DIRECTORY_H_ */ diff --git a/repos/os/src/server/trace_fs/file.h b/repos/os/src/server/trace_fs/file.h deleted file mode 100644 index 07a3fba21..000000000 --- a/repos/os/src/server/trace_fs/file.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * \brief File node - * \author Norman Feske - * \author Josef Soentgen - * \date 2012-04-11 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _FILE_H_ -#define _FILE_H_ - -/* Genode includes */ -#include -#include - -/* local includes */ -#include -#include - -namespace Trace_fs { - class Changeable_content; - class File; - class Buffered_file; -} - -/** - * - * - */ -class Trace_fs::Changeable_content -{ - protected: - - /** - * This member is used to communicate the state and - * must be set true by classes using this class in case - * the content has changed. - */ - bool _changed; - - /** - * This method is called when the content change is - * acknowledged. It may be overriden by any class using - * this particular class. - */ - virtual void _refresh_content() { } - - public: - - Changeable_content() : _changed(false) { } - - /** - * Check if the content was changed - * - * This evaluation has to be made by classes using this - * particular class. - * - * \return true if changed, otherwise false - */ - bool changed() const { return _changed; } - - - /** - * Acknowledge the content has changed - */ - void acknowledge_change() - { - _changed = false; - - _refresh_content(); - } -}; - - -/** - * File interface - */ - -class Trace_fs::File : public Node -{ - public: - - File(char const *name) - { - Node::name(name); - } - - virtual ~File() { } - - /******************** - ** Node interface ** - ********************/ - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) = 0; - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) = 0; - - virtual Status status() const = 0; - - /******************** - ** File interface ** - ********************/ - - virtual file_size_t length() const = 0; - - virtual void truncate(file_size_t size) = 0; -}; - -/** - * Memory buffered file - * - * This file merely exists in memory and grows automatically. - */ - -class Trace_fs::Buffered_file : public File -{ - private: - - typedef Chunk<4096> Chunk_level_3; - typedef Chunk_index<128, Chunk_level_3> Chunk_level_2; - typedef Chunk_index<64, Chunk_level_2> Chunk_level_1; - typedef Chunk_index<64, Chunk_level_1> Chunk_level_0; - - Chunk_level_0 _chunk; - - file_size_t _length; - - public: - - Buffered_file(Allocator &alloc, char const *name) - : File(name), _chunk(alloc, 0), _length(0) { } - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - file_size_t const chunk_used_size = _chunk.used_size(); - - if (seek_offset >= _length) - return 0; - - /* - * Constrain read transaction to available chunk data - * - * Note that 'chunk_used_size' may be lower than '_length' - * because 'Chunk' may have truncated tailing zeros. - */ - if (seek_offset + len >= _length) - len = _length - seek_offset; - - file_size_t read_len = len; - - if (seek_offset + read_len > chunk_used_size) { - if (chunk_used_size >= seek_offset) - read_len = chunk_used_size - seek_offset; - else - read_len = 0; - } - - _chunk.read(dst, read_len, seek_offset); - - /* add zero padding if needed */ - if (read_len < len) - memset(dst + read_len, 0, len - read_len); - - return len; - } - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - if (seek_offset == (seek_off_t)(~0)) - seek_offset = _chunk.used_size(); - - if (seek_offset + len >= Chunk_level_0::SIZE) { - len = (Chunk_level_0::SIZE-1) - seek_offset; - Genode::error(name(), ": size limit ", (long)Chunk_level_0::SIZE, " reached"); - } - - _chunk.write(src, len, (size_t)seek_offset); - - /* - * Keep track of file length. We cannot use 'chunk.used_size()' - * as file length because trailing zeros may by represented - * by zero chunks, which do not contribute to 'used_size()'. - */ - _length = max(_length, seek_offset + len); - - mark_as_updated(); - return len; - } - - virtual Status status() const - { - Status s; - - s.inode = inode(); - s.size = _length; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - virtual file_size_t length() const { return _length; } - - void truncate(file_size_t size) override - { - if (size < _chunk.used_size()) - _chunk.truncate(size); - - _length = size; - - mark_as_updated(); - } -}; - -#endif /* _FILE_H_ */ diff --git a/repos/os/src/server/trace_fs/followed_subject.h b/repos/os/src/server/trace_fs/followed_subject.h deleted file mode 100644 index 8a5d0fed9..000000000 --- a/repos/os/src/server/trace_fs/followed_subject.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * \brief Facility for managing the trace subjects - * \author Josef Soentgen - * \date 2014-01-22 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _SUBJECT_REGISTRY_H_ -#define _SUBJECT_REGISTRY_H_ - -#include -#include -#include - -#include -#include - -namespace Trace_fs { - typedef Genode::size_t size_t; - class Followed_subject; - class Followed_subject_registry; -} - -class Trace_fs::Followed_subject : public Directory -{ - public: - - /** - * This class manages the access to the trace subject's trace buffer - */ - class Trace_buffer_manager - { - public: - - class Already_managed { }; - class Not_managed { }; - - struct Process_entry - { - virtual size_t operator()(Genode::Trace::Buffer::Entry&) = 0; - }; - - private: - - Genode::Trace::Buffer *buffer; - Genode::Trace::Buffer::Entry current_entry; - - - public: - - Trace_buffer_manager(Genode::Region_map &rm, - Genode::Dataspace_capability ds_cap) - : - buffer(rm.attach(ds_cap)), - current_entry(buffer->first()) - { } - - size_t dump_entry(Process_entry &process) - { - size_t len = process(current_entry); - - current_entry = buffer->next(current_entry); - return len; - } - - bool last_entry() const - { - return current_entry.last(); - } - - void rewind() { current_entry = buffer->first(); } - }; - - - private: - - Genode::Allocator &_md_alloc; - - Genode::Region_map &_rm; - - int _handle; - - Genode::Trace::Subject_id _id; - Genode::Trace::Policy_id _policy_id; - - bool _was_traced; - - Trace_buffer_manager *_buffer_manager; - - public: - - Active_file active_file; - Buffer_size_file buffer_size_file; - Cleanup_file cleanup_file; - Enable_file enable_file; - Events_file events_file; - Policy_file policy_file; - - Followed_subject(Genode::Allocator &md_alloc, char const *name, - Genode::Region_map &rm, - Genode::Trace::Subject_id &id, int handle) - : - Directory(name), - _md_alloc(md_alloc), - _rm(rm), - _handle(handle), - _id(id), - _was_traced(false), - _buffer_manager(0), - active_file(_id), - buffer_size_file(), - cleanup_file(_id), - enable_file(_id), - events_file(_id, _md_alloc), - policy_file(_id, _md_alloc) - { - adopt_unsynchronized(&active_file); - adopt_unsynchronized(&cleanup_file); - adopt_unsynchronized(&enable_file); - adopt_unsynchronized(&events_file); - adopt_unsynchronized(&buffer_size_file); - adopt_unsynchronized(&policy_file); - } - - ~Followed_subject() - { - discard_unsynchronized(&active_file); - discard_unsynchronized(&cleanup_file); - discard_unsynchronized(&enable_file); - discard_unsynchronized(&events_file); - discard_unsynchronized(&buffer_size_file); - discard_unsynchronized(&policy_file); - } - - bool marked_for_cleanup() const { return cleanup_file.cleanup(); } - bool was_traced() const { return _was_traced; } - - Trace_buffer_manager* trace_buffer_manager() { return _buffer_manager; } - - void manage_trace_buffer(Genode::Dataspace_capability ds_cap) - { - if (_buffer_manager != 0) - throw Trace_buffer_manager::Already_managed(); - - _buffer_manager = new (&_md_alloc) Trace_buffer_manager(_rm, ds_cap); - } - - void unmanage_trace_buffer() - { - if (_buffer_manager == 0) - throw Trace_buffer_manager::Not_managed(); - - destroy(&_md_alloc, _buffer_manager); - _buffer_manager = 0; - } - - const Genode::Trace::Subject_id id() const { return _id; } - - const Genode::Trace::Policy_id policy_id() const { return _policy_id; } - void policy_id(Genode::Trace::Policy_id &id) { _policy_id.id = id.id; } - bool policy_valid() const { return (_policy_id.id != 0); } - void invalidate_policy() { _policy_id = Genode::Trace::Policy_id(); } - - int handle() const { return _handle; } -}; - - -/** - * This registry contains all current followed trace subjects - */ -class Trace_fs::Followed_subject_registry -{ - public: - - class Invalid_subject { }; - class Out_of_subject_handles { }; - - private: - - /* XXX abitrary limit - needs to be revisited when highly - * dynamic scenarios are executed */ - enum { MAX_SUBJECTS = 1024U }; - - Followed_subject *_subjects[MAX_SUBJECTS]; - - Genode::Allocator &_md_alloc; - - /** - * Find free subject handle - * - * \throw Out_of_subject_handles - */ - int _find_free_handle() - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - if (!_subjects[i]) { - return i; - } - - throw Out_of_subject_handles(); - } - - bool _in_range(int handle) const - { - return ((handle >= 0) && (handle < MAX_SUBJECTS)); - } - - public: - - Followed_subject_registry(Genode::Allocator &md_alloc) - : - _md_alloc(md_alloc) - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - _subjects[i] = 0; - } - - /** - * Return maximal number of subject that can be stored in the registry - * - * \return maximal number of subjects - */ - unsigned max_subjects() const { return MAX_SUBJECTS; } - - /** - * Allocate new subject - * - * \param name name of subject - * \param id subject id of tracre subject - */ - Followed_subject *alloc(char const *name, Genode::Trace::Subject_id &id, - Genode::Region_map &rm) - { - int handle = _find_free_handle(); - - _subjects[handle] = new (&_md_alloc) Followed_subject(_md_alloc, name, rm, id, handle); - - return _subjects[handle]; - } - - /** - * Free subject - * - * \param subject pointer to subject - */ - void free(Followed_subject *subject) - { - int handle = subject->handle(); - - if (!_in_range(handle)) - return; - - if(!_subjects[handle]) - return; - - _subjects[handle] = 0; - destroy(&_md_alloc, subject); - } - - /** - * Lookup subject by using the id - * - * \throw Invalid_subject(); - */ - Followed_subject *lookup(Genode::Trace::Subject_id const &sid) - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - if (_subjects[i]) { - if (_subjects[i]->id().id == sid.id) - return _subjects[i]; - } - - throw Invalid_subject(); - } -}; - -#endif /* _SUBJECT_REGISTRY_H_ */ diff --git a/repos/os/src/server/trace_fs/main.cc b/repos/os/src/server/trace_fs/main.cc deleted file mode 100644 index 8205eb3f9..000000000 --- a/repos/os/src/server/trace_fs/main.cc +++ /dev/null @@ -1,1136 +0,0 @@ -/* - * \brief Trace file system - * \author Josef Soentgen - * \date 2014-01-15 - */ - -/* - * 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 Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* local includes */ -#include -#include -#include -#include - - -namespace Trace_fs { - - using File_system::Packet_descriptor; - using File_system::Path; - - class Trace_file_system; - struct Policy; - struct Main; - struct Session_component; - struct Root; -} - - -/** - * Session-specific policy defined by the configuation - */ -struct Trace_fs::Policy -{ - uint64_t interval; /* in milliseconds */ - unsigned subject_limit; - Genode::Number_of_bytes trace_quota; - Genode::Number_of_bytes trace_meta_quota; - Genode::Number_of_bytes buffer_size; - Genode::Number_of_bytes buffer_size_max; - unsigned trace_parent_levels; - - static Number_of_bytes _kib(size_t value) { return value * (1 << 10); } - static Number_of_bytes _mib(size_t value) { return value * (1 << 20); } - - static Policy from_xml(Xml_node node) - { - return Policy { - .interval = node.attribute_value("interval", (uint64_t)1000), - .subject_limit = node.attribute_value("subject_limit", 128U), - .trace_quota = node.attribute_value("trace_quota", _mib(32)), - .trace_meta_quota = node.attribute_value("trace_meta_quota", _kib(256)), - .buffer_size = node.attribute_value("buffer_size", _kib(32)), - .buffer_size_max = node.attribute_value("buffer_size_max", _mib(1)), - .trace_parent_levels = node.attribute_value("parent_levels", 0U) - }; - } -}; - - -/** - * Return true if 'str' is a valid file name - */ -static inline bool valid_filename(char const *str) -{ - if (!str) return false; - - /* must have at least one character */ - if (str[0] == 0) return false; - - /* must not contain '/' or '\' or ':' */ - if (File_system::string_contains(str, '/') || - File_system::string_contains(str, '\\') || - File_system::string_contains(str, ':')) - return false; - - return true; -} - -/** - * This class updates the file system - * - * In this context updating means creating the files and directories if - * needed, refreshing their content or deleting them if they are no - * longer of any use. - */ -class Trace_fs::Trace_file_system -{ - private: - - /* local abbreviations */ - typedef Genode::size_t size_t; - - typedef Genode::Trace::Subject_id Subject_id; - typedef Genode::Trace::Subject_info Subject_info; - typedef Genode::Trace::Connection Trace; - - /** - * Simple node list - * - * This list is used to temporarily store pointers to all nodes - * needed for representing a trace subject in the file system when - * creating or cleaning up the file system hierachie. - */ - class Node_list - { - private: - - /** - * Node list element class - * - * A element only contains a pointer to the actual node. - */ - struct Node_list_entry : public Genode::List::Element - { - Node *node; - - Node_list_entry(Node *n) : node(n) { } - }; - - Genode::Allocator &_md_alloc; - - Genode::List _list; - - public: - - Node_list(Genode::Allocator &md_alloc) : _md_alloc(md_alloc) { } - - /** - * Free all memory automatically if the object goes out of - * scope or rather is deleted. - */ - ~Node_list() - { - for (Node_list_entry *e = _list.first(); e; ) { - Node_list_entry *cur = e; - e = e->next(); - - _list.remove(cur); - destroy(&_md_alloc, cur); - } - } - - /** - * Insert a node in the list - * - * \param node pointer to node - */ - void push(Node *node) - { - Node_list_entry *e = new (&_md_alloc) Node_list_entry(node); - _list.insert(e); - } - - /** - * Remove the first node from the list - * - * The first element will be removed from the list and the node - * is returned. - * - * \return pointer to node or 0 - */ - Node *pop() - { - Node_list_entry *e = _list.first(); - if (e) { - Node *node = e->node; - - _list.remove(e); - destroy(&_md_alloc, e); - - return node; - } - - return 0; - } - - /** - * Return the node pointer of the first element in the list - * - * This method only returns the pointer but leaves the list - * element in good order. - * - * \return pointer to node of the first element or 0 - */ - Node *first() - { - Node_list_entry *e = _list.first(); - return e ? e->node : 0; - } - }; - - - /** - * This class implements the Process_entry functor class - * - * It is needed by the Trace_buffer_manager to process a entry - * from the Trace::Buffer. - */ - template - class Process_entry : public Followed_subject::Trace_buffer_manager::Process_entry - { - private: - - char _buf[CAPACITY]; - size_t _length; - - - public: - - Process_entry() : _length(0) { _buf[0] = 0; } - - /** - * Return capacity of the internal buffer - * - * \return capacity of the buffer in bytes - */ - size_t capacity() const { return CAPACITY; } - - /** - * Return data of the processed Trace::Buffer::Entry - * - * \return pointer to data - */ - char const *data() const { return _buf; } - - /** - * Functor for processing a Trace:Buffer::Entry - * - * \param entry reference of Trace::Buffer::Entry - * - * \return length of processed Trace::Buffer::Entry - */ - Genode::size_t operator()(Genode::Trace::Buffer::Entry &entry) - { - Genode::size_t len = Genode::min(entry.length() + 1, CAPACITY); - Genode::memcpy(_buf, entry.data(), len); - _buf[len - 1] = '\n'; - - _length = len; - - return len; - } - }; - - - Genode::Region_map &_rm; - Genode::Allocator &_alloc; - Genode::Trace::Connection &_trace; - Directory &_root_dir; - - size_t _buffer_size; - size_t _buffer_size_max; - - Followed_subject_registry _followed_subject_registry; - - - /** - * Cast Node pointer to Directory pointer - * - * \param node pointer to node - */ - Directory *_node_to_directory(Node *node) - { - return dynamic_cast(node); - } - - /** - * Gather recent trace events - * - * \param subject pointer to subject - */ - void _gather_events(Followed_subject *subject) - { - Followed_subject::Trace_buffer_manager *manager = subject->trace_buffer_manager(); - if (!manager) - return; - - Process_entry<512> process_entry; - - while (!manager->last_entry()) { - size_t len = manager->dump_entry(process_entry); - - if (len == 0) - continue; - - try { subject->events_file.append(process_entry.data(), len); } - catch (...) { Genode::error("could not write entry"); } - } - - if (manager->last_entry()) { - manager->rewind(); - } - } - - /** - * Disable tracing of a followed subject - * - * \param subject pointer to subject - */ - void _disable_tracing(Followed_subject *subject) - { - subject->active_file.set_inactive(); - - _trace.pause(subject->id()); - _gather_events(subject); - try { subject->unmanage_trace_buffer(); } - catch (...) { Genode::error("trace buffer was not managed"); } - _trace.free(subject->id()); - } - - /** - * Enable tracing of a followed subject - * - * \param subject pointer to subject - */ - void _enable_tracing(Followed_subject *subject) - { - try { - _trace.trace(subject->id().id, subject->policy_id().id, - subject->buffer_size_file.size()); - - try { subject->manage_trace_buffer(_trace.buffer(subject->id())); } - catch (...) { Genode::error("trace buffer is already managed"); } - - subject->active_file.set_active(); - } - catch (...) { Genode::error("could not enable tracing"); } - } - - /** - * Search recursively the parent node for the corresponding label - * - * \param list list of traversed nodes - * \param walker label walking object - * \param parent parent node of the current directory - * - * \return parent node for the given label - */ - Directory* _find_parent_node(Node_list &list, Util::Label_walker &walker, - Directory &parent) - { - char const *remainder = walker.next(); - - Directory *child; - - try { child = _node_to_directory(parent.lookup(walker.element())); } - catch (File_system::Lookup_failed) { - try { - child = new (&_alloc) Directory(walker.element()); - parent.adopt_unsynchronized(child); - } - catch (...) { - Genode::error("could not create '", walker.element(), "'"); - return 0; - } - } - - list.push(child); - - if (!*remainder) { - return child; - } else { - return _find_parent_node(list, walker, *child); - } - } - - /** - * Remove unsused nodes and free the memory - * - * All nodes are removed from the list and discarded from their - * parent until we hit a node or rather a parent that still has - * child nodes. In this case we stop. The remaining entries in - * the node list are freed when the Node_list is deleted. - * - * \param list reference to list - */ - void _remove_nodes(Node_list &list) - { - while (Node *child = list.pop()) { - Node *parent = list.first(); - - Directory *dir = dynamic_cast(child); - if (dir->num_entries() == 0) { - - if (parent) { - Directory *dir = dynamic_cast(parent); - if (!(Genode::strcmp(dir->name(), child->name()) == 0)) - dir->discard_unsynchronized(child); - } - - destroy(&_alloc, dir); - } else { - /* do not bother any further, node has other children */ - break; - } - } - } - - - public: - - /** - * Constructor - */ - Trace_file_system(Genode::Region_map &rm, - Genode::Allocator &alloc, - Trace &trace, - Directory &root_dir, - size_t buffer_size, - size_t buffer_size_max) - : - _rm(rm), _alloc(alloc), _trace(trace), _root_dir(root_dir), - _buffer_size(buffer_size), _buffer_size_max(buffer_size_max), - _followed_subject_registry(_alloc) - { } - - /** - * Handle the change of the content of a node - * - * XXX This method could be made much simpler if a Node would - * store the subject_id and could be used to make the lookup. - */ - void handle_changed_node(Node *node) - { - Followed_subject *subject = 0; - bool policy_changed = false; - - using namespace File_system; - - /** - * It is enough to invoke acknowledge_change() on the Cleanup_file. - * Therefore here is nothing to be done. - */ - Cleanup_file *cleanup_file = dynamic_cast(node); - if (cleanup_file) { - return; - } - - Policy_file *policy_file = dynamic_cast(node); - if (policy_file) { - try { - subject = _followed_subject_registry.lookup(policy_file->id()); - size_t policy_length = policy_file->length(); - - /* policy was changed, unload old one first */ - if (subject->policy_valid()) { - _trace.unload_policy(subject->policy_id()); - - subject->invalidate_policy(); - } - - /** - * Copy the new policy only if it may containg something useful. - * XXX: It might be better to check for a more reaseonable length. - */ - if (policy_length > 0) { - try { - Genode::Trace::Policy_id id = _trace.alloc_policy(policy_length); - - Genode::Dataspace_capability ds_cap = _trace.policy(id); - if (ds_cap.valid()) { - void *ram = _rm.attach(ds_cap); - size_t n = policy_file->read((char *)ram, policy_length, 0UL); - - if (n != policy_length) { - Genode::error("error while copying policy content"); - } else { subject->policy_id(id); } - - _rm.detach(ram); - } - } - catch (...) { Genode::error("could not allocate policy"); } - } - - policy_changed = true; - } - catch (Trace_fs::Followed_subject_registry::Invalid_subject) { } - } - - Enable_file *enable_file = dynamic_cast(node); - if (enable_file) { - try { subject = _followed_subject_registry.lookup(enable_file->id()); } - catch (Trace_fs::Followed_subject_registry::Invalid_subject) { } - } - - /** - * Perform the action which was originally intended. This is actually - * safe because at this point we got invoked by either the Enable_file - * or Policy_file file. - */ - Subject_info info = _trace.subject_info(subject->id()); - Subject_info::State state = info.state(); - - /* tracing already enabled but policy has changed */ - if (subject->enable_file.enabled() && policy_changed) { - /* disable tracing first */ - if (state == Subject_info::State::TRACED) - _disable_tracing(subject); - - /* reenable only if the policy is actually valid */ - if (subject->policy_valid()) - _enable_tracing(subject); - } - /* subject is untraced but tracing is now enabled */ - else if (subject->enable_file.enabled() && - (state == Subject_info::State::UNTRACED)) { - if (subject->policy_valid()) - _enable_tracing(subject); - } - /* subject is traced but tracing is now disabled */ - else if (!subject->enable_file.enabled() && - (state == Subject_info::State::TRACED)) { - _disable_tracing(subject); - } - } - - /** - * Update the trace subjects - * - * \param subject_limit limit the number of trace subjects - */ - void update(int subject_limit) - { - Genode::Trace::Subject_id subjects[subject_limit]; - - size_t num_subjects = _trace.subjects(subjects, subject_limit); - - /* traverse current trace subjects */ - for (size_t i = 0; i < num_subjects; i++) { - Subject_info info = _trace.subject_info(subjects[i]); - Subject_info::State state = info.state(); - - /* opt-out early */ - switch (state) { - case Subject_info::State::INVALID: - case Subject_info::State::FOREIGN: - case Subject_info::State::ERROR: - continue; - break; /* never reached */ - default: - break; - } - - Followed_subject *followed_subject; - - try { - /* old subject found */ - followed_subject = _followed_subject_registry.lookup(subjects[i]); - - /** - * Update content of the corresponding events file - */ - if (state == Subject_info::State::TRACED) { - _gather_events(followed_subject); - continue; - } - - /** - * The subject is either UNTRACED or DEAD in which case we want to remove - * the nodes if they are marked for deletion. - */ - if (followed_subject->marked_for_cleanup() || - (!followed_subject->was_traced() && state == Subject_info::State::DEAD)) { - char const *label = info.session_label().string(); - - Node_list list(_alloc); - Util::Label_walker walker(label); - - Directory *parent = _find_parent_node(list, walker, _root_dir); - if (!parent) { - Genode::error("could not find parent node for label:'", label, "'"); - continue; - } - - parent->discard_unsynchronized(followed_subject); - _remove_nodes(list); - _followed_subject_registry.free(followed_subject); - continue; - } - } catch (Trace_fs::Followed_subject_registry::Invalid_subject) { - - /* ignore unknown but already dead subject */ - if (state == Subject_info::State::DEAD) - continue; - - /* new subject */ - char const *label = info.session_label().string(); - char const *name = info.thread_name().string(); - - Util::Buffer<64> subject_dir_name; - Genode::snprintf(subject_dir_name.data(), subject_dir_name.capacity(), - "%s.%d", name, subjects[i].id); - - subject_dir_name.replace('/', '_'); - - followed_subject = _followed_subject_registry.alloc(subject_dir_name.data(), - subjects[i], _rm); - - /* set trace buffer size */ - followed_subject->buffer_size_file.size_limit(_buffer_size_max); - followed_subject->buffer_size_file.size(_buffer_size); - - Node_list list(_alloc); - Util::Label_walker walker(label); - Directory *parent = _find_parent_node(list, walker, _root_dir); - if (!parent) { - Genode::error("could not find parent node on creation"); - continue; - } - - parent->adopt_unsynchronized(followed_subject); - } - } - } -}; - - -class Trace_fs::Session_component : public Session_rpc_object -{ - private: - - typedef File_system::Open_node Open_node; - - Genode::Entrypoint &_ep; - Ram_allocator &_ram; - Allocator &_md_alloc; - Directory &_root_dir; - Id_space _open_node_registry; - bool _writeable; - - unsigned _subject_limit; - uint64_t _poll_interval; - - Timer::Connection _fs_update_timer; - - Trace::Connection *_trace; - Trace_file_system *_trace_fs; - - Signal_handler _process_packet_handler { - _ep, *this, &Session_component::_process_packets }; - - Signal_handler _fs_update_handler { - _ep, *this, &Session_component::_fs_update }; - - - /************************** - ** File system updating ** - **************************/ - - /** - * Update the file system hierarchie and data of active trace subjects - */ - void _fs_update() - { - _trace_fs->update(_subject_limit); - } - - /****************************** - ** Packet-stream processing ** - ******************************/ - - /** - * Perform packet operation - */ - void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) - { - void * const content = tx_sink()->packet_content(packet); - size_t const length = packet.length(); - - /* resulting length */ - size_t res_length = 0; - bool succeeded = false; - - switch (packet.operation()) { - - case Packet_descriptor::READ: - if (content && (packet.length() <= packet.size())) { - Locked_ptr node { open_node.node() }; - if (!node.valid()) - break; - res_length = node->read((char *)content, length, packet.position()); - succeeded = res_length > 0; - } - break; - - case Packet_descriptor::WRITE: - if (content && (packet.length() <= packet.size())) { - Locked_ptr node { open_node.node() }; - if (!node.valid()) - break; - res_length = node->write((char const *)content, length, packet.position()); - - /* File system session can't handle partial writes */ - if (res_length != length) { - Genode::error("partial write detected ", - res_length, " vs ", length); - /* don't acknowledge */ - return; - } - succeeded = true; - } - break; - - case Packet_descriptor::CONTENT_CHANGED: { - open_node.register_notify(*tx_sink()); - - /* notify_listeners may bounce the packet back*/ - Locked_ptr node { open_node.node() }; - if (!node.valid()) - return; - node->notify_listeners(); - - /* otherwise defer acknowledgement of this packet */ - return; - } - - case Packet_descriptor::READ_READY: - succeeded = true; - /* not supported */ - break; - - case Packet_descriptor::SYNC: - succeeded = true; - /* not supported */ - break; - } - - packet.length(res_length); - packet.succeeded(succeeded); - tx_sink()->acknowledge_packet(packet); - } - - void _process_packet() - { - Packet_descriptor packet = tx_sink()->get_packet(); - - /* assume failure by default */ - packet.succeeded(false); - - auto process_packet_fn = [&] (Open_node &open_node) { - _process_packet_op(packet, open_node); - }; - - try { - _open_node_registry.apply(packet.handle(), process_packet_fn); - } catch (Id_space::Unknown_id const &) { - Genode::error("Invalid_handle"); - } - - /* - * The 'acknowledge_packet' function cannot block because we - * checked for 'ready_to_ack' in '_process_packets'. - */ - tx_sink()->acknowledge_packet(packet); - } - - /** - * Called by signal handler, executed in the context of the main - * thread (not serialized with the RPC functions) - */ - void _process_packets() - { - while (tx_sink()->packet_avail()) { - - /* - * Make sure that the '_process_packet' function does not - * block. - * - * If the acknowledgement queue is full, we defer packet - * processing until the client processed pending - * acknowledgements and thereby emitted a ready-to-ack - * signal. Otherwise, the call of 'acknowledge_packet()' - * in '_process_packet' would infinitely block the context - * of the main thread. The main thread is however needed - * for receiving any subsequent 'ready-to-ack' signals. - */ - if (!tx_sink()->ready_to_ack()) - return; - - _process_packet(); - } - } - - /** - * Check if string represents a valid path (must start with '/') - */ - static void _assert_valid_path(char const *path) - { - if (!path || path[0] != '/') { - Genode::warning("malformed path '", path, "'"); - throw Lookup_failed(); - } - } - - - public: - - /** - * Constructor - */ - Session_component(size_t tx_buf_size, - Genode::Entrypoint &ep, - Genode::Ram_allocator &ram, - Genode::Region_map &rm, - Genode::Env &env, - Directory &root_dir, - Allocator &md_alloc, - Trace_fs::Policy policy) - : - Session_rpc_object(ram.alloc(tx_buf_size), rm, ep.rpc_ep()), - _ep(ep), - _ram(ram), - _md_alloc(md_alloc), - _root_dir(root_dir), - - _subject_limit(policy.subject_limit), - _poll_interval(policy.interval), - _fs_update_timer(env), - _trace(new (&_md_alloc) - Genode::Trace::Connection(env, policy.trace_quota, - policy.trace_meta_quota, - policy.trace_parent_levels)), - _trace_fs(new (&_md_alloc) - Trace_file_system(rm, _md_alloc, *_trace, _root_dir, - policy.buffer_size, policy.buffer_size_max)) - { - _tx.sigh_packet_avail(_process_packet_handler); - _tx.sigh_ready_to_ack(_process_packet_handler); - - /** - * Register '_fs_update' dispatch function as signal handler - * for polling the trace session. - */ - _fs_update_timer.sigh(_fs_update_handler); - - /** - * We need to scale _poll_interval because trigger_periodic() - * uses usec. - */ - _fs_update_timer.trigger_periodic(_poll_interval * 1000); - } - - /** - * Destructor - */ - ~Session_component() - { - destroy(&_md_alloc, _trace_fs); - destroy(&_md_alloc, _trace); - - Dataspace_capability ds = tx_sink()->dataspace(); - _ram.free(static_cap_cast(ds)); - } - - - /*************************** - ** File_system interface ** - ***************************/ - - File_handle file(Dir_handle dir_handle, Name const &name, Mode mode, bool create) - { - if (!valid_filename(name.string())) - throw Invalid_name(); - - auto file_fn = [&] (Open_node &open_node) { - - Locked_ptr dir { open_node.node() }; - - if (!dir.valid()) - throw Invalid_handle(); - - if (create) - throw Permission_denied(); - - File *file = dynamic_cast(dir->lookup(name.string())); - if (!file) - throw Invalid_name(); - - Open_node *open_file = - new (_md_alloc) Open_node(file->weak_ptr(), _open_node_registry); - - return open_file->id(); - }; - - try { - return File_handle { - _open_node_registry.apply(dir_handle, file_fn).value - }; - } catch (Id_space::Unknown_id const &) { - throw Invalid_handle(); - } - } - - Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) - { - Genode::warning("symlinks not supported"); - throw Permission_denied(); - } - - Dir_handle dir(Path const &path, bool create) - { - char const *path_str = path.string(); - - _assert_valid_path(path_str); - - if (create) - throw Permission_denied(); - - if (!path.valid_string()) - throw Name_too_long(); - - Directory *dir = dynamic_cast(_root_dir.lookup(path_str + 1)); - if (!dir) - throw Invalid_name(); - - Open_node *open_dir = - new (_md_alloc) Open_node(dir->weak_ptr(), _open_node_registry); - - return Dir_handle { open_dir->id().value }; - } - - Node_handle node(Path const &path) - { - char const *path_str = path.string(); - - _assert_valid_path(path_str); - - Node *node = _root_dir.lookup(path_str + 1); - - Open_node *open_node = - new (_md_alloc) Open_node(node->weak_ptr(), _open_node_registry); - - return open_node->id(); - } - - void close(Node_handle handle) - { - auto close_fn = [&] (Open_node &open_node) { - - Locked_ptr node { open_node.node() }; - - if (!node.valid()) - throw Invalid_handle(); - - /** - * Acknowledge the change of the content of files which may be - * modified by the user of the file system. - */ - Changeable_content *changeable = dynamic_cast(&*node); - if (changeable) { - if (changeable->changed()) { - changeable->acknowledge_change(); - - /* let the trace fs perform the provoked actions */ - _trace_fs->handle_changed_node(&*node); - } - } - - /* - * Notify listeners about the changed file. - */ - node->notify_listeners(); - - /* - * De-allocate handle - */ - destroy(_md_alloc, &open_node); - }; - - try { - _open_node_registry.apply(handle, close_fn); - } catch (Id_space::Unknown_id const &) { - throw Invalid_handle(); - } - } - - Status status(Node_handle node_handle) - { - auto status_fn = [&] (Open_node &open_node) { - Locked_ptr node { open_node.node() }; - if (!node.valid()) - throw Invalid_handle(); - return node->status(); - }; - - try { - return _open_node_registry.apply(node_handle, status_fn); - } catch (Id_space::Unknown_id const &) { - throw Invalid_handle(); - } - } - - void control(Node_handle, Control) { } - void unlink(Dir_handle dir_handle, Name const &name) { } - - void truncate(File_handle handle, file_size_t size) - { - auto truncate_fn = [&] (Open_node &open_node) { - Locked_ptr node { open_node.node() }; - if (!node.valid()) - throw Invalid_handle(); - node->truncate(size); - }; - - try { - _open_node_registry.apply(handle, truncate_fn); - } catch (Id_space::Unknown_id const &) { - throw Invalid_handle(); - } - } - - void move(Dir_handle, Name const &, Dir_handle, Name const &) { } -}; - - -class Trace_fs::Root : public Root_component -{ - private: - - Genode::Entrypoint &_ep; - Genode::Ram_allocator &_ram; - Genode::Region_map &_rm; - Genode::Env &_env; - - Directory &_root_dir; - - Genode::Attached_rom_dataspace _config { _env, "config" }; - - protected: - - Session_component *_create_session(const char *args) - { - /* - * Determine client-specific policy defined implicitly by - * the client's label. - */ - Session_label const label = label_from_args(args); - - Session_policy policy(label, _config.xml()); - - /* make sure that root directory is defined */ - if (!policy.has_attribute("root")) { - Genode::error("Missing \"root\" attribute in policy definition"); - throw Service_denied(); - } - - Trace_fs::Policy const attributes = Trace_fs::Policy::from_xml(policy); - - size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); - - if (!tx_buf_size) { - Genode::error(label, " requested a session with a zero length transmission buffer"); - throw Genode::Service_denied(); - } - - /* - * Check if donated ram quota suffices for session data, - * and communication buffer. - */ - size_t session_size = sizeof(Session_component) + tx_buf_size; - if (max((size_t)4096, session_size) > ram_quota) { - Genode::error("insufficient 'ram_quota', got ", ram_quota, ", " - "need ", session_size); - throw Insufficient_ram_quota(); - } - return new (md_alloc()) - Session_component(tx_buf_size, _ep, _ram, _rm, _env, _root_dir, - *md_alloc(), attributes); - } - - public: - - /** - * Constructor - * - * \param ep entrypoint - * \param sig_rec signal receiver used for handling the - * data-flow signals of packet streams - * \param md_alloc meta-data allocator - */ - Root(Genode::Entrypoint &ep, Allocator &md_alloc, Ram_allocator &ram, - Region_map &rm, Env &env, Directory &root_dir) - : - Root_component(&ep.rpc_ep(), &md_alloc), - _ep(ep), - _ram(ram), - _rm(rm), - _env(env), - _root_dir(root_dir) - { } -}; - - -struct Trace_fs::Main -{ - Env &_env; - - Directory root_dir = { "/" }; - - /* - * Initialize root interface - */ - Sliced_heap sliced_heap = { _env.ram(), _env.rm() }; - - Root fs_root = { _env.ep(), sliced_heap, _env.ram(), _env.rm(), _env, root_dir }; - - Main(Env &env) : _env(env) - { - env.parent().announce(env.ep().manage(fs_root)); - } -}; - -void Component::construct(Genode::Env &env) { static Trace_fs::Main main(env); } diff --git a/repos/os/src/server/trace_fs/node.h b/repos/os/src/server/trace_fs/node.h deleted file mode 100644 index 17785d99d..000000000 --- a/repos/os/src/server/trace_fs/node.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * \brief File-system node - * \author Norman Feske - * \date 2012-04-11 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _NODE_H_ -#define _NODE_H_ - -/* Genode includes */ -#include -#include -#include -#include - -namespace Trace_fs { - using namespace File_system; - using namespace Genode; - class Node; -} - -class Trace_fs::Node : public Node_base, public Weak_object, - public List::Element -{ - public: - - typedef char Name[128]; - - private: - - Name _name; - unsigned long const _inode; - - /** - * Generate unique inode number - */ - static unsigned long _unique_inode() - { - static unsigned long inode_count; - return ++inode_count; - } - - public: - - Node() - : _inode(_unique_inode()) - { _name[0] = 0; } - - virtual ~Node() { lock_for_destruction(); } - - unsigned long inode() const { return _inode; } - char const *name() const { return _name; } - - /** - * Assign name - */ - void name(char const *name) { strncpy(_name, name, sizeof(_name)); } - - virtual Status status() const = 0; - - 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; - - /* - * Directory functionality - */ - virtual Node *lookup(char const *path, bool return_parent = false) - { - Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); - return nullptr; - } - - /* - * File functionality - */ - virtual void truncate(file_size_t size) - { - Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); - } -}; - -#endif /* _NODE_H_ */ diff --git a/repos/os/src/server/trace_fs/symlink.h b/repos/os/src/server/trace_fs/symlink.h deleted file mode 100644 index 84088ac41..000000000 --- a/repos/os/src/server/trace_fs/symlink.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * \brief Symlink file-system node - * \author Norman Feske - * \date 2012-04-11 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _SYMLINK_H_ -#define _SYMLINK_H_ - -/* local includes */ -#include - -namespace Trace_fs { - class Symlink; -} - -class Trace_fs::Symlink : public File -{ - public: - - Symlink(char const *name) : File(name) { } - - size_t read(char *dst, size_t len, seek_off_t seek_offset) { - return 0; } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) { - return 0; } - - file_size_t length() const { return 0; } - - void truncate(file_size_t) { } -}; - -#endif /* _SYMLINK_H_ */ diff --git a/repos/os/src/server/trace_fs/target.mk b/repos/os/src/server/trace_fs/target.mk deleted file mode 100644 index 2ce96cc1b..000000000 --- a/repos/os/src/server/trace_fs/target.mk +++ /dev/null @@ -1,6 +0,0 @@ -TARGET = trace_fs -SRC_CC = main.cc -LIBS = base -INC_DIR += $(PRG_DIR) - -CC_CXX_WARN_STRICT = diff --git a/repos/os/src/server/trace_fs/trace_files.h b/repos/os/src/server/trace_fs/trace_files.h deleted file mode 100644 index 43d4b122b..000000000 --- a/repos/os/src/server/trace_fs/trace_files.h +++ /dev/null @@ -1,438 +0,0 @@ -/* - * \brief Trace files - * \author Josef Soentgen - * \date 2014-01-22 - */ - -/* - * 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 Affero General Public License version 3. - */ - -#ifndef _TRACE_FILES_H_ -#define _TRACE_FILES_H_ - -/* Genode includes */ -#include - -/* local includes */ -#include - - -namespace Trace_fs { - class State_file; - class Active_file; - class Cleanup_file; - class Enable_file; - class Events_file; - class Buffer_size_file; - class Policy_file; -} - -/** - * The State_file is a stateful file that is used to implement - * files in the file system, which may trigger a action in the - * file system backend. - */ - -class Trace_fs::State_file : public File, - public Changeable_content -{ - protected: - - bool _state; - - - public: - - State_file(char const *name) - : File(name), _state(false) { } - - bool state() const { return _state; } - - - /******************** - ** Node interface ** - ********************/ - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - /* limit len */ - if (len > 2) - len = 2; - - switch (len) { - case 2: - dst[1] = '\n'; - case 1: - dst[0] = 0x30 + (char)_state; - break; - default: - /* zero length is useless */ - break; - } - - return len; - } - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - char buf[32]; - if (len >= sizeof buf) - return 0; - - using namespace Genode; - - strncpy(buf, src, min(len + 1, sizeof (buf))); - - /** - * For now, we only check the leading digit and do not care - * about the rest. - */ - if (!strcmp(buf, "1", 1)) { - _state = true; - } - else if (!strcmp(buf, "0", 1)) { - _state = false; - } else { - /* silently ignore bogus writes */ - return 0; - } - - Changeable_content::_changed = true; - - return len; - } - - Status status() const - { - Status s; - - s.inode = inode(); - s.size = 2; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - /******************** - ** File interface ** - ********************/ - - file_size_t length() const { return 2; } - void truncate(file_size_t size) { } -}; - - -/** - * The Active_file node shows the state of the tracing - */ - -class Trace_fs::Active_file : public State_file -{ - private: - - Genode::Trace::Subject_id &_id; - bool _active; - - - public: - - Active_file(Genode::Trace::Subject_id &id) - : State_file("active"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool active() const { return State_file::state(); } - - void set_active() { _state = true; } - void set_inactive() { _state = false; } -}; - - -/** - * The Cleanup_file is used to trigger the removal of files used by - * the traced subject and to free utilized memory. - */ - -class Trace_fs::Cleanup_file : public State_file -{ - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Cleanup_file(Genode::Trace::Subject_id &id) - : State_file("cleanup"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool cleanup() const { return State_file::state(); } -}; - - -/** - * The Enable_file is used to initiate the tracing process - */ - -class Trace_fs::Enable_file : public State_file -{ - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Enable_file(Genode::Trace::Subject_id &id) - : State_file("enable"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool enabled() const { return State_file::state(); } -}; - - -/** - * The Events_file encapsulates the trace buffer of traced thread - */ - -class Trace_fs::Events_file : public Buffered_file -{ - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Events_file(Genode::Trace::Subject_id &id, - Allocator &md_alloc) - : Buffered_file(md_alloc, "events"), _id(id) { } - - Genode::Trace::Subject_id id() const { return _id; } - - size_t append(char const *src, size_t len) - { - Buffered_file::write(src, len, length()); - - return len; - } - - /******************** - ** File interface ** - ********************/ - - /* override to prevent the user from overriding the file */ - size_t write(char const *src, size_t len, seek_off_t seek_offset) { return 0; } - void truncate(file_size_t size) { } -}; - - -/** - * This file contains the size of the trace buffer - */ - -class Trace_fs::Buffer_size_file : public File, - public Changeable_content -{ - private: - - file_size_t _length; - unsigned long _size_limit; - unsigned long _size; - - char _content[32]; - Genode::size_t _content_filled; - - /** - * Check if new size honors the size limit - * - * \param size new size of the buffer - * \return size limit if new size is greater, otherwise new size - */ - size_t _check_size_limit(size_t size) - { - if (size > _size_limit) - return _size_limit; - else - return size; - } - - /** - * Evalute the current content of the buffer - */ - void _refresh_content() - { - unsigned long tmp = 0; - - _content[_content_filled - 1] = '\0'; - _content_filled = 0; - - _length = Genode::strlen(_content); - - /* account for \n when reading from the file */ - _length += 1; - - ascii_to(_content, tmp); - - _size = _check_size_limit(tmp); - } - - - public: - - /** - * Constructor - */ - Buffer_size_file() : File("buffer_size"), _size_limit(0), _size(0) { } - - /** - * Return current size of the trace buffer - */ - unsigned long size() const { return _size; } - - /** - * Set current size of the trace buffer - */ - void size(unsigned long size) - { - _size = _check_size_limit(size); - - /* update file content */ - _length = Genode::snprintf(_content, sizeof (_content), "%lu", _size); - - /* account for \n when reading from the file */ - _length += 1; - } - - /** - * Set max size of a trace buffer - */ - void size_limit(unsigned long limit) { _size_limit = limit; } - - /** - * Return maximal size of the trace buffer - */ - unsigned long size_limit() const { return _size_limit; } - - - /******************** - ** Node interface ** - ********************/ - - /** - * Read current maximal size of the trace buffer - */ - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - if (len > 32) { - Genode::error("len:'", len, "' to small"); - return 0; - } - - char buf[32]; - Genode::snprintf(buf, sizeof (buf), "%lu\n", _size); - memcpy(dst, buf, len); - - return len; - } - - /** - * Write new current maximal size of the trace buffer - */ - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - if ((_content_filled + len) > sizeof (_content)) - return 0; - - Genode::memcpy(_content + _content_filled, src, len); - _content_filled += len; - - Changeable_content::_changed = true; - - return len; - } - - Status status() const - { - Status s; - - s.inode = inode(); - s.size = _length; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - - /******************** - ** File interface ** - ********************/ - - file_size_t length() const { return _length; } - - void truncate(file_size_t size) { } -}; - - -/** - * Policy file - */ - -class Trace_fs::Policy_file : public Buffered_file, - public Changeable_content -{ - private: - - Genode::Trace::Subject_id &_id; - file_size_t _length; - - - public: - - Policy_file(Genode::Trace::Subject_id &id, - Genode::Allocator &md_alloc) - : Buffered_file(md_alloc, "policy"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - - /******************** - ** Node interface ** - ********************/ - - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - return Buffered_file::read(dst, len, seek_offset); - } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - size_t written = Buffered_file::write(src, len, seek_offset); - - if (written > 0) - _changed = true; - - return written; - } - - - /******************** - ** File interface ** - ********************/ - - void truncate(file_size_t size) - { - Buffered_file::truncate(size); - - _changed = true; - } - -}; - -#endif /* _TRACE_FILES_H_ */ diff --git a/repos/ports/run/noux_trace_fs.run b/repos/ports/run/noux_trace_fs.run deleted file mode 100644 index 9f21f5803..000000000 --- a/repos/ports/run/noux_trace_fs.run +++ /dev/null @@ -1,160 +0,0 @@ -# -# The Linux version of Noux lacks the support for the fork system call. Hence, -# the run script is expected to fail. -# -if {[have_spec linux]} { - puts "Linux is unsupported." - exit 0 -} - -create_boot_directory - -import_from_depot [depot_user]/src/[base_src] \ - [depot_user]/pkg/[drivers_interactive_pkg] \ - [depot_user]/pkg/terminal \ - [depot_user]/src/init \ - [depot_user]/src/libc \ - [depot_user]/src/noux \ - [depot_user]/src/posix \ - [depot_user]/src/ncurses \ - [depot_user]/src/vim \ - [depot_user]/src/bash \ - [depot_user]/src/grep \ - [depot_user]/src/coreutils \ - [depot_user]/src/ram_fs - - -# write default vimrc file -set vimrc_fd [open "bin/vimrc" w] -puts $vimrc_fd { -set noloadplugins -set hls -set nocompatible -set laststatus=2 -set noswapfile -set viminfo=} -close $vimrc_fd - -install_config { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -} - -build { server/trace_fs lib/trace/policy/rpc_name } - -build_boot_image { vimrc trace_fs rpc_name } - -run_genode_until forever - -# vi: set ft=tcl :