mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 05:32:44 +00:00 
			
		
		
		
	Kernel: Rewrite ProcFS.
Now the filesystem is generated on-the-fly instead of manually adding and removing inodes as processes spawn and die. The code is convoluted and bloated as I wrote it while sleepless. However, it's still vastly better than the old ProcFS, so I'm committing it. I also added /proc/PID/fd/N symlinks for each of a process's open fd's.
This commit is contained in:
		
							parent
							
								
									ab56f36bfb
								
							
						
					
					
						commit
						5e9ba2ac84
					
				
					 13 changed files with 1133 additions and 468 deletions
				
			
		|  | @ -16,7 +16,7 @@ KERNEL_OBJS = \ | |||
|        Console.o \
 | ||||
|        IRQHandler.o \
 | ||||
|        kprintf.o \
 | ||||
|        ProcFileSystem.o \
 | ||||
|        ProcFS.o \
 | ||||
|        RTC.o \
 | ||||
|        TTY.o \
 | ||||
|        PTYMultiplexer.o \
 | ||||
|  |  | |||
|  | @ -201,7 +201,7 @@ class MemoryManager { | |||
|     friend class PhysicalPage; | ||||
|     friend class Region; | ||||
|     friend class VMObject; | ||||
|     friend ByteBuffer procfs$mm(SynthFSInode&); | ||||
|     friend ByteBuffer procfs$mm(InodeIdentifier); | ||||
| public: | ||||
|     static MemoryManager& the() PURE; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										1002
									
								
								Kernel/ProcFS.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1002
									
								
								Kernel/ProcFS.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										96
									
								
								Kernel/ProcFS.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								Kernel/ProcFS.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Lock.h> | ||||
| #include <AK/Types.h> | ||||
| #include <Kernel/FileSystem.h> | ||||
| 
 | ||||
| class Process; | ||||
| 
 | ||||
| class ProcFSInode; | ||||
| 
 | ||||
| class ProcFS final : public FS { | ||||
|     friend class ProcFSInode; | ||||
| public: | ||||
|     static ProcFS& the() PURE; | ||||
| 
 | ||||
|     virtual ~ProcFS() override; | ||||
|     static RetainPtr<ProcFS> create(); | ||||
| 
 | ||||
|     virtual bool initialize() override; | ||||
|     virtual const char* class_name() const override; | ||||
| 
 | ||||
|     virtual InodeIdentifier root_inode() const override; | ||||
|     virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override; | ||||
| 
 | ||||
|     virtual RetainPtr<Inode> create_inode(InodeIdentifier parent_id, const String& name, mode_t, unsigned size, int& error) override; | ||||
|     virtual RetainPtr<Inode> create_directory(InodeIdentifier parent_id, const String& name, mode_t, int& error) override; | ||||
| 
 | ||||
|     void add_sys_file(String&&, Function<ByteBuffer(ProcFSInode&)>&& read_callback, Function<ssize_t(ProcFSInode&, const ByteBuffer&)>&& write_callback); | ||||
|     void add_sys_bool(String&&, bool*, Function<void()>&& notify_callback = nullptr); | ||||
| 
 | ||||
| private: | ||||
|     ProcFS(); | ||||
| 
 | ||||
|     struct ProcFSDirectoryEntry { | ||||
|         ProcFSDirectoryEntry() { } | ||||
|         ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, Function<ByteBuffer(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RetainPtr<ProcFSInode>&& a_inode = nullptr) | ||||
|             : name(a_name) | ||||
|             , proc_file_type(a_proc_file_type) | ||||
|             , read_callback(move(a_read_callback)) | ||||
|             , write_callback(move(a_write_callback)) | ||||
|             , inode(move(a_inode)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         const char* name { nullptr }; | ||||
|         unsigned proc_file_type { 0 }; | ||||
|         Function<ByteBuffer(InodeIdentifier)> read_callback; | ||||
|         Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback; | ||||
|         RetainPtr<ProcFSInode> inode; | ||||
|         InodeIdentifier identifier(unsigned fsid) const; | ||||
|     }; | ||||
| 
 | ||||
|     ProcFSDirectoryEntry* get_directory_entry(InodeIdentifier) const; | ||||
| 
 | ||||
|     Vector<ProcFSDirectoryEntry> m_entries; | ||||
|     Vector<ProcFSDirectoryEntry> m_sys_entries; | ||||
| 
 | ||||
|     mutable Lock m_inodes_lock; | ||||
|     mutable HashMap<unsigned, ProcFSInode*> m_inodes; | ||||
|     RetainPtr<ProcFSInode> m_root_inode; | ||||
| }; | ||||
| 
 | ||||
| struct ProcFSInodeCustomData { | ||||
|     virtual ~ProcFSInodeCustomData(); | ||||
| }; | ||||
| 
 | ||||
| class ProcFSInode final : public Inode { | ||||
|     friend class ProcFS; | ||||
| public: | ||||
|     virtual ~ProcFSInode() override; | ||||
| 
 | ||||
|     void set_custom_data(OwnPtr<ProcFSInodeCustomData>&& custom_data) { m_custom_data = move(custom_data); } | ||||
|     ProcFSInodeCustomData* custom_data() { return m_custom_data.ptr(); } | ||||
|     const ProcFSInodeCustomData* custom_data() const { return m_custom_data.ptr(); } | ||||
| 
 | ||||
| private: | ||||
|     // ^Inode
 | ||||
|     virtual ssize_t read_bytes(off_t, size_t, byte* buffer, FileDescriptor*) const override; | ||||
|     virtual InodeMetadata metadata() const override; | ||||
|     virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override; | ||||
|     virtual InodeIdentifier lookup(const String& name) override; | ||||
|     virtual String reverse_lookup(InodeIdentifier) override; | ||||
|     virtual void flush_metadata() override; | ||||
|     virtual ssize_t write_bytes(off_t, size_t, const byte* buffer, FileDescriptor*) override; | ||||
|     virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override; | ||||
|     virtual bool remove_child(const String& name, int& error) override; | ||||
|     virtual RetainPtr<Inode> parent() const override; | ||||
|     virtual size_t directory_entry_count() const override; | ||||
|     virtual bool chmod(mode_t, int& error) override; | ||||
| 
 | ||||
|     ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); } | ||||
|     const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); } | ||||
|     ProcFSInode(ProcFS&, unsigned index); | ||||
| 
 | ||||
|     OwnPtr<ProcFSInodeCustomData> m_custom_data; | ||||
| }; | ||||
|  | @ -1,418 +0,0 @@ | |||
| #include "ProcFileSystem.h" | ||||
| #include "Process.h" | ||||
| #include <Kernel/VirtualFileSystem.h> | ||||
| #include "system.h" | ||||
| #include "MemoryManager.h" | ||||
| #include "StdLib.h" | ||||
| #include "i386.h" | ||||
| #include "KSyms.h" | ||||
| #include "Console.h" | ||||
| #include <AK/StringBuilder.h> | ||||
| 
 | ||||
| static ProcFS* s_the; | ||||
| 
 | ||||
| ProcFS& ProcFS::the() | ||||
| { | ||||
|     ASSERT(s_the); | ||||
|     return *s_the; | ||||
| } | ||||
| 
 | ||||
| RetainPtr<ProcFS> ProcFS::create() | ||||
| { | ||||
|     return adopt(*new ProcFS); | ||||
| } | ||||
| 
 | ||||
| ProcFS::ProcFS() | ||||
| { | ||||
|     s_the = this; | ||||
| } | ||||
| 
 | ||||
| ProcFS::~ProcFS() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_fds(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     if (process.number_of_open_file_descriptors() == 0) | ||||
|         return { }; | ||||
|     StringBuilder builder; | ||||
|     for (size_t i = 0; i < process.max_open_file_descriptors(); ++i) { | ||||
|         auto* descriptor = process.file_descriptor(i); | ||||
|         if (!descriptor) | ||||
|             continue; | ||||
|         builder.appendf("% 3u %s\n", i, descriptor->absolute_path().characters()); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_vm(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     StringBuilder builder; | ||||
|     builder.appendf("BEGIN       END         SIZE      COMMIT     NAME\n"); | ||||
|     for (auto& region : process.regions()) { | ||||
|         builder.appendf("%x -- %x    %x  %x   %s\n", | ||||
|             region->laddr().get(), | ||||
|             region->laddr().offset(region->size() - 1).get(), | ||||
|             region->size(), | ||||
|             region->committed(), | ||||
|             region->name().characters()); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_vmo(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     StringBuilder builder; | ||||
|     builder.appendf("BEGIN       END         SIZE        NAME\n"); | ||||
|     for (auto& region : process.regions()) { | ||||
|         builder.appendf("%x -- %x    %x    %s\n", | ||||
|             region->laddr().get(), | ||||
|             region->laddr().offset(region->size() - 1).get(), | ||||
|             region->size(), | ||||
|             region->name().characters()); | ||||
|         builder.appendf("VMO: %s \"%s\" @ %x(%u)\n", | ||||
|             region->vmo().is_anonymous() ? "anonymous" : "file-backed", | ||||
|             region->vmo().name().characters(), | ||||
|             ®ion->vmo(), | ||||
|             region->vmo().retain_count()); | ||||
|         for (size_t i = 0; i < region->vmo().page_count(); ++i) { | ||||
|             auto& physical_page = region->vmo().physical_pages()[i]; | ||||
|             builder.appendf("P%x%s(%u) ", | ||||
|                 physical_page ? physical_page->paddr().get() : 0, | ||||
|                 region->cow_map().get(i) ? "!" : "", | ||||
|                 physical_page ? physical_page->retain_count() : 0 | ||||
|             ); | ||||
|         } | ||||
|         builder.appendf("\n"); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_stack(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     ProcessPagingScope paging_scope(process); | ||||
|     struct RecognizedSymbol { | ||||
|         dword address; | ||||
|         const KSym* ksym; | ||||
|     }; | ||||
|     Vector<RecognizedSymbol> recognized_symbols; | ||||
|     if (auto* eip_ksym = ksymbolicate(process.tss().eip)) | ||||
|         recognized_symbols.append({ process.tss().eip, eip_ksym }); | ||||
|     for (dword* stack_ptr = (dword*)process.frame_ptr(); process.validate_read_from_kernel(LinearAddress((dword)stack_ptr)); stack_ptr = (dword*)*stack_ptr) { | ||||
|         dword retaddr = stack_ptr[1]; | ||||
|         if (auto* ksym = ksymbolicate(retaddr)) | ||||
|             recognized_symbols.append({ retaddr, ksym }); | ||||
|     } | ||||
|     StringBuilder builder; | ||||
|     for (auto& symbol : recognized_symbols) { | ||||
|         unsigned offset = symbol.address - symbol.ksym->address; | ||||
|         builder.appendf("%p  %s +%u\n", symbol.address, symbol.ksym->name, offset); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_regs(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     auto& tss = process.tss(); | ||||
|     StringBuilder builder; | ||||
|     builder.appendf("eax: %x\n", tss.eax); | ||||
|     builder.appendf("ebx: %x\n", tss.ebx); | ||||
|     builder.appendf("ecx: %x\n", tss.ecx); | ||||
|     builder.appendf("edx: %x\n", tss.edx); | ||||
|     builder.appendf("esi: %x\n", tss.esi); | ||||
|     builder.appendf("edi: %x\n", tss.edi); | ||||
|     builder.appendf("ebp: %x\n", tss.ebp); | ||||
|     builder.appendf("cr3: %x\n", tss.cr3); | ||||
|     builder.appendf("flg: %x\n", tss.eflags); | ||||
|     builder.appendf("sp:  %w:%x\n", tss.ss, tss.esp); | ||||
|     builder.appendf("pc:  %w:%x\n", tss.cs, tss.eip); | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_exe(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     auto inode = process.executable_inode(); | ||||
|     ASSERT(inode); | ||||
|     return VFS::the().absolute_path(*inode).to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$pid_cwd(Process& process) | ||||
| { | ||||
|     ProcessInspectionHandle handle(process); | ||||
|     auto inode = process.cwd_inode(); | ||||
|     ASSERT(inode); | ||||
|     return VFS::the().absolute_path(*inode).to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$self(SynthFSInode&) | ||||
| { | ||||
|     char buffer[16]; | ||||
|     ksprintf(buffer, "%u", current->pid()); | ||||
|     return ByteBuffer::copy((const byte*)buffer, strlen(buffer)); | ||||
| } | ||||
| 
 | ||||
| void ProcFS::add_process(Process& process) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     auto dir = add_file(create_directory(String::format("%d", process.pid()))); | ||||
|     m_pid2inode.set(process.pid(), 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] (SynthFSInode&) { return procfs$pid_exe(process); }, 00120777), dir.index()); | ||||
|     if (process.cwd_inode()) | ||||
|         add_file(create_generated_file("cwd", [&process] (SynthFSInode&) { return procfs$pid_cwd(process); }, 00120777), dir.index()); | ||||
| } | ||||
| 
 | ||||
| void ProcFS::remove_process(Process& process) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     auto pid = process.pid(); | ||||
|     auto it = m_pid2inode.find(pid); | ||||
|     if (it == m_pid2inode.end()) | ||||
|         return; | ||||
|     bool success = remove_file((*it).value); | ||||
|     ASSERT(success); | ||||
|     m_pid2inode.remove(pid); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$mm(SynthFSInode&) | ||||
| { | ||||
|     // FIXME: Implement
 | ||||
|     InterruptDisabler disabler; | ||||
|     StringBuilder builder; | ||||
|     for (auto* vmo : MM.m_vmos) { | ||||
|         builder.appendf("VMO: %p %s(%u): p:%4u %s\n", | ||||
|             vmo, | ||||
|             vmo->is_anonymous() ? "anon" : "file", | ||||
|             vmo->retain_count(), | ||||
|             vmo->page_count(), | ||||
|             vmo->name().characters()); | ||||
|     } | ||||
|     builder.appendf("VMO count: %u\n", MM.m_vmos.size()); | ||||
|     builder.appendf("Free physical pages: %u\n", MM.m_free_physical_pages.size()); | ||||
|     builder.appendf("Free supervisor physical pages: %u\n", MM.m_free_supervisor_physical_pages.size()); | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$dmesg(SynthFSInode&) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     StringBuilder builder; | ||||
|     for (char ch : Console::the().logbuffer()) | ||||
|         builder.append(ch); | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$mounts(SynthFSInode&) | ||||
| { | ||||
|     // FIXME: This is obviously racy against the VFS mounts changing.
 | ||||
|     StringBuilder builder; | ||||
|     VFS::the().for_each_mount([&builder] (auto& mount) { | ||||
|         auto& fs = mount.guest_fs(); | ||||
|         builder.appendf("%s @ ", fs.class_name()); | ||||
|         if (!mount.host().is_valid()) | ||||
|             builder.appendf("/"); | ||||
|         else { | ||||
|             builder.appendf("%u:%u", mount.host().fsid(), mount.host().index()); | ||||
|             auto path = VFS::the().absolute_path(mount.host()); | ||||
|             builder.append(' '); | ||||
|             builder.append(path); | ||||
|         } | ||||
|         builder.append('\n'); | ||||
|     }); | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$cpuinfo(SynthFSInode&) | ||||
| { | ||||
|     StringBuilder builder; | ||||
|     { | ||||
|         CPUID cpuid(0); | ||||
|         builder.appendf("cpuid:     "); | ||||
|         auto emit_dword = [&] (dword value) { | ||||
|             builder.appendf("%c%c%c%c", | ||||
|                 value & 0xff, | ||||
|                 (value >> 8) & 0xff, | ||||
|                 (value >> 16) & 0xff, | ||||
|                 (value >> 24) & 0xff); | ||||
|         }; | ||||
|         emit_dword(cpuid.ebx()); | ||||
|         emit_dword(cpuid.edx()); | ||||
|         emit_dword(cpuid.ecx()); | ||||
|         builder.appendf("\n"); | ||||
|     } | ||||
|     { | ||||
|         CPUID cpuid(1); | ||||
|         dword stepping = cpuid.eax() & 0xf; | ||||
|         dword model = (cpuid.eax() >> 4) & 0xf; | ||||
|         dword family = (cpuid.eax() >> 8) & 0xf; | ||||
|         dword type = (cpuid.eax() >> 12) & 0x3; | ||||
|         dword extended_model = (cpuid.eax() >> 16) & 0xf; | ||||
|         dword extended_family = (cpuid.eax() >> 20) & 0xff; | ||||
|         dword display_model; | ||||
|         dword display_family; | ||||
|         if (family == 15) { | ||||
|             display_family = family + extended_family; | ||||
|             display_model = model + (extended_model << 4); | ||||
|         } else if (family == 6) { | ||||
|             display_family = family; | ||||
|             display_model = model + (extended_model << 4); | ||||
|         } else { | ||||
|             display_family = family; | ||||
|             display_model = model; | ||||
|         } | ||||
|         builder.appendf("family:    %u\n", display_family); | ||||
|         builder.appendf("model:     %u\n", display_model); | ||||
|         builder.appendf("stepping:  %u\n", stepping); | ||||
|         builder.appendf("type:      %u\n", type); | ||||
|     } | ||||
|     { | ||||
|         // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000
 | ||||
|         //        and verifying that the returned eax>=0x80000004.
 | ||||
|         char buffer[48]; | ||||
|         dword* bufptr = reinterpret_cast<dword*>(buffer); | ||||
|         auto copy_brand_string_part_to_buffer = [&] (dword i) { | ||||
|             CPUID cpuid(0x80000002 + i); | ||||
|             *bufptr++ = cpuid.eax(); | ||||
|             *bufptr++ = cpuid.ebx(); | ||||
|             *bufptr++ = cpuid.ecx(); | ||||
|             *bufptr++ = cpuid.edx(); | ||||
|         }; | ||||
|         copy_brand_string_part_to_buffer(0); | ||||
|         copy_brand_string_part_to_buffer(1); | ||||
|         copy_brand_string_part_to_buffer(2); | ||||
|         builder.appendf("brandstr:  \"%s\"\n", buffer); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$kmalloc(SynthFSInode&) | ||||
| { | ||||
|     StringBuilder builder; | ||||
|     builder.appendf( | ||||
|         "eternal:      %u\n" | ||||
|         "allocated:    %u\n" | ||||
|         "free:         %u\n", | ||||
|         kmalloc_sum_eternal, | ||||
|         sum_alloc, | ||||
|         sum_free | ||||
|     ); | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$summary(SynthFSInode&) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     auto processes = Process::all_processes(); | ||||
|     StringBuilder builder; | ||||
|     builder.appendf("PID TPG PGP SID  OWNER  STATE      PPID NSCHED     FDS  TTY  NAME\n"); | ||||
|     for (auto* process : processes) { | ||||
|         builder.appendf("% 3u % 3u % 3u % 3u  % 4u   % 8s   % 3u  % 9u  % 3u  % 4s  %s\n", | ||||
|             process->pid(), | ||||
|             process->tty() ? process->tty()->pgid() : 0, | ||||
|             process->pgid(), | ||||
|             process->sid(), | ||||
|             process->uid(), | ||||
|             to_string(process->state()), | ||||
|             process->ppid(), | ||||
|             process->times_scheduled(), | ||||
|             process->number_of_open_file_descriptors(), | ||||
|             process->tty() ? strrchr(process->tty()->tty_name().characters(), '/') + 1 : "n/a", | ||||
|             process->name().characters()); | ||||
|     } | ||||
|     return builder.to_byte_buffer(); | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$inodes(SynthFSInode&) | ||||
| { | ||||
|     extern HashTable<Inode*>& all_inodes(); | ||||
|     auto& vfs = VFS::the(); | ||||
|     StringBuilder builder; | ||||
|     for (auto it : all_inodes()) { | ||||
|         RetainPtr<Inode> inode = *it; | ||||
|         String path = vfs.absolute_path(*inode); | ||||
|         builder.appendf("Inode{K%x} %02u:%08u (%u) %s\n", inode.ptr(), inode->fsid(), inode->index(), inode->retain_count(), path.characters()); | ||||
|     } | ||||
|     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(); | ||||
|     add_file(create_generated_file("mm", procfs$mm)); | ||||
|     add_file(create_generated_file("mounts", procfs$mounts)); | ||||
|     add_file(create_generated_file("kmalloc", procfs$kmalloc)); | ||||
|     add_file(create_generated_file("summary", procfs$summary)); | ||||
|     add_file(create_generated_file("cpuinfo", procfs$cpuinfo)); | ||||
|     add_file(create_generated_file("inodes", procfs$inodes)); | ||||
|     add_file(create_generated_file("dmesg", procfs$dmesg)); | ||||
|     add_file(create_generated_file("self", procfs$self, 00120777)); | ||||
|     m_sys_dir = add_file(create_directory("sys")); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| const char* ProcFS::class_name() const | ||||
| { | ||||
|     return "ProcFS"; | ||||
| } | ||||
|  | @ -1,30 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Types.h> | ||||
| #include <Kernel/SyntheticFileSystem.h> | ||||
| 
 | ||||
| class Process; | ||||
| 
 | ||||
| class ProcFS final : public SynthFS { | ||||
| public: | ||||
|     static ProcFS& the() PURE; | ||||
| 
 | ||||
|     virtual ~ProcFS() override; | ||||
|     static RetainPtr<ProcFS> create(); | ||||
| 
 | ||||
|     virtual bool initialize() override; | ||||
|     virtual const char* class_name() const override; | ||||
| 
 | ||||
|     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; | ||||
| }; | ||||
| 
 | ||||
|  | @ -10,7 +10,6 @@ | |||
| #include "MemoryManager.h" | ||||
| #include "i8253.h" | ||||
| #include "RTC.h" | ||||
| #include "ProcFileSystem.h" | ||||
| #include <AK/StdLibExtras.h> | ||||
| #include <LibC/signal_numbers.h> | ||||
| #include <LibC/errno_numbers.h> | ||||
|  | @ -60,13 +59,23 @@ void Process::initialize() | |||
|     initialize_gui_statics(); | ||||
| } | ||||
| 
 | ||||
| Vector<pid_t> Process::all_pids() | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     Vector<pid_t> pids; | ||||
|     pids.ensure_capacity(g_processes->size_slow()); | ||||
|     for (auto* process = g_processes->head(); process; process = process->next()) | ||||
|         pids.unchecked_append(process->pid()); | ||||
|     return pids; | ||||
| } | ||||
| 
 | ||||
| Vector<Process*> Process::all_processes() | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     Vector<Process*> processes; | ||||
|     processes.ensure_capacity(g_processes->size_slow()); | ||||
|     for (auto* process = g_processes->head(); process; process = process->next()) | ||||
|         processes.append(process); | ||||
|         processes.unchecked_append(process); | ||||
|     return processes; | ||||
| } | ||||
| 
 | ||||
|  | @ -266,8 +275,6 @@ Process* Process::fork(RegisterDump& regs) | |||
|     dbgprintf("fork: child will begin executing at %w:%x with stack %w:%x\n", child->m_tss.cs, child->m_tss.eip, child->m_tss.ss, child->m_tss.esp); | ||||
| #endif | ||||
| 
 | ||||
|     ProcFS::the().add_process(*child); | ||||
| 
 | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         g_processes->prepend(child); | ||||
|  | @ -507,8 +514,6 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, | |||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     ProcFS::the().add_process(*process); | ||||
| 
 | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         g_processes->prepend(process); | ||||
|  | @ -571,7 +576,6 @@ Process* Process::create_kernel_process(String&& name, void (*e)()) | |||
|             g_processes->prepend(process); | ||||
|             system.nprocess++; | ||||
|         } | ||||
|         ProcFS::the().add_process(*process); | ||||
| #ifdef TASK_DEBUG | ||||
|         kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); | ||||
| #endif | ||||
|  | @ -703,7 +707,6 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring | |||
| Process::~Process() | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     ProcFS::the().remove_process(*this); | ||||
|     system.nprocess--; | ||||
| 
 | ||||
|     if (g_last_fpu_process == this) | ||||
|  |  | |||
|  | @ -55,6 +55,7 @@ public: | |||
|     static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr); | ||||
|     ~Process(); | ||||
| 
 | ||||
|     static Vector<pid_t> all_pids(); | ||||
|     static Vector<Process*> all_processes(); | ||||
| 
 | ||||
|     enum State { | ||||
|  | @ -406,6 +407,17 @@ public: | |||
|         m_process.set_state(m_original_state); | ||||
|     } | ||||
| 
 | ||||
|     Process& process() { return m_process; } | ||||
| 
 | ||||
|     static OwnPtr<ProcessInspectionHandle> from_pid(pid_t pid) | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         auto* process = Process::from_pid(pid); | ||||
|         if (process) | ||||
|             return make<ProcessInspectionHandle>(*process); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     Process* operator->() { return &m_process; } | ||||
|     Process& operator*() { return m_process; } | ||||
| private: | ||||
|  |  | |||
|  | @ -92,10 +92,10 @@ int strcmp(const char *s1, const char *s2) | |||
| 
 | ||||
| char* strdup(const char *str) | ||||
| { | ||||
|     dword len = strlen(str); | ||||
|     char *s = (char*)kmalloc(len); | ||||
|     memcpy(s, str, len); | ||||
|     return s; | ||||
|     size_t len = strlen(str); | ||||
|     char* new_str = (char*)kmalloc(len + 1); | ||||
|     strcpy(new_str, str); | ||||
|     return new_str; | ||||
| } | ||||
| 
 | ||||
| int memcmp(const void* v1, const void* v2, size_t n) | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ | |||
| #include <Kernel/VirtualFileSystem.h> | ||||
| #include "GUIEventDevice.h" | ||||
| #include "MemoryManager.h" | ||||
| #include "ProcFileSystem.h" | ||||
| #include "ProcFS.h" | ||||
| #include "RTC.h" | ||||
| #include "VirtualConsole.h" | ||||
| #include "Scheduler.h" | ||||
|  | @ -171,8 +171,8 @@ void init() | |||
| 
 | ||||
|     memset(&system, 0, sizeof(system)); | ||||
| 
 | ||||
|     auto procfs = ProcFS::create(); | ||||
|     procfs->initialize(); | ||||
|     auto new_procfs = ProcFS::create(); | ||||
|     new_procfs->initialize(); | ||||
| 
 | ||||
|     auto devptsfs = DevPtsFS::create(); | ||||
|     devptsfs->initialize(); | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ typedef short __s16; | |||
| 
 | ||||
| typedef dword uid_t; | ||||
| typedef dword gid_t; | ||||
| typedef int pid_t; | ||||
| typedef signed_word pid_t; | ||||
| typedef dword time_t; | ||||
| typedef dword suseconds_t; | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ typedef __intmax_t intmax_t; | |||
| 
 | ||||
| typedef uint32_t uid_t; | ||||
| typedef uint32_t gid_t; | ||||
| typedef int pid_t; | ||||
| typedef int16_t pid_t; | ||||
| 
 | ||||
| typedef uint32_t size_t; | ||||
| typedef int32_t ssize_t; | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| #include "WSMessageLoop.h" | ||||
| #include "Process.h" | ||||
| #include "MemoryManager.h" | ||||
| #include <Kernel/ProcFileSystem.h> | ||||
| #include <Kernel/ProcFS.h> | ||||
| #include <SharedGraphics/Font.h> | ||||
| #include <SharedGraphics/Painter.h> | ||||
| #include <SharedGraphics/CharacterBitmap.h> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling