mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:27:45 +00:00
Move WindowServer to userspace.
This is a monster patch that required changing a whole bunch of things. There are performance and stability issues all over the place, but it works. Pretty cool, I have to admit :^)
This commit is contained in:
parent
0b1b21d622
commit
640360e958
41 changed files with 325 additions and 463 deletions
|
@ -95,9 +95,9 @@ Region* BochsVGADevice::mmap(Process& process, LinearAddress preferred_laddr, si
|
|||
0,
|
||||
"BochsVGA Framebuffer",
|
||||
true, true);
|
||||
kprintf("BochsVGA: %s(%u) created Region{%p} for framebuffer P%x\n",
|
||||
kprintf("BochsVGA: %s(%u) created Region{%p} with size %u for framebuffer P%x with laddr L%x\n",
|
||||
process.name().characters(), process.pid(),
|
||||
region, framebuffer_address().as_ptr());
|
||||
region, region->size(), framebuffer_address().as_ptr(), region->laddr().get());
|
||||
ASSERT(region);
|
||||
return region;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <Kernel/Socket.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/BlockDevice.h>
|
||||
#include <Kernel/MemoryManager.h>
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& inode)
|
||||
{
|
||||
|
@ -54,6 +55,10 @@ FileDescriptor::FileDescriptor(RetainPtr<Socket>&& socket, SocketRole role)
|
|||
|
||||
FileDescriptor::~FileDescriptor()
|
||||
{
|
||||
if (m_socket) {
|
||||
m_socket->close(m_socket_role);
|
||||
m_socket = nullptr;
|
||||
}
|
||||
if (m_device) {
|
||||
m_device->close();
|
||||
m_device = nullptr;
|
||||
|
@ -364,6 +369,7 @@ Region* FileDescriptor::mmap(Process& process, LinearAddress laddr, size_t offse
|
|||
// FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
|
||||
ASSERT(laddr.as_ptr() == nullptr);
|
||||
auto* region = process.allocate_file_backed_region(LinearAddress(), size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE);
|
||||
region->page_in();
|
||||
return region;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,3 +108,20 @@ enum KeyCode : byte {
|
|||
Key_Tilde,
|
||||
Key_Backtick,
|
||||
};
|
||||
|
||||
enum KeyModifier {
|
||||
Mod_Alt = 0x01,
|
||||
Mod_Ctrl = 0x02,
|
||||
Mod_Shift = 0x04,
|
||||
Is_Press = 0x80,
|
||||
};
|
||||
|
||||
struct KeyEvent {
|
||||
KeyCode key { Key_Invalid };
|
||||
byte character { 0 };
|
||||
byte flags { 0 };
|
||||
bool alt() const { return flags & Mod_Alt; }
|
||||
bool ctrl() const { return flags & Mod_Ctrl; }
|
||||
bool shift() const { return flags & Mod_Shift; }
|
||||
bool is_press() const { return flags & Is_Press; }
|
||||
};
|
||||
|
|
|
@ -12,22 +12,7 @@ class KeyboardClient;
|
|||
class Keyboard final : public IRQHandler, public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
enum Modifier {
|
||||
Mod_Alt = 0x01,
|
||||
Mod_Ctrl = 0x02,
|
||||
Mod_Shift = 0x04,
|
||||
Is_Press = 0x80,
|
||||
};
|
||||
|
||||
struct Event {
|
||||
KeyCode key { Key_Invalid };
|
||||
byte character { 0 };
|
||||
byte flags { 0 };
|
||||
bool alt() const { return flags & Mod_Alt; }
|
||||
bool ctrl() const { return flags & Mod_Ctrl; }
|
||||
bool shift() const { return flags & Mod_Shift; }
|
||||
bool is_press() const { return flags & Is_Press; }
|
||||
};
|
||||
using Event = KeyEvent;
|
||||
|
||||
[[gnu::pure]] static Keyboard& the();
|
||||
|
||||
|
|
|
@ -106,37 +106,54 @@ bool LocalSocket::connect(const sockaddr* address, socklen_t address_size, int&
|
|||
return true;
|
||||
}
|
||||
|
||||
void LocalSocket::close(SocketRole role)
|
||||
{
|
||||
if (role == SocketRole::Accepted)
|
||||
m_server_closed = true;
|
||||
else if (role == SocketRole::Connected)
|
||||
m_client_closed = true;
|
||||
}
|
||||
|
||||
bool LocalSocket::can_read(SocketRole role) const
|
||||
{
|
||||
if (m_bound && is_listening())
|
||||
return can_accept();
|
||||
|
||||
if (role == SocketRole::Accepted)
|
||||
return !m_for_server.is_empty();
|
||||
else
|
||||
return !m_for_client.is_empty();
|
||||
return m_client_closed || !m_for_server.is_empty();
|
||||
else if (role == SocketRole::Connected)
|
||||
return m_server_closed || !m_for_client.is_empty();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size)
|
||||
{
|
||||
if (role == SocketRole::Accepted)
|
||||
return m_for_server.read(buffer, size);
|
||||
else
|
||||
else if (role == SocketRole::Connected)
|
||||
return m_for_client.read(buffer, size);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size)
|
||||
{
|
||||
if (role == SocketRole::Accepted)
|
||||
if (role == SocketRole::Accepted) {
|
||||
if (m_client_closed)
|
||||
return -EPIPE;
|
||||
return m_for_client.write(data, size);
|
||||
else
|
||||
} else if (role == SocketRole::Connected) {
|
||||
if (m_client_closed)
|
||||
return -EPIPE;
|
||||
return m_for_server.write(data, size);
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool LocalSocket::can_write(SocketRole role) const
|
||||
{
|
||||
if (role == SocketRole::Accepted)
|
||||
return m_for_client.bytes_in_write_buffer() < 4096;
|
||||
else
|
||||
return m_for_server.bytes_in_write_buffer() < 4096;
|
||||
return m_client_closed || m_for_client.bytes_in_write_buffer() < 4096;
|
||||
else if (role == SocketRole::Connected)
|
||||
return m_server_closed || m_for_server.bytes_in_write_buffer() < 4096;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
virtual bool bind(const sockaddr*, socklen_t, int& error) override;
|
||||
virtual bool connect(const sockaddr*, socklen_t, int& error) override;
|
||||
virtual bool get_address(sockaddr*, socklen_t*) override;
|
||||
|
||||
virtual void close(SocketRole) override;
|
||||
virtual bool can_read(SocketRole) const override;
|
||||
virtual ssize_t read(SocketRole, byte*, size_t) override;
|
||||
virtual ssize_t write(SocketRole, const byte*, size_t) override;
|
||||
|
@ -27,6 +27,8 @@ private:
|
|||
RetainPtr<LocalSocket> m_peer;
|
||||
|
||||
bool m_bound { false };
|
||||
bool m_server_closed { false };
|
||||
bool m_client_closed { false };
|
||||
sockaddr_un m_address;
|
||||
|
||||
DoubleBuffer m_for_client;
|
||||
|
|
|
@ -51,26 +51,6 @@ VFS_OBJS = \
|
|||
FileDescriptor.o \
|
||||
SyntheticFileSystem.o
|
||||
|
||||
SHAREDGRAPHICS_OBJS = \
|
||||
../SharedGraphics/Rect.o \
|
||||
../SharedGraphics/Painter.o \
|
||||
../SharedGraphics/Font.o \
|
||||
../SharedGraphics/Color.o \
|
||||
../SharedGraphics/CharacterBitmap.o \
|
||||
../SharedGraphics/GraphicsBitmap.o
|
||||
|
||||
WINDOWSERVER_OBJS = \
|
||||
../WindowServer/WSMessageReceiver.o \
|
||||
../WindowServer/WSMessageLoop.o \
|
||||
../WindowServer/WSWindow.o \
|
||||
../WindowServer/WSWindowManager.o \
|
||||
../WindowServer/WSScreen.o \
|
||||
../WindowServer/WSMenuBar.o \
|
||||
../WindowServer/WSMenu.o \
|
||||
../WindowServer/WSMenuItem.o \
|
||||
../WindowServer/WSClientConnection.o \
|
||||
../WindowServer/main.o
|
||||
|
||||
AK_OBJS = \
|
||||
../AK/String.o \
|
||||
../AK/StringImpl.o \
|
||||
|
@ -78,7 +58,7 @@ AK_OBJS = \
|
|||
../AK/FileSystemPath.o \
|
||||
../AK/StdLibExtras.o
|
||||
|
||||
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(WINDOWSERVER_OBJS) $(SHAREDGRAPHICS_OBJS)
|
||||
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS)
|
||||
|
||||
NASM = nasm
|
||||
KERNEL = kernel
|
||||
|
@ -89,7 +69,7 @@ STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
|
|||
KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident -fno-builtin
|
||||
WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough
|
||||
FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic
|
||||
OPTIMIZATION_FLAGS = -Oz -fno-asynchronous-unwind-tables -fno-omit-frame-pointer
|
||||
OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables -fno-omit-frame-pointer
|
||||
INCLUDE_FLAGS = -I.. -I.
|
||||
#SUGGEST_FLAGS = -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override #-Wsuggest-attribute=noreturn
|
||||
|
||||
|
|
|
@ -581,9 +581,12 @@ bool MemoryManager::validate_user_write(const Process& process, LinearAddress la
|
|||
|
||||
RetainPtr<Region> Region::clone()
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
|
||||
if (m_shared || (m_readable && !m_writable)) {
|
||||
dbgprintf("%s<%u> Region::clone(): sharing %s (L%x)\n",
|
||||
current->name().characters(),
|
||||
current->pid(),
|
||||
m_name.characters(),
|
||||
laddr().get());
|
||||
// Create a new region backed by the same VMObject.
|
||||
return adopt(*new Region(laddr(), size(), m_vmo.copy_ref(), m_offset_in_vmo, String(m_name), m_readable, m_writable));
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ public:
|
|||
const VMObject& vmo() const { return *m_vmo; }
|
||||
VMObject& vmo() { return *m_vmo; }
|
||||
|
||||
bool is_shared() const { return m_shared; }
|
||||
void set_shared(bool shared) { m_shared = shared; }
|
||||
|
||||
bool is_bitmap() const { return m_is_bitmap; }
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
#include "Scheduler.h"
|
||||
#include "FIFO.h"
|
||||
#include "KSyms.h"
|
||||
#include <WindowServer/WSMessageLoop.h>
|
||||
#include <Kernel/Socket.h>
|
||||
#include "MasterPTY.h"
|
||||
#include "elf.h"
|
||||
#include <AK/StringBuilder.h>
|
||||
|
||||
//#define DEBUG_IO
|
||||
//#define TASK_DEBUG
|
||||
//#define FORK_DEBUG
|
||||
#define SIGNAL_DEBUG
|
||||
#define MAX_PROCESS_GIDS 32
|
||||
//#define SHARED_BUFFER_DEBUG
|
||||
|
||||
static const dword default_kernel_stack_size = 16384;
|
||||
static const dword default_userspace_stack_size = 65536;
|
||||
|
@ -49,7 +50,6 @@ void Process::initialize()
|
|||
s_hostname = new String("courage");
|
||||
s_hostname_lock = new Lock;
|
||||
Scheduler::initialize();
|
||||
new WSMessageLoop;
|
||||
}
|
||||
|
||||
Vector<pid_t> Process::all_pids()
|
||||
|
@ -167,11 +167,11 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params)
|
|||
if ((dword)addr & ~PAGE_MASK)
|
||||
return (void*)-EINVAL;
|
||||
if (flags & MAP_ANONYMOUS) {
|
||||
// FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
|
||||
ASSERT(addr == nullptr);
|
||||
auto* region = allocate_region(LinearAddress(), size, "mmap", prot & PROT_READ, prot & PROT_WRITE, false);
|
||||
auto* region = allocate_region(LinearAddress((dword)addr), size, "mmap", prot & PROT_READ, prot & PROT_WRITE, false);
|
||||
if (!region)
|
||||
return (void*)-ENOMEM;
|
||||
if (flags & MAP_SHARED)
|
||||
region->set_shared(true);
|
||||
return region->laddr().as_ptr();
|
||||
}
|
||||
if (offset & ~PAGE_MASK)
|
||||
|
@ -184,6 +184,8 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params)
|
|||
auto* region = descriptor->mmap(*this, LinearAddress((dword)addr), offset, size, prot);
|
||||
if (!region)
|
||||
return (void*)-ENOMEM;
|
||||
if (flags & MAP_SHARED)
|
||||
region->set_shared(true);
|
||||
return region->laddr().as_ptr();
|
||||
}
|
||||
|
||||
|
@ -191,9 +193,9 @@ int Process::sys$munmap(void* addr, size_t size)
|
|||
{
|
||||
auto* region = region_from_range(LinearAddress((dword)addr), size);
|
||||
if (!region)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
if (!deallocate_region(*region))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2136,9 +2138,6 @@ void Process::finalize()
|
|||
{
|
||||
ASSERT(current == g_finalizer);
|
||||
|
||||
if (WSMessageLoop::the().running())
|
||||
WSMessageLoop::the().notify_client_died(gui_client_id());
|
||||
|
||||
m_fds.clear();
|
||||
m_tty = nullptr;
|
||||
disown_all_shared_buffers();
|
||||
|
@ -2367,13 +2366,17 @@ struct SharedBuffer {
|
|||
{
|
||||
if (m_pid1 == process.pid()) {
|
||||
++m_pid1_retain_count;
|
||||
if (!m_pid1_region)
|
||||
if (!m_pid1_region) {
|
||||
m_pid1_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true);
|
||||
m_pid1_region->set_shared(true);
|
||||
}
|
||||
return m_pid1_region->laddr().as_ptr();
|
||||
} else if (m_pid2 == process.pid()) {
|
||||
++m_pid2_retain_count;
|
||||
if (!m_pid2_region)
|
||||
if (!m_pid2_region) {
|
||||
m_pid2_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true);
|
||||
m_pid2_region->set_shared(true);
|
||||
}
|
||||
return m_pid2_region->laddr().as_ptr();
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -2445,7 +2448,9 @@ void SharedBuffer::destroy_if_unused()
|
|||
{
|
||||
if (!m_pid1_retain_count && !m_pid2_retain_count) {
|
||||
LOCKER(shared_buffers().lock());
|
||||
kprintf("Destroying unused SharedBuffer{%p} (pid1: %d, pid2: %d)\n", this, m_pid1, m_pid2);
|
||||
#ifdef SHARED_BUFFER_DEBUG
|
||||
dbgprintf("Destroying unused SharedBuffer{%p} (pid1: %d, pid2: %d)\n", this, m_pid1, m_pid2);
|
||||
#endif
|
||||
shared_buffers().resource().remove(m_shared_buffer_id);
|
||||
}
|
||||
}
|
||||
|
@ -2474,7 +2479,11 @@ int Process::sys$create_shared_buffer(pid_t peer_pid, size_t size, void** buffer
|
|||
int shared_buffer_id = ++s_next_shared_buffer_id;
|
||||
auto shared_buffer = make<SharedBuffer>(m_pid, peer_pid, size);
|
||||
shared_buffer->m_pid1_region = allocate_region_with_vmo(LinearAddress(), shared_buffer->size(), shared_buffer->m_vmo.copy_ref(), 0, "SharedBuffer", true, true);
|
||||
shared_buffer->m_pid1_region->set_shared(true);
|
||||
*buffer = shared_buffer->m_pid1_region->laddr().as_ptr();
|
||||
#ifdef SHARED_BUFFER_DEBUG
|
||||
dbgprintf("%s(%u): Created shared buffer %d (%u bytes, vmo is %u) for sharing with %d\n", name().characters(), pid(),shared_buffer_id, size, shared_buffer->size(), peer_pid);
|
||||
#endif
|
||||
shared_buffers().resource().set(shared_buffer_id, move(shared_buffer));
|
||||
return shared_buffer_id;
|
||||
}
|
||||
|
@ -2486,6 +2495,9 @@ int Process::sys$release_shared_buffer(int shared_buffer_id)
|
|||
if (it == shared_buffers().resource().end())
|
||||
return -EINVAL;
|
||||
auto& shared_buffer = *(*it).value;
|
||||
#ifdef SHARED_BUFFER_DEBUG
|
||||
dbgprintf("%s(%u): Releasing shared buffer %d\n", name().characters(), pid(), shared_buffer_id);
|
||||
#endif
|
||||
shared_buffer.release(*this);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2499,5 +2511,8 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id)
|
|||
auto& shared_buffer = *(*it).value;
|
||||
if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid)
|
||||
return (void*)-EINVAL;
|
||||
#ifdef SHARED_BUFFER_DEBUG
|
||||
dbgprintf("%s(%u): Retaining shared buffer %d\n", name().characters(), pid(), shared_buffer_id);
|
||||
#endif
|
||||
return shared_buffer.retain(*this);
|
||||
}
|
||||
|
|
|
@ -48,9 +48,6 @@ struct DisplayInfo {
|
|||
|
||||
class Process : public InlineLinkedListNode<Process>, public Weakable<Process> {
|
||||
friend class InlineLinkedListNode<Process>;
|
||||
friend class WSWindowManager; // FIXME: Make a better API for allocate_region().
|
||||
friend class GraphicsBitmap; // FIXME: Make a better API for allocate_region().
|
||||
friend class Font; //FIXME: This is beyond gross.
|
||||
public:
|
||||
static Process* create_kernel_process(String&& name, void (*entry)());
|
||||
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);
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
virtual bool connect(const sockaddr*, socklen_t, int& error) = 0;
|
||||
virtual bool get_address(sockaddr*, socklen_t*) = 0;
|
||||
virtual bool is_local() const { return false; }
|
||||
|
||||
virtual void close(SocketRole) = 0;
|
||||
virtual bool can_read(SocketRole) const = 0;
|
||||
virtual ssize_t read(SocketRole, byte*, size_t) = 0;
|
||||
virtual ssize_t write(SocketRole, const byte*, size_t) = 0;
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
#include "BochsVGADevice.h"
|
||||
|
||||
//#define SPAWN_GUITEST
|
||||
#define SPAWN_LAUNCHER
|
||||
//#define SPAWN_LAUNCHER
|
||||
//#define SPAWN_GUITEST2
|
||||
#define SPAWN_FILE_MANAGER
|
||||
//#define SPAWN_FILE_MANAGER
|
||||
//#define SPAWN_FONTEDITOR
|
||||
//#define SPAWN_MULTIPLE_SHELLS
|
||||
//#define STRESS_TEST_SPAWNING
|
||||
|
@ -101,6 +101,10 @@ VFS* vfs;
|
|||
|
||||
int error;
|
||||
|
||||
Process::create_user_process("/bin/WindowServer", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0);
|
||||
if (error != 0) {
|
||||
dbgprintf("error: %d\n", error);
|
||||
}
|
||||
//Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
||||
Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0);
|
||||
#ifdef SPAWN_GUITEST
|
||||
|
@ -128,9 +132,6 @@ VFS* vfs;
|
|||
Process::create_kernel_process("spawn_stress", spawn_stress);
|
||||
#endif
|
||||
|
||||
extern void WindowServer_main();
|
||||
Process::create_kernel_process("WindowServer", WindowServer_main);
|
||||
|
||||
current->sys$exit(0);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ $make_cmd -C ../LibGUI clean && \
|
|||
$make_cmd -C ../LibGUI && \
|
||||
$make_cmd -C ../Userland clean && \
|
||||
$make_cmd -C ../Userland && \
|
||||
$make_cmd -C ../WindowServer clean && \
|
||||
$make_cmd -C ../WindowServer && \
|
||||
$make_cmd -C ../Applications/Terminal clean && \
|
||||
$make_cmd -C ../Applications/Terminal && \
|
||||
$make_cmd -C ../Applications/FontEditor clean && \
|
||||
|
|
|
@ -69,6 +69,7 @@ cp -v ../Applications/Launcher/Launcher mnt/bin/Launcher
|
|||
cp -v ../Applications/Clock/Clock mnt/bin/Clock
|
||||
cp -v ../Applications/FileManager/FileManager mnt/bin/FileManager
|
||||
cp -v ../Applications/About/About mnt/bin/About
|
||||
cp -v ../WindowServer/WindowServer mnt/bin/WindowServer
|
||||
cp -v kernel.map mnt/
|
||||
sh sync-local.sh
|
||||
umount mnt
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue