mirror of
https://github.com/RGBCube/serenity
synced 2025-05-19 23:35:08 +00:00
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.
This commit is contained in:
parent
f7ca6d254d
commit
4fef895eda
15 changed files with 121 additions and 33 deletions
|
@ -125,7 +125,12 @@ ssize_t Keyboard::read(Process&, byte* buffer, size_t size)
|
||||||
while ((size_t)nread < size) {
|
while ((size_t)nread < size) {
|
||||||
if (m_queue.is_empty())
|
if (m_queue.is_empty())
|
||||||
break;
|
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;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,16 @@ public:
|
||||||
|
|
||||||
void set_client(KeyboardClient* client) { m_client = client; }
|
void set_client(KeyboardClient* client) { m_client = client; }
|
||||||
|
|
||||||
|
// ^CharacterDevice
|
||||||
|
virtual ssize_t read(Process&, 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:
|
private:
|
||||||
// ^IRQHandler
|
// ^IRQHandler
|
||||||
virtual void handle_irq() override;
|
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 bool can_write(Process&) const override { return true; }
|
|
||||||
|
|
||||||
void emit(byte);
|
void emit(byte);
|
||||||
|
|
||||||
KeyboardClient* m_client { nullptr };
|
KeyboardClient* m_client { nullptr };
|
||||||
|
|
|
@ -537,7 +537,7 @@ bool MemoryManager::validate_user_read(const Process& process, LinearAddress lad
|
||||||
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
|
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
|
||||||
if (!pte.is_present())
|
if (!pte.is_present())
|
||||||
return false;
|
return false;
|
||||||
if (!pte.is_user_allowed())
|
if (process.isRing3() && !pte.is_user_allowed())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,7 @@ bool MemoryManager::validate_user_write(const Process& process, LinearAddress la
|
||||||
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
|
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
|
||||||
if (!pte.is_present())
|
if (!pte.is_present())
|
||||||
return false;
|
return false;
|
||||||
if (!pte.is_user_allowed())
|
if (process.isRing3() && !pte.is_user_allowed())
|
||||||
return false;
|
return false;
|
||||||
if (!pte.is_writable())
|
if (!pte.is_writable())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -129,6 +129,7 @@ ssize_t PS2MouseDevice::read(Process&, byte* buffer, size_t size)
|
||||||
while ((size_t)nread < size) {
|
while ((size_t)nread < size) {
|
||||||
if (m_queue.is_empty())
|
if (m_queue.is_empty())
|
||||||
break;
|
break;
|
||||||
|
// FIXME: Don't return partial data frames.
|
||||||
buffer[nread++] = m_queue.dequeue();
|
buffer[nread++] = m_queue.dequeue();
|
||||||
}
|
}
|
||||||
return nread;
|
return nread;
|
||||||
|
|
|
@ -1295,6 +1295,7 @@ int Process::sys$open(const char* path, int options)
|
||||||
if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
|
if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
|
||||||
return -EMFILE;
|
return -EMFILE;
|
||||||
int error = -EWHYTHO;
|
int error = -EWHYTHO;
|
||||||
|
ASSERT(cwd_inode());
|
||||||
auto descriptor = VFS::the().open(path, error, options, cwd_inode()->identifier());
|
auto descriptor = VFS::the().open(path, error, options, cwd_inode()->identifier());
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
return error;
|
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(writefds, m_select_write_fds);
|
||||||
transfer_fds(readfds, m_select_read_fds);
|
transfer_fds(readfds, m_select_read_fds);
|
||||||
|
|
||||||
block(BlockedSelect);
|
#ifdef DEBUG_IO
|
||||||
Scheduler::yield();
|
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;
|
int markedfds = 0;
|
||||||
|
|
||||||
|
@ -1989,3 +1997,11 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
|
|
||||||
return markedfds;
|
return markedfds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inode* Process::cwd_inode()
|
||||||
|
{
|
||||||
|
// FIXME: This is retarded factoring.
|
||||||
|
if (!m_cwd)
|
||||||
|
m_cwd = VFS::the().root_inode();
|
||||||
|
return m_cwd.ptr();
|
||||||
|
}
|
||||||
|
|
|
@ -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_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); }
|
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(); }
|
Inode* executable_inode() { return m_executable.ptr(); }
|
||||||
|
|
||||||
size_t number_of_open_file_descriptors() const;
|
size_t number_of_open_file_descriptors() const;
|
||||||
|
@ -256,6 +256,9 @@ public:
|
||||||
Vector<GUI_Event>& gui_events() { return m_gui_events; }
|
Vector<GUI_Event>& gui_events() { return m_gui_events; }
|
||||||
SpinLock& gui_events_lock() { return m_gui_events_lock; }
|
SpinLock& gui_events_lock() { return m_gui_events_lock; }
|
||||||
|
|
||||||
|
bool wakeup_requested() { return m_wakeup_requested; }
|
||||||
|
void request_wakeup() { m_wakeup_requested = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
friend class Scheduler;
|
friend class Scheduler;
|
||||||
|
@ -357,6 +360,8 @@ private:
|
||||||
Vector<GUI_Event> m_gui_events;
|
Vector<GUI_Event> m_gui_events;
|
||||||
SpinLock m_gui_events_lock;
|
SpinLock m_gui_events_lock;
|
||||||
int m_next_window_id { 1 };
|
int m_next_window_id { 1 };
|
||||||
|
|
||||||
|
dword m_wakeup_requested { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Process* current;
|
extern Process* current;
|
||||||
|
|
|
@ -108,8 +108,7 @@ int Process::gui$invalidate_window(int window_id)
|
||||||
if (it == m_windows.end())
|
if (it == m_windows.end())
|
||||||
return -EBADWINDOW;
|
return -EBADWINDOW;
|
||||||
auto& window = *(*it).value;
|
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().post_event(&window, make<WSEvent>(WSEvent::WM_Invalidate));
|
||||||
|
WSEventLoop::the().server_process().request_wakeup();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,11 @@ bool Scheduler::pick_next()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.state() == Process::BlockedSelect) {
|
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) {
|
for (int fd : process.m_select_read_fds) {
|
||||||
if (process.m_fds[fd].descriptor->can_read(process)) {
|
if (process.m_fds[fd].descriptor->can_read(process)) {
|
||||||
process.unblock();
|
process.unblock();
|
||||||
|
|
|
@ -37,6 +37,7 @@ VirtualConsole* tty3;
|
||||||
Keyboard* keyboard;
|
Keyboard* keyboard;
|
||||||
PS2MouseDevice* ps2mouse;
|
PS2MouseDevice* ps2mouse;
|
||||||
GUIEventDevice* gui_event_device;
|
GUIEventDevice* gui_event_device;
|
||||||
|
VFS* vfs;
|
||||||
|
|
||||||
#ifdef STRESS_TEST_SPAWNING
|
#ifdef STRESS_TEST_SPAWNING
|
||||||
static void spawn_stress() NORETURN;
|
static void spawn_stress() NORETURN;
|
||||||
|
@ -62,8 +63,6 @@ static void init_stage2()
|
||||||
{
|
{
|
||||||
Syscall::initialize();
|
Syscall::initialize();
|
||||||
|
|
||||||
auto vfs = make<VFS>();
|
|
||||||
|
|
||||||
auto dev_zero = make<ZeroDevice>();
|
auto dev_zero = make<ZeroDevice>();
|
||||||
vfs->register_character_device(*dev_zero);
|
vfs->register_character_device(*dev_zero);
|
||||||
|
|
||||||
|
@ -138,6 +137,9 @@ void init()
|
||||||
gdt_init();
|
gdt_init();
|
||||||
idt_init();
|
idt_init();
|
||||||
|
|
||||||
|
VFS::initialize_globals();
|
||||||
|
vfs = new VFS;
|
||||||
|
|
||||||
keyboard = new Keyboard;
|
keyboard = new Keyboard;
|
||||||
ps2mouse = new PS2MouseDevice;
|
ps2mouse = new PS2MouseDevice;
|
||||||
gui_event_device = new GUIEventDevice;
|
gui_event_device = new GUIEventDevice;
|
||||||
|
@ -153,7 +155,6 @@ void init()
|
||||||
|
|
||||||
MemoryManager::initialize();
|
MemoryManager::initialize();
|
||||||
|
|
||||||
VFS::initialize_globals();
|
|
||||||
StringImpl::initialize_globals();
|
StringImpl::initialize_globals();
|
||||||
|
|
||||||
PIT::initialize();
|
PIT::initialize();
|
||||||
|
|
|
@ -8,6 +8,7 @@ mknod mnt/dev/tty0 c 4 0
|
||||||
mknod mnt/dev/tty1 c 4 1
|
mknod mnt/dev/tty1 c 4 1
|
||||||
mknod mnt/dev/tty2 c 4 2
|
mknod mnt/dev/tty2 c 4 2
|
||||||
mknod mnt/dev/tty3 c 4 3
|
mknod mnt/dev/tty3 c 4 3
|
||||||
|
mknod mnt/dev/keyboard c 85 1
|
||||||
mknod mnt/dev/psaux c 10 1
|
mknod mnt/dev/psaux c 10 1
|
||||||
mknod mnt/dev/ptmx c 5 2
|
mknod mnt/dev/ptmx c 5 2
|
||||||
mknod mnt/dev/ptm0 c 10 0
|
mknod mnt/dev/ptm0 c 10 0
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
#include "WSWindowManager.h"
|
#include "WSWindowManager.h"
|
||||||
#include "WSScreen.h"
|
#include "WSScreen.h"
|
||||||
#include "PS2MouseDevice.h"
|
#include "PS2MouseDevice.h"
|
||||||
#include "Scheduler.h"
|
#include <Kernel/Keyboard.h>
|
||||||
|
#include <AK/Bitmap.h>
|
||||||
|
#include "Process.h"
|
||||||
|
|
||||||
//#define WSEVENTLOOP_DEBUG
|
//#define WSEVENTLOOP_DEBUG
|
||||||
|
|
||||||
|
@ -34,10 +36,19 @@ WSEventLoop& WSEventLoop::the()
|
||||||
int WSEventLoop::exec()
|
int WSEventLoop::exec()
|
||||||
{
|
{
|
||||||
m_server_process = current;
|
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;
|
m_running = true;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
if (m_queued_events.is_empty())
|
if (m_queued_events.is_empty())
|
||||||
waitForEvent();
|
wait_for_event();
|
||||||
|
|
||||||
Vector<QueuedEvent> events;
|
Vector<QueuedEvent> events;
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
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());
|
dbgprintf("WSEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
|
||||||
#endif
|
#endif
|
||||||
m_queued_events.append({ receiver, move(event) });
|
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(¶ms);
|
||||||
|
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& screen = WSScreen::the();
|
||||||
|
auto& mouse = PS2MouseDevice::the();
|
||||||
bool prev_left_button = screen.left_mouse_button_pressed();
|
bool prev_left_button = screen.left_mouse_button_pressed();
|
||||||
bool prev_right_button = screen.right_mouse_button_pressed();
|
bool prev_right_button = screen.right_mouse_button_pressed();
|
||||||
int dx = 0;
|
int dx = 0;
|
||||||
int dy = 0;
|
int dy = 0;
|
||||||
while (mouse.can_read(*m_server_process)) {
|
while (mouse.can_read(*m_server_process)) {
|
||||||
signed_byte data[3];
|
signed_byte data[3];
|
||||||
ssize_t nread = mouse.read(*m_server_process, (byte*)data, 3);
|
ssize_t nread = mouse.read(*m_server_process, (byte*)data, sizeof(data));
|
||||||
ASSERT(nread == 3);
|
ASSERT(nread == sizeof(data));
|
||||||
bool left_button = data[0] & 1;
|
bool left_button = data[0] & 1;
|
||||||
bool right_button = data[0] & 2;
|
bool right_button = data[0] & 2;
|
||||||
dx += data[1];
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ public:
|
||||||
Process& server_process() { return *m_server_process; }
|
Process& server_process() { return *m_server_process; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void waitForEvent();
|
void wait_for_event();
|
||||||
|
void drain_mouse();
|
||||||
|
void drain_keyboard();
|
||||||
|
|
||||||
SpinLock m_lock;
|
SpinLock m_lock;
|
||||||
|
|
||||||
|
@ -37,4 +39,7 @@ private:
|
||||||
|
|
||||||
Process* m_server_process { nullptr };
|
Process* m_server_process { nullptr };
|
||||||
bool m_running { false };
|
bool m_running { false };
|
||||||
|
|
||||||
|
int m_keyboard_fd { -1 };
|
||||||
|
int m_mouse_fd { -1 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ class WSFrameBuffer final : public WSScreen {
|
||||||
public:
|
public:
|
||||||
WSFrameBuffer(unsigned width, unsigned height);
|
WSFrameBuffer(unsigned width, unsigned height);
|
||||||
WSFrameBuffer(RGBA32*, unsigned width, unsigned height);
|
WSFrameBuffer(RGBA32*, unsigned width, unsigned height);
|
||||||
virtual ~WSFrameBuffer() override;
|
~WSFrameBuffer();
|
||||||
|
|
||||||
void show();
|
void show();
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,6 @@ WSScreen::WSScreen(unsigned width, unsigned height)
|
||||||
s_the = this;
|
s_the = this;
|
||||||
|
|
||||||
m_cursor_location = rect().center();
|
m_cursor_location = rect().center();
|
||||||
|
|
||||||
Keyboard::the().set_client(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WSScreen::~WSScreen()
|
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();
|
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);
|
auto event = make<KeyEvent>(WSEvent::KeyDown, 0);
|
||||||
int key_code = 0;
|
int key_code = 0;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
#include <Widgets/Size.h>
|
#include <Widgets/Size.h>
|
||||||
#include <Kernel/Keyboard.h>
|
#include <Kernel/Keyboard.h>
|
||||||
|
|
||||||
class WSScreen : public KeyboardClient {
|
class WSScreen {
|
||||||
public:
|
public:
|
||||||
virtual ~WSScreen();
|
~WSScreen();
|
||||||
|
|
||||||
int width() const { return m_width; }
|
int width() const { return m_width; }
|
||||||
int height() const { return m_height; }
|
int height() const { return m_height; }
|
||||||
|
@ -23,14 +23,12 @@ public:
|
||||||
bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; }
|
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_mouse_data(int dx, int dy, bool left_button, bool right_button);
|
||||||
|
void on_receive_keyboard_data(Keyboard::Key);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
WSScreen(unsigned width, unsigned height);
|
WSScreen(unsigned width, unsigned height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^KeyboardClient
|
|
||||||
virtual void on_key_pressed(Keyboard::Key) final;
|
|
||||||
|
|
||||||
int m_width { 0 };
|
int m_width { 0 };
|
||||||
int m_height { 0 };
|
int m_height { 0 };
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue