More reasonable pointers, file nodes

This commit is contained in:
2024-04-07 18:36:06 +02:00
parent 9e53a0de33
commit ad273d0a96
20 changed files with 364 additions and 110 deletions

2
run.sh
View File

@@ -2,7 +2,7 @@
POSITIONAL_ARGS=()
QEMU_OPTS=" -no-reboot "
QEMU_OPTS=" -no-reboot -m 256M"
while [[ $# -gt 0 ]]; do
case $1 in

View File

@@ -9,7 +9,7 @@
extern volatile struct limine_module_request module_request;
static constexpr unsigned max_saved_modules = 2;
static constexpr unsigned max_saved_modules = 4;
static constexpr unsigned max_saved_module_name = 256;
void limine_modules_remap();

View File

@@ -88,32 +88,12 @@ uint64_t syscall_close(uint64_t FD) {
//FIXME:
uint64_t syscall_read(uint64_t fd, char *buf, uint64_t len) {
if (fd == 0) {
auto c = buf;
while ((c - buf) < len) {
*c = GlobalTtyManager.get_tty(0)->readchar();
if (*c == '\r') {
*(c++) = '\n';
break;
}
c++;
}
return (c - buf);
}
auto f = FDT::current()->get(fd);
if (!f) return -1;
return f->read(buf, len);
}
uint64_t syscall_write(uint64_t fd, const char *buf, uint64_t len) {
if (fd == 1) {
auto c = buf;
while (*c != '\0' && (c - buf) < len) {
GlobalTtyManager.all_tty_putchar(*c);
c++;
}
return len;
}
auto f = FDT::current()->get(fd);
if (!f) return -1;
return f->write(buf, len);

View File

@@ -2,8 +2,10 @@
#define POINTERS_H
#include <atomic>
#include <optional>
#include <utility>
#include "asserts.hpp"
#include "kmem.hpp"
class SharedPtrTester;
@@ -55,6 +57,78 @@ private:
T *ptr = nullptr;
};
struct SharedPtr_Base {
struct UsesBlock {
int32_t _uses_ctl;
int32_t _uses_obj;
} __attribute__((packed));
std::atomic<UsesBlock> _uses;
static_assert(decltype(_uses)::is_always_lock_free);
// Increments control block use counter
void weak_lock() {
UsesBlock old_uses = _uses.load();
UsesBlock new_uses;
do {
assert(old_uses._uses_ctl >= 1);
new_uses = old_uses;
new_uses._uses_ctl++;
} while (!_uses.compare_exchange_weak(old_uses, new_uses));
}
// Decrements control block use counter
// Returns true if it was deleted
bool weak_release() {
UsesBlock old_uses = _uses.load();
UsesBlock new_uses;
do {
new_uses = old_uses;
new_uses._uses_ctl--;
} while (!_uses.compare_exchange_weak(old_uses, new_uses));
if (new_uses._uses_ctl == 0)
delete this;
return new_uses._uses_ctl == 0;
}
// Increments control and object use counter
// Returns false if the object was already deleted
bool strong_lock() {
UsesBlock old_uses = _uses.load();
UsesBlock new_uses;
do {
if (old_uses._uses_obj <= 0)
return false;
new_uses = old_uses;
new_uses._uses_ctl++;
new_uses._uses_obj++;
} while (!_uses.compare_exchange_weak(old_uses, new_uses));
assert(new_uses._uses_obj > 0);
assert(new_uses._uses_ctl >= new_uses._uses_obj);
return true;
}
// Decrements control and object use counter
// Returns true if the object is to be deleted (it was the last reference)
bool strong_release() {
UsesBlock old_uses = _uses.load();
UsesBlock new_uses;
do {
new_uses = old_uses;
new_uses._uses_obj--;
new_uses._uses_ctl--;
} while (!_uses.compare_exchange_weak(old_uses, new_uses));
if (new_uses._uses_ctl == 0)
delete this;
return new_uses._uses_obj == 0;
}
};
template<typename T>
class SharedPtr {
friend SharedPtrTester;
@@ -62,51 +136,146 @@ class SharedPtr {
public:
SharedPtr() = default;
explicit SharedPtr(T *data) : ptr(data), uses(new std::atomic<int>(1)) {}
explicit SharedPtr(T *data) : _ptr(data), _base(new SharedPtr_Base{SharedPtr_Base::UsesBlock{1, 1}}) {}
SharedPtr(std::nullptr_t a_nullptr) : _ptr(nullptr), _base(nullptr) {}
~SharedPtr() {
if (ptr == nullptr || uses == nullptr) return;
if (uses->fetch_sub(1) == 1) {
delete ptr;
delete uses;
}
unref();
}
SharedPtr(SharedPtr const &other) : ptr(other.ptr), uses(other.uses) {
++(*uses);
SharedPtr(SharedPtr const &other) : _base(other._base), _ptr(other._ptr) {
if (!_base) return;
_base->strong_lock();
}
SharedPtr(SharedPtr &&other) {
if (ptr != nullptr && uses != nullptr)
if (uses->fetch_sub(1) == 1) {
delete ptr;
delete uses;
}
uses = other.uses;
ptr = other.ptr;
other.uses = nullptr;
other.ptr = nullptr;
unref();
_base = other._base;
_ptr = other._ptr;
other._base = nullptr;
other._ptr = nullptr;
}
SharedPtr &operator=(SharedPtr other) {
std::swap(ptr, other.ptr);
std::swap(uses, other.uses);
std::swap(_base, other._base);
std::swap(_ptr, other._ptr);
return *this;
}
T *operator->() const { return ptr; }
T *operator->() const {
return _ptr;
}
T &operator*() const { return *ptr; }
T &operator*() const {
return *_ptr;
}
T *get() const noexcept { return ptr; }
T *get() const noexcept {
return _ptr;
}
[[nodiscard]] int useCount() const { return *uses; }
[[nodiscard]] int useCount() const {
if (!_base) return 0;
return _base->_uses.load()._uses_obj;
}
template<typename Tgt, template<class> class Ptr, typename Orig>
friend Ptr<Tgt> static_ptr_cast(const Ptr<Orig> &ptr);
private:
T *ptr = nullptr;
std::atomic<int> *uses = nullptr;
template<typename U>
friend class WeakPtr;
explicit SharedPtr(T *ptr, SharedPtr_Base *base) : _ptr(ptr), _base(base) {}
void unref() {
if (!_base) return;
if (_base->strong_release())
delete _ptr;
_ptr = nullptr;
_base = nullptr;
}
T *_ptr = nullptr;
SharedPtr_Base *_base = nullptr;
};
template<typename T>
class WeakPtr {
public:
WeakPtr() = default;
WeakPtr(const SharedPtr<T> &shared) : _base(shared._base), _ptr(shared._ptr) { _base->weak_lock(); }
WeakPtr(std::nullptr_t a_nullptr) : _ptr(nullptr), _base(nullptr) {}
~WeakPtr() {
unref();
}
WeakPtr(WeakPtr const &other) : _base(other._base), _ptr(other._ptr) {
if (!_base) return;
_base->weak_lock();
}
WeakPtr(WeakPtr &&other) {
unref();
_base = other._base;
_ptr = other._ptr;
other._base = nullptr;
other._ptr = nullptr;
}
WeakPtr &operator=(WeakPtr other) {
std::swap(_ptr, other._ptr);
std::swap(_base, other._base);
return *this;
}
std::optional<SharedPtr<T>> lock() {
if (!_base) return std::nullopt;
if (_base->strong_lock())
return SharedPtr(_ptr, _base);
else
return std::nullopt;
}
[[nodiscard]] int expired() const {
if (!_base) return true;
return _base->_uses.load()._uses_obj <= 0;
}
template<typename Tgt, template<class> class Ptr, typename Orig>
friend Ptr<Tgt> static_ptr_cast(const Ptr<Orig> &ptr);
private:
void unref() {
if (!_base) return;
_base->weak_release();
_base = nullptr;
_ptr = nullptr;
}
T *_ptr = nullptr;
SharedPtr_Base *_base = nullptr;
};
template<typename Tgt, template<class> class Ptr, typename Orig>
static Ptr<Tgt> static_ptr_cast(const Ptr<Orig> &ptr) {
static_assert(std::is_convertible_v<Orig *, Tgt *> || std::is_base_of_v<Orig, Tgt>);
if constexpr (std::is_same_v<Ptr<Tgt>, SharedPtr<Tgt>>) {
ptr._base->strong_lock();
} else if constexpr (std::is_same_v<Ptr<Tgt>, WeakPtr<Tgt>>) {
ptr._base->weak_lock();
} else {
static_assert(false);
}
return Ptr<Tgt>(static_cast<Tgt *>(ptr._ptr), ptr._base);
}
class COWTester;
template<typename T>

View File

@@ -11,4 +11,6 @@ target_sources(kernel.elf PRIVATE
FDT.cpp
VFSGlobals.cpp
File.cpp
PipeFs.cpp
TtyPipe.cpp
)

View File

@@ -7,12 +7,13 @@
#include "File.hpp"
#include "MountTable.hpp"
#include "PointersCollection.hpp"
#include "TtyPipe.hpp"
#include "VFSApi.hpp"
#include "VFSGlobals.hpp"
#include "paging.hpp"
FDT::FD FDT::open(const Path &p, FileOpts opts) {
if (auto n = VFSGlobals::root.traverse(p)) {
if (auto n = VFSGlobals::root.traverse(p); n.get() != nullptr) {
LockGuard l(_mtx);
_files.add(_cur_fd++, UniquePtr<File>(new File(n, opts)));
return _cur_fd - 1;
@@ -44,6 +45,10 @@ File *FDT::get(FDT::FD fd) const {
FDT *FDT::current() {
return Scheduler::cur_task()->_addressSpace->getFdt();
}
FDT::FDT() {
_files.add(0, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDONLY)));
_files.add(1, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDWR)));
}
FDHandle::FDHandle(FDT::FD fd) : _fd(fd) {
}
FDHandle::~FDHandle() {

View File

@@ -14,6 +14,8 @@
class FDT {
public:
FDT();
using FD = int64_t;
FD open(const Path &p, FileOpts opts);
void close(FD fd);

View File

@@ -4,23 +4,25 @@
#include "File.hpp"
#include <utility>
#include "Node.hpp"
File::File(Node *node, FileOpts opts) : _n(node), _opts(opts) {
File::File(SharedPtr<Node> node, FileOpts opts) : _n(std::move(node)), _opts(opts) {
if (opts & FileOpts::O_WRONLY)
assert(opts & FileOpts::O_RDONLY);
}
File::~File() {
}
Node *File::node() {
SharedPtr<Node> File::node() const {
return _n;
}
NodeDir *File::dir() {
if (_n && _n->type() == Node::DIR) return static_cast<NodeDir *>(_n);
SharedPtr<NodeDir> File::dir() const {
if (_n.get() && _n->type() == Node::DIR) return static_ptr_cast<NodeDir>(_n);
return nullptr;
}
NodeFile *File::file() const {
if (_n && _n->type() == Node::FILE) return static_cast<NodeFile *>(_n);
SharedPtr<NodeFile> File::file() const {
if (_n.get() && _n->type() == Node::FILE) return static_ptr_cast<NodeFile>(_n);
return nullptr;
}
uint64_t File::seek(uint64_t pos) {
@@ -28,7 +30,7 @@ uint64_t File::seek(uint64_t pos) {
return pos;
}
uint64_t File::read(char *buf, uint64_t size) {
if (file()) {
if (file().get() != nullptr) {
file()->read(buf, _pos, size);
_pos += size;
return size;
@@ -36,12 +38,12 @@ uint64_t File::read(char *buf, uint64_t size) {
}
uint64_t File::write(const char *buf, uint64_t size) {
if (!(_opts & FileOpts::O_WRONLY)) return -1;
if (file()) {
if (file().get() != nullptr) {
file()->write(buf, _pos, size);
_pos += size;
return size;
}
}
uint64_t File::size() {
if (file()) return file()->size();
if (file().get() != nullptr) return file()->size();
}

View File

@@ -6,6 +6,8 @@
#define FICUS_FILE_HPP
#include "FileOpts.h"
#include "PointersCollection.hpp"
#include <cstdint>
class Node;
@@ -14,24 +16,24 @@ class NodeFile;
class File {
public:
File(Node *n, FileOpts opts);
File(SharedPtr<Node> n, FileOpts opts);
~File();
File(const File &f) = delete;
File &operator=(const File &o) = delete;
File(const File &f) = delete;
File &operator=(const File &o) = delete;
Node *node();
NodeDir *dir();
NodeFile *file() const;
SharedPtr<Node> node() const;
SharedPtr<NodeDir> dir() const;
SharedPtr<NodeFile> file() const;
uint64_t seek(uint64_t pos);
uint64_t read(char *buf, uint64_t size);
uint64_t write(const char *buf, uint64_t size);
uint64_t size();
uint64_t seek(uint64_t pos);
uint64_t read(char *buf, uint64_t size);
uint64_t write(const char *buf, uint64_t size);
uint64_t size();
private:
Node *const _n;
uint64_t _pos = 0;
FileOpts _opts;
SharedPtr<Node> _n;
uint64_t _pos = 0;
FileOpts _opts;
};
#endif //FICUS_FILE_HPP

View File

@@ -5,28 +5,27 @@
#include "MemFs.hpp"
#include "LockGuard.hpp"
Vector<Node *> MemFs::MemFsNodeDir::children() {
LockGuard l(_lock);
Vector<SharedPtr<Node>> MemFs::MemFsNodeDir::children() {
LockGuard l(_lock);
Vector<Node *> out;
Vector<SharedPtr<Node>> out;
for (auto c: _children) {
out.emplace_back(c.data);
}
return out;
}
NodeDir *MemFs::MemFsNodeDir::mkdir(const String &name) {
SharedPtr<NodeDir> MemFs::MemFsNodeDir::mkdir(const String &name) {
LockGuard l(_lock);
auto newnode = new MemFsNodeDir();
newnode->_name = name;
_children.add(name, newnode);
return newnode;
auto newnode = MemFsNodeDir::create(name);
_children.add(name, static_ptr_cast<Node>(newnode));
return static_ptr_cast<NodeDir>(newnode);
}
NodeFile *MemFs::MemFsNodeDir::mkfile(const String &name) {
SharedPtr<NodeFile> MemFs::MemFsNodeDir::mkfile(const String &name) {
LockGuard l(_lock);
auto newfile = new MemFsNodeFile(name);
_children.add(name, newfile);
return newfile;
auto newfile = MemFsNodeFile::create(name);
_children.add(name, static_ptr_cast<Node>(newfile));
return static_ptr_cast<NodeFile>(newfile);
}
bool MemFs::MemFsNodeFile::read(char *buf, size_t start, size_t num) {
LockGuard l(_lock);

View File

@@ -14,33 +14,46 @@
class MemFs : public Filesystem {
struct MemFsNodeDir : public NodeDir {
public:
Vector<Node *> children() override;
NodeDir *mkdir(const String &name) override;
NodeFile *mkfile(const String &name) override;
Vector<SharedPtr<Node>> children() override;
SharedPtr<NodeDir> mkdir(const String &name) override;
SharedPtr<NodeFile> mkfile(const String &name) override;
static SharedPtr<MemFsNodeDir> create(const String &name) {
auto shared = SharedPtr(new MemFsNodeDir(name));
shared->_self_weak = static_ptr_cast<Node>(shared);
return shared;
}
private:
SkipList<String, Node *> _children;
MemFsNodeDir(const String &name) { _name = name; }
SkipList<String, SharedPtr<Node>> _children;
};
struct MemFsNodeFile : public NodeFile {
public:
MemFsNodeFile(const String &name) { _name = name; }
bool read(char *buf, size_t start, size_t num) override;
bool write(const char *buf, size_t start, size_t num) override;
size_t size() override;
bool is_tty() override { return false; }
bool read(char *buf, size_t start, size_t num) override;
bool write(const char *buf, size_t start, size_t num) override;
size_t size() override;
static SharedPtr<MemFsNodeFile> create(const String &name) {
auto shared = SharedPtr(new MemFsNodeFile(name));
shared->_self_weak = static_ptr_cast<Node>(shared);
return shared;
}
private:
MemFsNodeFile(const String &name) { _name = name; }
Vector<uint8_t> _bytes;
};
public:
MemFs(NodeDir *mounted_on) : Filesystem(mounted_on) {}
NodeDir *root() override { return &_rootNode; }
NodeDir *root() override { return _rootNode.get(); }
private:
MemFsNodeDir _rootNode;
SharedPtr<MemFsNodeDir> _rootNode = MemFsNodeDir::create("");
};

View File

@@ -8,24 +8,25 @@
#include "Filesystem.hpp"
Node::~Node() = default;
Node *Node::traverse(const Path &path) {
NodeDir &nodeDir = static_cast<NodeDir &>(*this);
SharedPtr<Node> Node::traverse(const Path &path) {
Filesystem *mnt;
{
LockGuard l(_lock);
mnt = nodeDir._mount;
mnt = _mount;
}
if (mnt) return mnt->root()->traverse(path);
if (path.empty()) {
return this;
auto ret = _self_weak.lock();
assert(ret != std::nullopt);
return *ret;
}
if (type() == DIR) {
// Horribly inefficient
auto children = nodeDir.children();
auto children = static_cast<NodeDir *>(this)->children();
for (size_t i = 0; i < children.size(); i++) {
if (children[i]->name() == path[0]) {
return children[i]->traverse(path.subvector(1, path.size()));

View File

@@ -5,6 +5,8 @@
#ifndef FICUS_NODE_HPP
#define FICUS_NODE_HPP
#include <utility>
#include "List.hpp"
#include "LockGuard.hpp"
#include "String.hpp"
@@ -28,7 +30,7 @@ public:
LockGuard l(_lock);
return _name;
}
virtual Node *traverse(const Path &path);
virtual SharedPtr<Node> traverse(const Path &path);
protected:
Node(Type type) : _type(type) {}
@@ -40,16 +42,17 @@ protected:
String _name;
Filesystem *_mount = nullptr;
WeakPtr<Node> _self_weak = nullptr;
};
class NodeFile;
class NodeDir : public Node {
public:
virtual Vector<Node *> children() = 0;
virtual NodeDir *mkdir(const String &name) = 0;
virtual NodeFile *mkfile(const String &name) = 0;
virtual void set_mounted(Filesystem *mount);
virtual Vector<SharedPtr<Node>> children() = 0;
virtual SharedPtr<NodeDir> mkdir(const String &name) = 0;
virtual SharedPtr<NodeFile> mkfile(const String &name) = 0;
virtual void set_mounted(Filesystem *mount);
protected:
NodeDir() : Node(Type::DIR) {}
@@ -60,6 +63,7 @@ public:
virtual bool read(char *buf, size_t start, size_t num) = 0;
virtual bool write(const char *buf, size_t start, size_t num) = 0;
virtual size_t size() = 0;
virtual bool is_tty() = 0;
protected:
NodeFile() : Node(Type::FILE) {}

View File

@@ -0,0 +1,5 @@
//
// Created by Stepan Usatiuk on 05.04.2024.
//
#include "PipeFs.hpp"

13
src/kernel/vfs/PipeFs.hpp Normal file
View File

@@ -0,0 +1,13 @@
//
// Created by Stepan Usatiuk on 05.04.2024.
//
#ifndef FICUS_PIPEFS_HPP
#define FICUS_PIPEFS_HPP
class PipeFs {
};
#endif //FICUS_PIPEFS_HPP

View File

@@ -0,0 +1,29 @@
//
// Created by Stepan Usatiuk on 05.04.2024.
//
#include "TtyPipe.hpp"
#include "TtyManager.hpp"
bool TtyPipe::read(char *buf, size_t start, size_t num) {
auto c = buf;
while ((c - buf) < num) {
*c = GlobalTtyManager.get_tty(0)->readchar();
if (*c == '\r') {
*(c++) = '\n';
break;
}
c++;
}
return (c - buf);
}
bool TtyPipe::write(const char *buf, size_t start, size_t num) {
auto c = buf;
while (*c != '\0' && (c - buf) < num) {
GlobalTtyManager.all_tty_putchar(*c);
c++;
}
return num;
}
size_t TtyPipe::size() {
return 0;
}

View File

@@ -0,0 +1,28 @@
//
// Created by Stepan Usatiuk on 05.04.2024.
//
#ifndef FICUS_TTYPIPE_HPP
#define FICUS_TTYPIPE_HPP
#include "Node.hpp"
class TtyPipe : public NodeFile {
public:
bool read(char *buf, size_t start, size_t num) override;
bool write(const char *buf, size_t start, size_t num) override;
size_t size() override;
bool is_tty() override { return true; }
static SharedPtr<TtyPipe> create() {
auto shared = SharedPtr(new TtyPipe());
shared->_self_weak = static_ptr_cast<Node>(shared);
return shared;
}
private:
TtyPipe() = default;
};
#endif //FICUS_TTYPIPE_HPP

View File

@@ -12,7 +12,7 @@ bool VFSApi::mkdir(const Path &path) {
FDHandle root_fd = FDHandle(FDT::current()->open(root, O_RDWR));
if (root_fd.get() == -1) return false;
File *root_f = FDT::current()->get(root_fd.get());
if (!root_f->dir()) return false;
if (root_f->dir().get() == nullptr) return false;
root_f->dir()->mkdir(path.back());
return true;
}
@@ -21,7 +21,7 @@ bool VFSApi::touch(const Path &path) {
FDHandle root_fd = FDHandle(FDT::current()->open(root, O_RDWR));
if (root_fd.get() == -1) return false;
File *root_f = FDT::current()->get(root_fd.get());
if (!root_f->dir()) return false;
if (root_f->dir().get() == nullptr) return false;
root_f->dir()->mkfile(path.back());
return true;
}

View File

@@ -3,15 +3,15 @@
//
#include "VFSGlobals.hpp"
Vector<Node *> RootNode::children() {
Vector<SharedPtr<Node>> RootNode::children() {
assert(false);
return {};
}
NodeDir *RootNode::mkdir(const String &name) {
SharedPtr<NodeDir> RootNode::mkdir(const String &name) {
assert(false);
return nullptr;
}
NodeFile *RootNode::mkfile(const String &name) {
SharedPtr<NodeFile> RootNode::mkfile(const String &name) {
assert(false);
return nullptr;
}

View File

@@ -10,9 +10,9 @@
class RootNode : public NodeDir {
public:
Vector<Node *> children() override;
NodeDir *mkdir(const String &name) override;
NodeFile *mkfile(const String &name) override;
Vector<SharedPtr<Node>> children() override;
SharedPtr<NodeDir> mkdir(const String &name) override;
SharedPtr<NodeFile> mkfile(const String &name) override;
};
namespace VFSGlobals {