Ver Fonte

Add mechanism to expose kernel variables to userspace via ProcFS.

Only booleans are supported at first. More types can be added easily.
Use this to add /proc/sys/wm_flash_flush which when enabled flashes pending
screen flush rects in yellow before they happen.
Andreas Kling há 6 anos atrás
pai
commit
f7cc454162

+ 2 - 1
Kernel/MemoryManager.h

@@ -15,6 +15,7 @@
 
 class Process;
 extern Process* current;
+class SynthFSInode;
 
 enum class PageFaultResponse {
     ShouldCrash,
@@ -166,7 +167,7 @@ class MemoryManager {
     friend class PhysicalPage;
     friend class Region;
     friend class VMObject;
-    friend ByteBuffer procfs$mm();
+    friend ByteBuffer procfs$mm(SynthFSInode&);
 public:
     static MemoryManager& the() PURE;
 

+ 65 - 13
Kernel/ProcFileSystem.cpp

@@ -156,15 +156,15 @@ void ProcFS::add_process(Process& process)
     ksprintf(buf, "%d", process.pid());
     auto dir = add_file(create_directory(buf));
     m_pid2inode.set(process.pid(), dir.index());
-    add_file(create_generated_file("vm", [&process] { return procfs$pid_vm(process); }), dir.index());
-    add_file(create_generated_file("vmo", [&process] { return procfs$pid_vmo(process); }), dir.index());
-    add_file(create_generated_file("stack", [&process] { return procfs$pid_stack(process); }), dir.index());
-    add_file(create_generated_file("regs", [&process] { return procfs$pid_regs(process); }), dir.index());
-    add_file(create_generated_file("fds", [&process] { return procfs$pid_fds(process); }), dir.index());
+    add_file(create_generated_file("vm", [&process] (SynthFSInode&) { return procfs$pid_vm(process); }), dir.index());
+    add_file(create_generated_file("vmo", [&process] (SynthFSInode&) { return procfs$pid_vmo(process); }), dir.index());
+    add_file(create_generated_file("stack", [&process] (SynthFSInode&) { return procfs$pid_stack(process); }), dir.index());
+    add_file(create_generated_file("regs", [&process] (SynthFSInode&) { return procfs$pid_regs(process); }), dir.index());
+    add_file(create_generated_file("fds", [&process] (SynthFSInode&) { return procfs$pid_fds(process); }), dir.index());
     if (process.executable_inode())
-        add_file(create_generated_file("exe", [&process] { return procfs$pid_exe(process); }, 00120777), dir.index());
+        add_file(create_generated_file("exe", [&process] (SynthFSInode&) { return procfs$pid_exe(process); }, 00120777), dir.index());
     if (process.cwd_inode())
-        add_file(create_generated_file("cwd", [&process] { return procfs$pid_cwd(process); }, 00120777), dir.index());
+        add_file(create_generated_file("cwd", [&process] (SynthFSInode&) { return procfs$pid_cwd(process); }, 00120777), dir.index());
 }
 
 void ProcFS::remove_process(Process& process)
@@ -179,7 +179,7 @@ void ProcFS::remove_process(Process& process)
     m_pid2inode.remove(pid);
 }
 
-ByteBuffer procfs$mm()
+ByteBuffer procfs$mm(SynthFSInode&)
 {
     // FIXME: Implement
     InterruptDisabler disabler;
@@ -198,7 +198,7 @@ ByteBuffer procfs$mm()
     return builder.to_byte_buffer();
 }
 
-ByteBuffer procfs$mounts()
+ByteBuffer procfs$mounts(SynthFSInode&)
 {
     InterruptDisabler disabler;
     StringBuilder builder;
@@ -213,7 +213,7 @@ ByteBuffer procfs$mounts()
     return builder.to_byte_buffer();
 }
 
-ByteBuffer procfs$cpuinfo()
+ByteBuffer procfs$cpuinfo(SynthFSInode&)
 {
     StringBuilder builder;
     {
@@ -276,7 +276,7 @@ ByteBuffer procfs$cpuinfo()
     return builder.to_byte_buffer();
 }
 
-ByteBuffer procfs$kmalloc()
+ByteBuffer procfs$kmalloc(SynthFSInode&)
 {
     StringBuilder builder;
     builder.appendf(
@@ -290,7 +290,7 @@ ByteBuffer procfs$kmalloc()
     return builder.to_byte_buffer();
 }
 
-ByteBuffer procfs$summary()
+ByteBuffer procfs$summary(SynthFSInode&)
 {
     InterruptDisabler disabler;
     auto processes = Process::allProcesses();
@@ -313,7 +313,7 @@ ByteBuffer procfs$summary()
     return builder.to_byte_buffer();
 }
 
-ByteBuffer procfs$inodes()
+ByteBuffer procfs$inodes(SynthFSInode&)
 {
     extern HashTable<Inode*>& all_inodes();
     auto& vfs = VFS::the();
@@ -326,6 +326,57 @@ ByteBuffer procfs$inodes()
     return builder.to_byte_buffer();
 }
 
+struct SysVariableData final : public SynthFSInodeCustomData {
+    virtual ~SysVariableData() override { }
+
+    enum Type {
+        Invalid,
+        Boolean,
+    };
+    Type type { Invalid };
+    Function<void()> change_callback;
+    void* address;
+};
+
+static ByteBuffer read_sys_bool(SynthFSInode& inode)
+{
+    ASSERT(inode.custom_data());
+    auto buffer = ByteBuffer::create_uninitialized(2);
+    auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
+    ASSERT(custom_data.type == SysVariableData::Boolean);
+    ASSERT(custom_data.address);
+    buffer[0] = *reinterpret_cast<bool*>(custom_data.address) ? '1' : '0';
+    buffer[1] = '\n';
+    return buffer;
+}
+
+static ssize_t write_sys_bool(SynthFSInode& inode, const ByteBuffer& data)
+{
+    ASSERT(inode.custom_data());
+    if (data.size() >= 1 && (data[0] == '0' || data[0] == '1')) {
+        auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
+        ASSERT(custom_data.address);
+        bool old_value = *reinterpret_cast<bool*>(custom_data.address);
+        bool new_value = data[0] == '1';
+        *reinterpret_cast<bool*>(custom_data.address) = new_value;
+        if (old_value != new_value && custom_data.change_callback)
+            custom_data.change_callback();
+    }
+    return data.size();
+}
+
+void ProcFS::add_sys_bool(String&& name, bool* var, Function<void()>&& change_callback)
+{
+    auto file = create_generated_file(move(name), move(read_sys_bool), move(write_sys_bool));
+    auto data = make<SysVariableData>();
+    data->type = SysVariableData::Boolean;
+    data->change_callback = move(change_callback);
+    data->address = var;
+    file->set_custom_data(move(data));
+    InterruptDisabler disabler;
+    add_file(move(file), m_sys_dir.index());
+}
+
 bool ProcFS::initialize()
 {
     SynthFS::initialize();
@@ -335,6 +386,7 @@ bool ProcFS::initialize()
     add_file(create_generated_file("summary", procfs$summary));
     add_file(create_generated_file("cpuinfo", procfs$cpuinfo));
     add_file(create_generated_file("inodes", procfs$inodes));
+    m_sys_dir = add_file(create_directory("sys"));
     return true;
 }
 

+ 5 - 0
Kernel/ProcFileSystem.h

@@ -18,9 +18,14 @@ public:
     void add_process(Process&);
     void remove_process(Process&);
 
+    void add_sys_file(String&&, Function<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback);
+
+    void add_sys_bool(String&&, bool*, Function<void()>&& change_callback = nullptr);
+
 private:
     ProcFS();
 
     HashMap<pid_t, InodeIndex> m_pid2inode;
+    InodeIdentifier m_sys_dir;
 };
 

+ 4 - 3
VirtualFileSystem/FileDescriptor.cpp

@@ -167,9 +167,10 @@ ssize_t FileDescriptor::write(Process& process, const byte* data, size_t size)
         // FIXME: What should happen to m_currentOffset?
         return m_device->write(process, data, size);
     }
-    // FIXME: Implement non-device writes.
-    ASSERT_NOT_REACHED();
-    return -1;
+    ASSERT(m_inode);
+    ssize_t nwritten = m_inode->write(ByteBuffer::wrap((byte*)data, size));
+    m_current_offset += nwritten;
+    return nwritten;
 }
 
 bool FileDescriptor::can_write(Process& process)

+ 25 - 6
VirtualFileSystem/SyntheticFileSystem.cpp

@@ -69,7 +69,7 @@ RetainPtr<SynthFSInode> SynthFS::create_text_file(String&& name, ByteBuffer&& co
     return file;
 }
 
-RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer()>&& generator, Unix::mode_t mode)
+RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& generator, Unix::mode_t mode)
 {
     auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
     file->m_generator = move(generator);
@@ -82,6 +82,20 @@ RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<B
     return file;
 }
 
+RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback, Unix::mode_t mode)
+{
+    auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
+    file->m_generator = move(read_callback);
+    file->m_write_callback = move(write_callback);
+    file->m_name = move(name);
+    file->m_metadata.size = 0;
+    file->m_metadata.uid = 0;
+    file->m_metadata.gid = 0;
+    file->m_metadata.mode = mode;
+    file->m_metadata.mtime = mepoch;
+    return file;
+}
+
 InodeIdentifier SynthFS::add_file(RetainPtr<SynthFSInode>&& file, InodeIndex parent)
 {
     ASSERT_INTERRUPTS_DISABLED();
@@ -197,10 +211,10 @@ ssize_t SynthFSInode::read_bytes(Unix::off_t offset, size_t count, byte* buffer,
     ByteBuffer generatedData;
     if (m_generator) {
         if (!descriptor) {
-            generatedData = m_generator();
+            generatedData = m_generator(*this);
         } else {
             if (!descriptor->generator_cache())
-                descriptor->generator_cache() = m_generator();
+                descriptor->generator_cache() = m_generator(*this);
             generatedData = descriptor->generator_cache();
         }
     }
@@ -259,10 +273,11 @@ void SynthFSInode::flush_metadata()
 {
 }
 
-bool SynthFSInode::write(const ByteBuffer&)
+bool SynthFSInode::write(const ByteBuffer& data)
 {
-    ASSERT_NOT_REACHED();
-    return false;
+    if (!m_write_callback)
+        return 0; // FIXME: -EPERM?
+    return m_write_callback(*this, data);
 }
 
 bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error)
@@ -274,3 +289,7 @@ bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte
     ASSERT_NOT_REACHED();
     return false;
 }
+
+SynthFSInodeCustomData::~SynthFSInodeCustomData()
+{
+}

+ 13 - 2
VirtualFileSystem/SyntheticFileSystem.h

@@ -28,7 +28,8 @@ protected:
 
     RetainPtr<SynthFSInode> create_directory(String&& name);
     RetainPtr<SynthFSInode> create_text_file(String&& name, ByteBuffer&&, Unix::mode_t = 0010644);
-    RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer()>&&, Unix::mode_t = 0100644);
+    RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Unix::mode_t = 0100644);
+    RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&&, Unix::mode_t = 0100644);
 
     InodeIdentifier add_file(RetainPtr<SynthFSInode>&&, InodeIndex parent = RootInodeIndex);
     bool remove_file(InodeIndex);
@@ -38,11 +39,19 @@ private:
     HashMap<InodeIndex, RetainPtr<SynthFSInode>> m_inodes;
 };
 
+struct SynthFSInodeCustomData {
+    virtual ~SynthFSInodeCustomData();
+};
+
 class SynthFSInode final : public Inode {
     friend class SynthFS;
 public:
     virtual ~SynthFSInode() override;
 
+    void set_custom_data(OwnPtr<SynthFSInodeCustomData>&& custom_data) { m_custom_data = move(custom_data); }
+    SynthFSInodeCustomData* custom_data() { return m_custom_data.ptr(); }
+    const SynthFSInodeCustomData* custom_data() const { return m_custom_data.ptr(); }
+
 private:
     // ^Inode
     virtual ssize_t read_bytes(Unix::off_t, size_t, byte* buffer, FileDescriptor*) override;
@@ -62,9 +71,11 @@ private:
     String m_name;
     InodeIdentifier m_parent;
     ByteBuffer m_data;
-    Function<ByteBuffer()> m_generator;
+    Function<ByteBuffer(SynthFSInode&)> m_generator;
+    Function<ssize_t(SynthFSInode&, const ByteBuffer&)> m_write_callback;
     Vector<SynthFSInode*> m_children;
     InodeMetadata m_metadata;
+    OwnPtr<SynthFSInodeCustomData> m_custom_data;
 };
 
 inline SynthFS& SynthFSInode::fs()

+ 5 - 4
WindowServer/WSWindowManager.cpp

@@ -4,11 +4,11 @@
 #include "WSEventLoop.h"
 #include "Process.h"
 #include "MemoryManager.h"
+#include <Kernel/ProcFileSystem.h>
 #include <Widgets/Painter.h>
 #include <Widgets/CharacterBitmap.h>
 #include <AK/StdLibExtras.h>
 
-//#define DEBUG_FLUSH_YELLOW
 //#define DEBUG_COUNTERS
 
 static const int windowTitleBarHeight = 16;
@@ -130,6 +130,8 @@ WSWindowManager::WSWindowManager()
     m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17);
     m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17);
 
+    ProcFS::the().add_sys_bool("wm_flash_flush", &m_flash_flush);
+
     invalidate();
     compose();
 }
@@ -444,9 +446,8 @@ void WSWindowManager::flush(const Rect& a_rect)
     const RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
     size_t pitch = m_back_bitmap->pitch();
 
-#ifdef DEBUG_FLUSH_YELLOW
-    m_front_painter->fill_rect(rect, Color::Yellow);
-#endif
+    if (m_flash_flush)
+        m_front_painter->fill_rect(rect, Color::Yellow);
 
     for (int y = 0; y < rect.height(); ++y) {
         fast_dword_copy(front_ptr, back_ptr, rect.width());

+ 2 - 0
WindowServer/WSWindowManager.h

@@ -94,4 +94,6 @@ private:
     OwnPtr<Painter> m_front_painter;
 
     mutable Lock m_lock;
+
+    bool m_flash_flush { false };
 };