diff --git a/AK/DoublyLinkedList.h b/AK/DoublyLinkedList.h index a5a72562d6b..31f506626f4 100644 --- a/AK/DoublyLinkedList.h +++ b/AK/DoublyLinkedList.h @@ -8,7 +8,7 @@ template class DoublyLinkedList { private: struct Node { - explicit Node(T&& v) : value(v) { } + explicit Node(T&& v) : value(move(v)) { } T value; Node* next { nullptr }; Node* prev { nullptr }; @@ -62,7 +62,8 @@ public: class Iterator { public: - bool operator!=(const Iterator& other) { return m_node != other.m_node; } + bool operator!=(const Iterator& other) const { return m_node != other.m_node; } + bool operator==(const Iterator& other) const { return m_node == other.m_node; } Iterator& operator++() { m_node = m_node->next; return *this; } T& operator*() { return m_node->value; } bool isEnd() const { return !m_node; } @@ -78,7 +79,8 @@ public: class ConstIterator { public: - bool operator!=(const ConstIterator& other) { return m_node != other.m_node; } + bool operator!=(const ConstIterator& other) const { return m_node != other.m_node; } + bool operator==(const ConstIterator& other) const { return m_node == other.m_node; } ConstIterator& operator++() { m_node = m_node->next; return *this; } const T& operator*() const { return m_node->value; } bool isEnd() const { return !m_node; } diff --git a/AK/HashTable.h b/AK/HashTable.h index df3caac0d6b..b91020f54fc 100644 --- a/AK/HashTable.h +++ b/AK/HashTable.h @@ -56,7 +56,7 @@ public: class Iterator { public: - bool operator!=(const Iterator& other) + bool operator!=(const Iterator& other) const { if (m_isEnd && other.m_isEnd) return false; @@ -65,6 +65,7 @@ public: || m_bucketIndex != other.m_bucketIndex || m_bucketIterator != other.m_bucketIterator; } + bool operator==(const Iterator& other) const { return !(*this != other); } T& operator*() { #ifdef HASHTABLE_DEBUG @@ -126,12 +127,12 @@ public: typename DoublyLinkedList::Iterator m_bucketIterator; }; - Iterator begin() { return Iterator(*this, false); } + Iterator begin() { return Iterator(*this, isEmpty()); } Iterator end() { return Iterator(*this, true); } class ConstIterator { public: - bool operator!=(const ConstIterator& other) + bool operator!=(const ConstIterator& other) const { if (m_isEnd && other.m_isEnd) return false; @@ -140,6 +141,7 @@ public: || m_bucketIndex != other.m_bucketIndex || m_bucketIterator != other.m_bucketIterator; } + bool operator==(const ConstIterator& other) const { return !(*this != other); } const T& operator*() const { #ifdef HASHTABLE_DEBUG @@ -203,7 +205,7 @@ public: typename DoublyLinkedList::ConstIterator m_bucketIterator; }; - ConstIterator begin() const { return ConstIterator(*this, false); } + ConstIterator begin() const { return ConstIterator(*this, isEmpty()); } ConstIterator end() const { return ConstIterator(*this, true); } Iterator find(const T&); diff --git a/AK/OwnPtr.h b/AK/OwnPtr.h index 482b628e083..24c92642a04 100644 --- a/AK/OwnPtr.h +++ b/AK/OwnPtr.h @@ -2,6 +2,7 @@ #include "StdLib.h" #include "Types.h" +#include "Traits.h" namespace AK { @@ -96,6 +97,12 @@ make(Args&&... args) return OwnPtr(new T(forward(args)...)); } +template +struct Traits> { + static unsigned hash(const OwnPtr& p) { return (unsigned)p.ptr(); } + static void dump(const OwnPtr& p) { kprintf("%p", p.ptr()); } +}; + } using AK::OwnPtr; diff --git a/AK/Vector.h b/AK/Vector.h index 959b5c9b023..7c258eb6590 100644 --- a/AK/Vector.h +++ b/AK/Vector.h @@ -12,11 +12,12 @@ template class VectorImpl { public: ~VectorImpl() { } - static OwnPtr create(size_t capacity) + static VectorImpl* create(size_t capacity) { size_t size = sizeof(VectorImpl) + sizeof(T) * capacity; void* slot = kmalloc(size); - return OwnPtr(new (slot) VectorImpl(capacity)); + new (slot) VectorImpl(capacity); + return (VectorImpl*)slot; } size_t size() const { return m_size; } @@ -59,14 +60,17 @@ public: ~Vector() { clear(); } Vector(Vector&& other) - : m_impl(move(other.m_impl)) + : m_impl(other.m_impl) { + other.m_impl = nullptr; } Vector& operator=(Vector&& other) { - if (this != &other) - m_impl = move(other.m_impl); + if (this != &other) { + m_impl = other.m_impl; + other.m_impl = nullptr; + } return *this; } @@ -75,6 +79,7 @@ public: for (size_t i = 0; i < size(); ++i) { at(i).~T(); } + kfree(m_impl); m_impl = nullptr; } @@ -134,8 +139,9 @@ public: new (newImpl->slot(i)) T(move(m_impl->at(i))); m_impl->at(i).~T(); } + kfree(m_impl); } - m_impl = move(newImpl); + m_impl = newImpl; } class Iterator { @@ -174,7 +180,7 @@ private: return max(size_t(4), capacity + (capacity / 4) + 4); } - OwnPtr> m_impl; + VectorImpl* m_impl { nullptr }; }; } diff --git a/AK/kmalloc.h b/AK/kmalloc.h index 24f48f376fb..0ade91659a4 100644 --- a/AK/kmalloc.h +++ b/AK/kmalloc.h @@ -1,5 +1,7 @@ #pragma once +#include "Compiler.h" + #ifdef SERENITY #ifdef USERLAND #include diff --git a/AK/test.cpp b/AK/test.cpp index d017990d001..a181da2c4da 100644 --- a/AK/test.cpp +++ b/AK/test.cpp @@ -16,6 +16,26 @@ static void testWeakPtr(); int main(int, char**) { StringImpl::initializeGlobals(); + + { + struct entry { + String s; + }; + + HashMap tab; + tab.set(1, { "one" }); + tab.set(2, { "two" }); + tab.set(3, { "three" }); + tab.set(4, { "four" }); + tab.remove(1); + tab.remove(2); + tab.remove(3); + for (auto& it : tab) { + printf("%s\n", it.value.s.characters()); + } + return 0; + } + { CircularQueue queue; queue.dump(); diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index d6aa99bbc28..cbe119a5ac7 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -1,6 +1,14 @@ #include "ProcFileSystem.h" #include "Task.h" +static ProcFileSystem* s_the; + +ProcFileSystem& ProcFileSystem::the() +{ + ASSERT(s_the); + return *s_the; +} + RetainPtr ProcFileSystem::create() { return adopt(*new ProcFileSystem); @@ -8,15 +16,56 @@ RetainPtr ProcFileSystem::create() ProcFileSystem::ProcFileSystem() { + s_the = this; } ProcFileSystem::~ProcFileSystem() { } +void ProcFileSystem::addProcess(Task& task) +{ + ASSERT_INTERRUPTS_DISABLED(); + char buf[16]; + ksprintf(buf, "%d", task.pid()); + auto dir = addFile(createDirectory(buf)); + m_pid2inode.set(task.pid(), dir.index()); + addFile(createGeneratedFile("vm", [&task] { + InterruptDisabler disabler; + char* buffer; + auto stringImpl = StringImpl::createUninitialized(80 + task.regionCount() * 80, buffer); + memset(buffer, 0, stringImpl->length()); + char* ptr = buffer; + ptr += ksprintf(ptr, "BEGIN END SIZE NAME\n"); + for (auto& region : task.regions()) { + ptr += ksprintf(ptr, "%x -- %x %x %s\n", + region->linearAddress.get(), + region->linearAddress.offset(region->size - 1).get(), + region->size, + region->name.characters()); + } + *ptr = '\0'; + return ByteBuffer::copy((byte*)buffer, ptr - buffer); + }), dir.index()); +} + +void ProcFileSystem::removeProcess(Task& task) +{ + ASSERT_INTERRUPTS_DISABLED(); + auto pid = task.pid(); + auto it = m_pid2inode.find(pid); + ASSERT(it != m_pid2inode.end()); + bool success = removeFile((*it).value); + ASSERT(success); + m_pid2inode.remove(pid); +} + bool ProcFileSystem::initialize() { SyntheticFileSystem::initialize(); + + auto d = addFile(createDirectory("sys")); + addFile(createGeneratedFile("summary", [] { InterruptDisabler disabler; auto tasks = Task::allTasks(); diff --git a/Kernel/ProcFileSystem.h b/Kernel/ProcFileSystem.h index 68d8d04a689..f7602cc20f5 100644 --- a/Kernel/ProcFileSystem.h +++ b/Kernel/ProcFileSystem.h @@ -3,15 +3,24 @@ #include #include +class Task; + class ProcFileSystem final : public SyntheticFileSystem { public: + static ProcFileSystem& the(); + virtual ~ProcFileSystem() override; static RetainPtr create(); virtual bool initialize() override; virtual const char* className() const override; + void addProcess(Task&); + void removeProcess(Task&); + private: ProcFileSystem(); + + HashMap m_pid2inode; }; diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 5a64e76fc7b..15b407d6750 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -12,6 +12,7 @@ #include "errno.h" #include "i8253.h" #include "RTC.h" +#include "ProcFileSystem.h" //#define DEBUG_IO //#define TASK_DEBUG @@ -397,11 +398,14 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring) // HACK: Ring2 SS in the TSS is the current PID. m_tss.ss2 = m_pid; m_farPtr.offset = 0x98765432; + + ProcFileSystem::the().addProcess(*this); } Task::~Task() { InterruptDisabler disabler; + ProcFileSystem::the().removeProcess(*this); system.nprocess--; delete [] m_ldtEntries; m_ldtEntries = nullptr; diff --git a/Kernel/Task.h b/Kernel/Task.h index b58b139c0cf..4a1e5fe1645 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -15,6 +15,7 @@ class Zone; class Task : public InlineLinkedListNode { friend class InlineLinkedListNode; + class Region; public: static Task* createKernelTask(void (*entry)(), String&& name); static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr); @@ -110,6 +111,8 @@ public: static void taskDidCrash(Task*); + size_t regionCount() const { return m_regions.size(); } + const Vector>& regions() const { return m_regions; } void dumpRegions(); void didSchedule() { ++m_timesScheduled; } diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 5d37ef78778..0880d104192 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -108,9 +108,7 @@ static void init_stage2() vfs->mountRoot(e2fs.copyRef()); - auto procfs = ProcFileSystem::create(); - procfs->initialize(); - vfs->mount(procfs.copyRef(), "/proc"); + vfs->mount(ProcFileSystem::the(), "/proc"); #endif @@ -200,6 +198,9 @@ void init() kprintf("%u kB base memory\n", base_memory); kprintf("%u kB extended memory\n", ext_memory); + auto procfs = ProcFileSystem::create(); + procfs->initialize(); + Task::initialize(); Task::createKernelTask(undertaker_main, "undertaker"); diff --git a/VirtualFileSystem/FileHandle.cpp b/VirtualFileSystem/FileHandle.cpp index 5aa8c541153..c1a67dfe252 100644 --- a/VirtualFileSystem/FileHandle.cpp +++ b/VirtualFileSystem/FileHandle.cpp @@ -133,7 +133,7 @@ bool FileHandle::isDirectory() const return m_vnode->metadata().isDirectory(); } -ssize_t FileHandle::get_dir_entries(byte* buffer, size_t size) +ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size) { Locker locker(VirtualFileSystem::lock()); diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 8d1cb9b8522..0943949475f 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -21,21 +21,36 @@ bool SyntheticFileSystem::initialize() // Add a File for the root directory. // FIXME: This needs work. auto rootDir = make(); - rootDir->metadata.inode = { id(), 1 }; + rootDir->metadata.inode = { id(), RootInodeIndex }; + rootDir->parent = { id(), RootInodeIndex }; rootDir->metadata.mode = 0040555; rootDir->metadata.uid = 0; rootDir->metadata.gid = 0; rootDir->metadata.size = 0; rootDir->metadata.mtime = mepoch; - m_files.append(move(rootDir)); + m_inodes.set(RootInodeIndex, move(rootDir)); +#if 0 #ifndef SERENITY addFile(createTextFile("file", "I'm a synthetic file!\n")); addFile(createTextFile("message", "Hey! This isn't my bottle!\n")); +#endif #endif return true; } +auto SyntheticFileSystem::createDirectory(String&& name) -> OwnPtr +{ + auto file = make(); + file->name = move(name); + file->metadata.size = 0; + file->metadata.uid = 0; + file->metadata.gid = 0; + file->metadata.mode = 0040555; + file->metadata.mtime = mepoch; + return file; +} + auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr { auto file = make(); @@ -44,7 +59,7 @@ auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr file->metadata.size = file->data.size(); file->metadata.uid = 100; file->metadata.gid = 200; - file->metadata.mode = 0100644; + file->metadata.mode = 04; file->metadata.mtime = mepoch; return file; } @@ -62,11 +77,42 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function&& file) +InodeIdentifier SyntheticFileSystem::addFile(OwnPtr&& file, InodeIndex parent) { ASSERT(file); - file->metadata.inode = { id(), m_files.size() + 1 }; - m_files.append(move(file)); + auto it = m_inodes.find(parent); + ASSERT(it != m_inodes.end()); + InodeIdentifier newInode { id(), generateInodeIndex() }; + file->metadata.inode = newInode; + file->parent = { id(), parent }; + (*it).value->children.append(file.ptr()); + m_inodes.set(newInode.index(), move(file)); + return newInode; +} + +bool SyntheticFileSystem::removeFile(InodeIndex inode) +{ + auto it = m_inodes.find(inode); + if (it == m_inodes.end()) + return false; + auto& file = *(*it).value; + + auto pit = m_inodes.find(file.parent.index()); + if (pit == m_inodes.end()) + return false; + auto& parent = *(*pit).value; + for (size_t i = 0; i < parent.children.size(); ++i) { + if (parent.children[i]->metadata.inode.index() != inode) { + continue; + } + parent.children.remove(i); + break; + } + + for (auto& child : file.children) + removeFile(child->metadata.inode.index()); + m_inodes.remove(inode); + return true; } const char* SyntheticFileSystem::className() const @@ -85,14 +131,20 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio #ifdef SYNTHFS_DEBUG kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index()); #endif - if (inode.index() != 1) + + auto it = m_inodes.find(inode.index()); + if (it == m_inodes.end()) + return false; + const File& synInode = *(*it).value; + if (!synInode.metadata.isDirectory()) return false; - callback({ ".", m_files[0]->metadata.inode }); - callback({ "..", m_files[0]->metadata.inode }); + callback({ ".", synInode.metadata.inode }); + callback({ "..", synInode.parent }); - for (unsigned i = 1; i < m_files.size(); ++i) - callback({ m_files[i]->name, m_files[i]->metadata.inode }); + for (auto& child : synInode.children) { + callback({ child->name, child->metadata.inode }); + } return true; } @@ -102,10 +154,11 @@ InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const #ifdef SYNTHFS_DEBUG kprintf("[synthfs] inodeMetadata(%u)\n", inode.index()); #endif - if (inode.index() == 0 || inode.index() > m_files.size()) - return InodeMetadata(); - auto& file = *m_files[inode.index() - 1]; - return file.metadata; + + auto it = m_inodes.find(inode.index()); + if (it == m_inodes.end()) + return { }; + return (*it).value->metadata; } bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp) @@ -120,6 +173,7 @@ InodeIdentifier SyntheticFileSystem::createInode(InodeIdentifier parentInode, co (void) parentInode; (void) name; (void) mode; + (void) size; kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n"); return { }; } @@ -136,12 +190,13 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o #ifdef SYNTHFS_DEBUG kprintf("[synthfs] readInode %u\n", inode.index()); #endif - ASSERT(inode.index() != 1); - ASSERT(inode.index() <= m_files.size()); ASSERT(offset >= 0); ASSERT(buffer); - - auto& file = *m_files[inode.index() - 1]; +\ + auto it = m_inodes.find(inode.index()); + if (it == m_inodes.end()) + return false; + const File& file = *(*it).value; ByteBuffer generatedData; if (file.generator) generatedData = file.generator(); @@ -154,6 +209,13 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o InodeIdentifier SyntheticFileSystem::makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) { + (void) parentInode; + (void) name; kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n"); return { }; } + +auto SyntheticFileSystem::generateInodeIndex() -> InodeIndex +{ + return m_nextInodeIndex++; +} diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index 419ea647a9b..dc129caf567 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -21,21 +21,31 @@ public: virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; protected: + typedef unsigned InodeIndex; + + InodeIndex generateInodeIndex(); + static constexpr InodeIndex RootInodeIndex = 1; + SyntheticFileSystem(); struct File { String name; InodeMetadata metadata; + InodeIdentifier parent; ByteBuffer data; Function generator; + Vector children; }; + OwnPtr createDirectory(String&& name); OwnPtr createTextFile(String&& name, String&& text); OwnPtr createGeneratedFile(String&& name, Function&&); - void addFile(OwnPtr&&); + InodeIdentifier addFile(OwnPtr&&, InodeIndex parent = RootInodeIndex); + bool removeFile(InodeIndex); private: - Vector> m_files; + InodeIndex m_nextInodeIndex { 2 }; + HashMap> m_inodes; }; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index 0cb6eb83af6..ba60b8d4eac 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -52,6 +52,7 @@ VirtualFileSystem::VirtualFileSystem() VirtualFileSystem::~VirtualFileSystem() { kprintf("[VFS] ~VirtualFileSystem with %u nodes allocated\n", allocatedNodeCount()); + // FIXME: m_nodes is never freed. Does it matter though? } auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr