From 5ded77df39e816f565b26761624893d085ca6eef Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 29 Jul 2019 07:26:01 +0200 Subject: [PATCH] Kernel+ProcessManager: Let processes have an icon and show it in the table. Processes can now have an icon assigned, which is essentially a 16x16 RGBA32 bitmap exposed as a shared buffer ID. You set the icon ID by calling set_process_icon(int) and the icon ID will be exposed through /proc/all. To make this work, I added a mechanism for making shared buffers globally accessible. For safety reasons, each app seals the icon buffer before making it global. Right now the first call to GWindow::set_icon() is what determines the process icon. We'll probably change this in the future. :^) --- Applications/ProcessManager/ProcessModel.cpp | 10 +++++++ Applications/ProcessManager/ProcessModel.h | 1 + Kernel/FileSystem/ProcFS.cpp | 1 + Kernel/Process.cpp | 26 +++++++++++++++++++ Kernel/Process.h | 7 +++++ Kernel/SharedBuffer.cpp | 17 +++++++++++- Kernel/SharedBuffer.h | 3 +++ Kernel/Syscall.cpp | 4 +++ Kernel/Syscall.h | 4 ++- Libraries/LibC/unistd.cpp | 12 +++++++++ Libraries/LibC/unistd.h | 2 ++ .../LibCore/CProcessStatisticsReader.cpp | 1 + Libraries/LibCore/CProcessStatisticsReader.h | 1 + Libraries/LibGUI/GWindow.cpp | 10 +++++++ 14 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Applications/ProcessManager/ProcessModel.cpp b/Applications/ProcessManager/ProcessModel.cpp index 428e8779cf..b2f78245c8 100644 --- a/Applications/ProcessManager/ProcessModel.cpp +++ b/Applications/ProcessManager/ProcessModel.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -138,6 +139,14 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const if (role == Role::Display) { switch (index.column()) { case Column::Icon: + if (process.current_state.icon_id != -1) { + auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(process.current_state.icon_id); + if (icon_buffer) { + auto icon_bitmap = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *icon_buffer, { 16, 16 }); + if (icon_bitmap) + return *icon_bitmap; + } + } return *m_generic_process_icon; case Column::PID: return process.current_state.pid; @@ -193,6 +202,7 @@ void ProcessModel::update() state.name = it.value.name; state.amount_virtual = it.value.amount_virtual; state.amount_resident = it.value.amount_resident; + state.icon_id = it.value.icon_id; sum_times_scheduled += it.value.times_scheduled; { auto pit = m_processes.find(it.value.pid); diff --git a/Applications/ProcessManager/ProcessModel.h b/Applications/ProcessManager/ProcessModel.h index 21003a6666..883da5d5cb 100644 --- a/Applications/ProcessManager/ProcessModel.h +++ b/Applications/ProcessManager/ProcessModel.h @@ -50,6 +50,7 @@ private: size_t amount_resident; unsigned syscall_count; float cpu_percent; + int icon_id; }; struct Process { diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index b1ea7d9491..5041fd10c9 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -548,6 +548,7 @@ ByteBuffer procfs$all(InodeIdentifier) process_object.set("ticks", process.main_thread().ticks()); process_object.set("priority", to_string(process.priority())); process_object.set("syscall_count", process.syscall_count()); + process_object.set("icon_id", process.icon_id()); array.append(process_object); }; build_process(*Scheduler::colonel()); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index ef8803a85e..a4d1b41644 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2452,6 +2452,19 @@ int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid) return 0; } +int Process::sys$share_buffer_globally(int shared_buffer_id) +{ + LOCKER(shared_buffers().lock()); + auto it = shared_buffers().resource().find(shared_buffer_id); + if (it == shared_buffers().resource().end()) + return -EINVAL; + auto& shared_buffer = *(*it).value; + if (!shared_buffer.is_shared_with(m_pid)) + return -EPERM; + shared_buffer.share_globally(); + return 0; +} + int Process::sys$release_shared_buffer(int shared_buffer_id) { LOCKER(shared_buffers().lock()); @@ -2773,3 +2786,16 @@ String Process::backtrace(ProcessInspectionHandle& handle) const }); return builder.to_string(); } + +int Process::sys$set_process_icon(int icon_id) +{ + LOCKER(shared_buffers().lock()); + auto it = shared_buffers().resource().find(icon_id); + if (it == shared_buffers().resource().end()) + return -EINVAL; + auto& shared_buffer = *(*it).value; + if (!shared_buffer.is_shared_with(m_pid)) + return -EPERM; + m_icon_id = icon_id; + return 0; +} diff --git a/Kernel/Process.h b/Kernel/Process.h index 7f38cb5e71..e114bc0cbf 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -22,6 +22,7 @@ class PageDirectory; class Region; class VMObject; class ProcessTracer; +class SharedBuffer; timeval kgettimeofday(); void kgettimeofday(timeval&); @@ -208,12 +209,14 @@ public: int sys$mknod(const char* pathname, mode_t, dev_t); int sys$create_shared_buffer(int, void** buffer); int sys$share_buffer_with(int, pid_t peer_pid); + int sys$share_buffer_globally(int); void* sys$get_shared_buffer(int shared_buffer_id); int sys$release_shared_buffer(int shared_buffer_id); int sys$seal_shared_buffer(int shared_buffer_id); int sys$get_shared_buffer_size(int shared_buffer_id); int sys$halt(); int sys$reboot(); + int sys$set_process_icon(int icon_id); static void initialize(); @@ -281,6 +284,8 @@ public: const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); } + int icon_id() const { return m_icon_id; } + private: friend class MemoryManager; friend class Scheduler; @@ -359,6 +364,8 @@ private: Lock m_big_lock { "Process" }; u64 m_alarm_deadline { 0 }; + + int m_icon_id { -1 }; }; class ProcessInspectionHandle { diff --git a/Kernel/SharedBuffer.cpp b/Kernel/SharedBuffer.cpp index 29665e3bc9..5753a2a6b3 100644 --- a/Kernel/SharedBuffer.cpp +++ b/Kernel/SharedBuffer.cpp @@ -1,5 +1,5 @@ -#include #include +#include Lockable>>& shared_buffers() { @@ -29,6 +29,8 @@ void SharedBuffer::sanity_check(const char* what) bool SharedBuffer::is_shared_with(pid_t peer_pid) { LOCKER(shared_buffers().lock()); + if (m_global) + return true; for (auto& ref : m_refs) { if (ref.pid == peer_pid) { return true; @@ -42,6 +44,18 @@ void* SharedBuffer::ref_for_process_and_get_address(Process& process) { LOCKER(shared_buffers().lock()); ASSERT(is_shared_with(process.pid())); + if (m_global) { + bool found = false; + for (auto& ref : m_refs) { + if (ref.pid == process.pid()) { + found = true; + break; + } + } + if (!found) + m_refs.append(Reference(process.pid())); + } + for (auto& ref : m_refs) { if (ref.pid == process.pid()) { ref.count++; @@ -93,6 +107,7 @@ void SharedBuffer::deref_for_process(Process& process) destroy_if_unused(); return; } + return; } } diff --git a/Kernel/SharedBuffer.h b/Kernel/SharedBuffer.h index e779186892..bd2751471d 100644 --- a/Kernel/SharedBuffer.h +++ b/Kernel/SharedBuffer.h @@ -36,14 +36,17 @@ public: bool is_shared_with(pid_t peer_pid); void* ref_for_process_and_get_address(Process& process); void share_with(pid_t peer_pid); + void share_globally() { m_global = true; } void deref_for_process(Process& process); void disown(pid_t pid); size_t size() const { return m_vmo->size(); } void destroy_if_unused(); void seal(); + int id() const { return m_shared_buffer_id; } int m_shared_buffer_id { -1 }; bool m_writable { true }; + bool m_global { false }; NonnullRefPtr m_vmo; Vector m_refs; unsigned m_total_refs { 0 }; diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 43db79393e..432a593bba 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -299,6 +299,10 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3 return current->process().sys$dump_backtrace(); case Syscall::SC_watch_file: return current->process().sys$watch_file((const char*)arg1, (int)arg2); + case Syscall::SC_share_buffer_globally: + return current->process().sys$share_buffer_globally((int)arg1); + case Syscall::SC_set_process_icon: + return current->process().sys$set_process_icon((int)arg1); default: kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3); return -ENOSYS; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index b45343964f..44ba85cd88 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -119,7 +119,9 @@ struct timeval; __ENUMERATE_SYSCALL(dump_backtrace) \ __ENUMERATE_SYSCALL(dbgputch) \ __ENUMERATE_SYSCALL(dbgputstr) \ - __ENUMERATE_SYSCALL(watch_file) + __ENUMERATE_SYSCALL(watch_file) \ + __ENUMERATE_SYSCALL(share_buffer_globally) \ + __ENUMERATE_SYSCALL(set_process_icon) namespace Syscall { diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index b912544efd..922039c09f 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -442,6 +442,18 @@ int share_buffer_with(int shared_buffer_id, pid_t peer_pid) __RETURN_WITH_ERRNO(rc, rc, -1); } +int share_buffer_globally(int shared_buffer_id) +{ + int rc = syscall(SC_share_buffer_globally, shared_buffer_id); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int set_process_icon(int icon_id) +{ + int rc = syscall(SC_set_process_icon, icon_id); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + void* get_shared_buffer(int shared_buffer_id) { int rc = syscall(SC_get_shared_buffer, shared_buffer_id); diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index d574eb737a..b4b8928e9c 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -24,10 +24,12 @@ int create_thread(int (*)(void*), void*); void exit_thread(int); int create_shared_buffer(int, void** buffer); int share_buffer_with(int, pid_t peer_pid); +int share_buffer_globally(int); void* get_shared_buffer(int shared_buffer_id); int release_shared_buffer(int shared_buffer_id); int seal_shared_buffer(int shared_buffer_id); int get_shared_buffer_size(int shared_buffer_id); +int set_process_icon(int icon_id); int read_tsc(unsigned* lsw, unsigned* msw); inline int getpagesize() { return 4096; } pid_t fork(); diff --git a/Libraries/LibCore/CProcessStatisticsReader.cpp b/Libraries/LibCore/CProcessStatisticsReader.cpp index d0e521762c..bb904c087b 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.cpp +++ b/Libraries/LibCore/CProcessStatisticsReader.cpp @@ -43,6 +43,7 @@ HashMap CProcessStatisticsReader::get_all() process.ticks = process_object.get("ticks").to_u32(); process.priority = process_object.get("priority").to_string(); process.syscall_count = process_object.get("syscall_count").to_u32(); + process.icon_id = process_object.get("icon_id").to_int(); // and synthetic data last process.username = username_from_uid(process.uid); diff --git a/Libraries/LibCore/CProcessStatisticsReader.h b/Libraries/LibCore/CProcessStatisticsReader.h index 1e15dbc560..343ad0ac39 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.h +++ b/Libraries/LibCore/CProcessStatisticsReader.h @@ -24,6 +24,7 @@ struct CProcessStatistics { unsigned ticks; String priority; unsigned syscall_count; + int icon_id; // synthetic String username; diff --git a/Libraries/LibGUI/GWindow.cpp b/Libraries/LibGUI/GWindow.cpp index 699168fb97..725fa676bc 100644 --- a/Libraries/LibGUI/GWindow.cpp +++ b/Libraries/LibGUI/GWindow.cpp @@ -635,6 +635,16 @@ void GWindow::set_icon(const GraphicsBitmap* icon) painter.blit({ 0, 0 }, *icon, icon->rect()); } + int rc = seal_shared_buffer(m_icon->shared_buffer_id()); + ASSERT(rc == 0); + + rc = share_buffer_globally(m_icon->shared_buffer_id()); + ASSERT(rc == 0); + + static bool has_set_process_icon; + if (!has_set_process_icon) + set_process_icon(m_icon->shared_buffer_id()); + WSAPI_ClientMessage message; message.type = WSAPI_ClientMessage::Type::SetWindowIconBitmap; message.window_id = m_window_id;