mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 19:38:12 +00:00
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.
This commit is contained in:
parent
9454c5dd52
commit
f7cc454162
8 changed files with 121 additions and 29 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
if (m_flash_flush)
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
#endif
|
||||
|
||||
for (int y = 0; y < rect.height(); ++y) {
|
||||
fast_dword_copy(front_ptr, back_ptr, rect.width());
|
||||
|
|
|
@ -94,4 +94,6 @@ private:
|
|||
OwnPtr<Painter> m_front_painter;
|
||||
|
||||
mutable Lock m_lock;
|
||||
|
||||
bool m_flash_flush { false };
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue