Просмотр исходного кода

Rework WindowServer to use select() in its main event loop.

The system can finally idle without burning CPU. :^)

There are some issues with scheduling making the mouse cursor sloppy
and unresponsive that need to be dealt with.
Andreas Kling 6 лет назад
Родитель
Сommit
4fef895eda

+ 6 - 1
Kernel/Keyboard.cpp

@@ -125,7 +125,12 @@ ssize_t Keyboard::read(Process&, byte* buffer, size_t size)
     while ((size_t)nread < size) {
         if (m_queue.is_empty())
             break;
-        buffer[nread++] = m_queue.dequeue().character;
+        // Don't return partial data frames.
+        if ((size - nread) < 2)
+            break;
+        auto key = m_queue.dequeue();
+        buffer[nread++] = key.character;
+        buffer[nread++] = key.modifiers;
     }
     return nread;
 }

+ 5 - 5
Kernel/Keyboard.h

@@ -32,16 +32,16 @@ public:
 
     void set_client(KeyboardClient* client) { m_client = client; }
 
-private:
-    // ^IRQHandler
-    virtual void handle_irq() override;
-
     // ^CharacterDevice
     virtual ssize_t read(Process&, byte* buffer, size_t) override;
-    virtual ssize_t write(Process&, const byte* buffer, size_t) override;
     virtual bool can_read(Process&) const override;
+    virtual ssize_t write(Process&, const byte* buffer, size_t) override;
     virtual bool can_write(Process&) const override { return true; }
 
+private:
+    // ^IRQHandler
+    virtual void handle_irq() override;
+
     void emit(byte);
 
     KeyboardClient* m_client { nullptr };

+ 2 - 2
Kernel/MemoryManager.cpp

@@ -537,7 +537,7 @@ bool MemoryManager::validate_user_read(const Process& process, LinearAddress lad
     auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
     if (!pte.is_present())
         return false;
-    if (!pte.is_user_allowed())
+    if (process.isRing3() && !pte.is_user_allowed())
         return false;
     return true;
 }
@@ -552,7 +552,7 @@ bool MemoryManager::validate_user_write(const Process& process, LinearAddress la
     auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
     if (!pte.is_present())
         return false;
-    if (!pte.is_user_allowed())
+    if (process.isRing3() && !pte.is_user_allowed())
         return false;
     if (!pte.is_writable())
         return false;

+ 1 - 0
Kernel/PS2MouseDevice.cpp

@@ -129,6 +129,7 @@ ssize_t PS2MouseDevice::read(Process&, byte* buffer, size_t size)
     while ((size_t)nread < size) {
         if (m_queue.is_empty())
             break;
+        // FIXME: Don't return partial data frames.
         buffer[nread++] = m_queue.dequeue();
     }
     return nread;

+ 18 - 2
Kernel/Process.cpp

@@ -1295,6 +1295,7 @@ int Process::sys$open(const char* path, int options)
     if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
         return -EMFILE;
     int error = -EWHYTHO;
+    ASSERT(cwd_inode());
     auto descriptor = VFS::the().open(path, error, options, cwd_inode()->identifier());
     if (!descriptor)
         return error;
@@ -1960,8 +1961,15 @@ int Process::sys$select(const Syscall::SC_select_params* params)
     transfer_fds(writefds, m_select_write_fds);
     transfer_fds(readfds, m_select_read_fds);
 
-    block(BlockedSelect);
-    Scheduler::yield();
+#ifdef DEBUG_IO
+    dbgprintf("%s<%u> selecting on (read:%u, write:%u)\n", name().characters(), pid(), m_select_read_fds.size(), m_select_write_fds.size());
+#endif
+
+    if (!m_wakeup_requested) {
+        block(BlockedSelect);
+        Scheduler::yield();
+    }
+    m_wakeup_requested = false;
 
     int markedfds = 0;
 
@@ -1989,3 +1997,11 @@ int Process::sys$select(const Syscall::SC_select_params* params)
 
     return markedfds;
 }
+
+Inode* Process::cwd_inode()
+{
+    // FIXME: This is retarded factoring.
+    if (!m_cwd)
+        m_cwd = VFS::the().root_inode();
+    return m_cwd.ptr();
+}

+ 6 - 1
Kernel/Process.h

@@ -236,7 +236,7 @@ public:
     template<typename T> bool validate_read_typed(T* value, size_t count = 1) { return validate_read(value, sizeof(T) * count); }
     template<typename T> bool validate_write_typed(T* value, size_t count = 1) { return validate_write(value, sizeof(T) * count); }
 
-    Inode* cwd_inode() { return m_cwd.ptr(); }
+    Inode* cwd_inode();
     Inode* executable_inode() { return m_executable.ptr(); }
 
     size_t number_of_open_file_descriptors() const;
@@ -256,6 +256,9 @@ public:
     Vector<GUI_Event>& gui_events() { return m_gui_events; }
     SpinLock& gui_events_lock() { return m_gui_events_lock; }
 
+    bool wakeup_requested() { return m_wakeup_requested; }
+    void request_wakeup() { m_wakeup_requested = true; }
+
 private:
     friend class MemoryManager;
     friend class Scheduler;
@@ -357,6 +360,8 @@ private:
     Vector<GUI_Event> m_gui_events;
     SpinLock m_gui_events_lock;
     int m_next_window_id { 1 };
+
+    dword m_wakeup_requested { false };
 };
 
 extern Process* current;

+ 1 - 2
Kernel/ProcessGUI.cpp

@@ -108,8 +108,7 @@ int Process::gui$invalidate_window(int window_id)
     if (it == m_windows.end())
         return -EBADWINDOW;
     auto& window = *(*it).value;
-    // FIXME: This should queue up a message that the window server process can read.
-    //        Poking into its data structures is not good.
     WSEventLoop::the().post_event(&window, make<WSEvent>(WSEvent::WM_Invalidate));
+    WSEventLoop::the().server_process().request_wakeup();
     return 0;
 }

+ 5 - 0
Kernel/Scheduler.cpp

@@ -65,6 +65,11 @@ bool Scheduler::pick_next()
         }
 
         if (process.state() == Process::BlockedSelect) {
+            if (process.wakeup_requested()) {
+                process.m_wakeup_requested = false;
+                process.unblock();
+                return true;
+            }
             for (int fd : process.m_select_read_fds) {
                 if (process.m_fds[fd].descriptor->can_read(process)) {
                     process.unblock();

+ 4 - 3
Kernel/init.cpp

@@ -37,6 +37,7 @@ VirtualConsole* tty3;
 Keyboard* keyboard;
 PS2MouseDevice* ps2mouse;
 GUIEventDevice* gui_event_device;
+VFS* vfs;
 
 #ifdef STRESS_TEST_SPAWNING
 static void spawn_stress() NORETURN;
@@ -62,8 +63,6 @@ static void init_stage2()
 {
     Syscall::initialize();
 
-    auto vfs = make<VFS>();
-
     auto dev_zero = make<ZeroDevice>();
     vfs->register_character_device(*dev_zero);
 
@@ -138,6 +137,9 @@ void init()
     gdt_init();
     idt_init();
 
+    VFS::initialize_globals();
+    vfs = new VFS;
+
     keyboard = new Keyboard;
     ps2mouse = new PS2MouseDevice;
     gui_event_device = new GUIEventDevice;
@@ -153,7 +155,6 @@ void init()
 
     MemoryManager::initialize();
 
-    VFS::initialize_globals();
     StringImpl::initialize_globals();
 
     PIT::initialize();

+ 1 - 0
Kernel/sync.sh

@@ -8,6 +8,7 @@ mknod mnt/dev/tty0 c 4 0
 mknod mnt/dev/tty1 c 4 1
 mknod mnt/dev/tty2 c 4 2
 mknod mnt/dev/tty3 c 4 3
+mknod mnt/dev/keyboard c 85 1
 mknod mnt/dev/psaux c 10 1
 mknod mnt/dev/ptmx c 5 2
 mknod mnt/dev/ptm0 c 10 0

+ 60 - 6
WindowServer/WSEventLoop.cpp

@@ -4,7 +4,9 @@
 #include "WSWindowManager.h"
 #include "WSScreen.h"
 #include "PS2MouseDevice.h"
-#include "Scheduler.h"
+#include <Kernel/Keyboard.h>
+#include <AK/Bitmap.h>
+#include "Process.h"
 
 //#define WSEVENTLOOP_DEBUG
 
@@ -34,10 +36,19 @@ WSEventLoop& WSEventLoop::the()
 int WSEventLoop::exec()
 {
     m_server_process = current;
+
+    m_keyboard_fd = m_server_process->sys$open("/dev/keyboard", O_RDONLY);
+    m_mouse_fd = m_server_process->sys$open("/dev/psaux", O_RDONLY);
+
+    ASSERT(m_keyboard_fd >= 0);
+    ASSERT(m_mouse_fd >= 0);
+
     m_running = true;
     for (;;) {
+
         if (m_queued_events.is_empty())
-            waitForEvent();
+            wait_for_event();
+
         Vector<QueuedEvent> events;
         {
             LOCKER(m_lock);
@@ -69,20 +80,48 @@ void WSEventLoop::post_event(WSEventReceiver* receiver, OwnPtr<WSEvent>&& event)
     dbgprintf("WSEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
 #endif
     m_queued_events.append({ receiver, move(event) });
+
+    if (current != m_server_process)
+        m_server_process->request_wakeup();
 }
 
-void WSEventLoop::waitForEvent()
+void WSEventLoop::wait_for_event()
+{
+    fd_set rfds;
+    memset(&rfds, 0, sizeof(rfds));
+    auto bitmap = Bitmap::wrap((byte*)&rfds, FD_SETSIZE);
+    bitmap.set(m_keyboard_fd, true);
+    bitmap.set(m_mouse_fd, true);
+    Syscall::SC_select_params params;
+    params.nfds = max(m_keyboard_fd, m_mouse_fd) + 1;
+    params.readfds = &rfds;
+    params.writefds = nullptr;
+    params.exceptfds = nullptr;
+    params.timeout = nullptr;
+    int rc = m_server_process->sys$select(&params);
+    memory_barrier();
+    if (rc < 0) {
+        ASSERT_NOT_REACHED();
+    }
+
+    //if (bitmap.get(m_keyboard_fd))
+        drain_keyboard();
+    //if (bitmap.get(m_mouse_fd))
+        drain_mouse();
+}
+
+void WSEventLoop::drain_mouse()
 {
-    auto& mouse = PS2MouseDevice::the();
     auto& screen = WSScreen::the();
+    auto& mouse = PS2MouseDevice::the();
     bool prev_left_button = screen.left_mouse_button_pressed();
     bool prev_right_button = screen.right_mouse_button_pressed();
     int dx = 0;
     int dy = 0;
     while (mouse.can_read(*m_server_process)) {
         signed_byte data[3];
-        ssize_t nread = mouse.read(*m_server_process, (byte*)data, 3);
-        ASSERT(nread == 3);
+        ssize_t nread = mouse.read(*m_server_process, (byte*)data, sizeof(data));
+        ASSERT(nread == sizeof(data));
         bool left_button = data[0] & 1;
         bool right_button = data[0] & 2;
         dx += data[1];
@@ -96,3 +135,18 @@ void WSEventLoop::waitForEvent()
         }
     }
 }
+
+void WSEventLoop::drain_keyboard()
+{
+    auto& screen = WSScreen::the();
+    auto& keyboard = Keyboard::the();
+    while (keyboard.can_read(*m_server_process)) {
+        byte data[2];
+        ssize_t nread = keyboard.read(*m_server_process, (byte*)data, sizeof(data));
+        ASSERT(nread == sizeof(data));
+        Keyboard::Key key;
+        key.character = data[0];
+        key.modifiers = data[1];
+        screen.on_receive_keyboard_data(key);
+    }
+}

+ 6 - 1
WindowServer/WSEventLoop.h

@@ -25,7 +25,9 @@ public:
     Process& server_process() { return *m_server_process; }
 
 private:
-    void waitForEvent();
+    void wait_for_event();
+    void drain_mouse();
+    void drain_keyboard();
 
     SpinLock m_lock;
 
@@ -37,4 +39,7 @@ private:
 
     Process* m_server_process { nullptr };
     bool m_running { false };
+
+    int m_keyboard_fd { -1 };
+    int m_mouse_fd { -1 };
 };

+ 1 - 1
WindowServer/WSFrameBuffer.h

@@ -9,7 +9,7 @@ class WSFrameBuffer final : public WSScreen {
 public:
     WSFrameBuffer(unsigned width, unsigned height);
     WSFrameBuffer(RGBA32*, unsigned width, unsigned height);
-    virtual ~WSFrameBuffer() override;
+    ~WSFrameBuffer();
 
     void show();
 

+ 1 - 3
WindowServer/WSScreen.cpp

@@ -25,8 +25,6 @@ WSScreen::WSScreen(unsigned width, unsigned height)
     s_the = this;
 
     m_cursor_location = rect().center();
-
-    Keyboard::the().set_client(this);
 }
 
 WSScreen::~WSScreen()
@@ -62,7 +60,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
         WSWindowManager::the().draw_cursor();
 }
 
-void WSScreen::on_key_pressed(Keyboard::Key key)
+void WSScreen::on_receive_keyboard_data(Keyboard::Key key)
 {
     auto event = make<KeyEvent>(WSEvent::KeyDown, 0);
     int key_code = 0;

+ 3 - 5
WindowServer/WSScreen.h

@@ -4,9 +4,9 @@
 #include <Widgets/Size.h>
 #include <Kernel/Keyboard.h>
 
-class WSScreen : public KeyboardClient {
+class WSScreen {
 public:
-    virtual ~WSScreen();
+    ~WSScreen();
 
     int width() const { return m_width; }
     int height() const { return m_height; }
@@ -23,14 +23,12 @@ public:
     bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; }
 
     void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button);
+    void on_receive_keyboard_data(Keyboard::Key);
 
 protected:
     WSScreen(unsigned width, unsigned height);
 
 private:
-    // ^KeyboardClient
-    virtual void on_key_pressed(Keyboard::Key) final;
-
     int m_width { 0 };
     int m_height { 0 };