mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:37:35 +00:00
Implement basic support for POSIX-style select().
Now we can block on both the PTY *and* the GUI event stream in Terminal.
This commit is contained in:
parent
46181cf023
commit
10387beda7
8 changed files with 164 additions and 30 deletions
|
@ -1909,3 +1909,78 @@ DisplayInfo Process::get_display_info()
|
||||||
info.framebuffer = m_display_framebuffer_region->linearAddress.asPtr();
|
info.framebuffer = m_display_framebuffer_region->linearAddress.asPtr();
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
|
{
|
||||||
|
if (!validate_read_typed(params))
|
||||||
|
return -EFAULT;
|
||||||
|
if (params->writefds && !validate_read_typed(params->writefds))
|
||||||
|
return -EFAULT;
|
||||||
|
if (params->readfds && !validate_read_typed(params->readfds))
|
||||||
|
return -EFAULT;
|
||||||
|
if (params->exceptfds && !validate_read_typed(params->exceptfds))
|
||||||
|
return -EFAULT;
|
||||||
|
if (params->timeout && !validate_read_typed(params->timeout))
|
||||||
|
return -EFAULT;
|
||||||
|
int nfds = params->nfds;
|
||||||
|
fd_set* writefds = params->writefds;
|
||||||
|
fd_set* readfds = params->readfds;
|
||||||
|
fd_set* exceptfds = params->exceptfds;
|
||||||
|
auto* timeout = params->timeout;
|
||||||
|
|
||||||
|
// FIXME: Implement exceptfds support.
|
||||||
|
ASSERT(!exceptfds);
|
||||||
|
|
||||||
|
// FIXME: Implement timeout support.
|
||||||
|
ASSERT(!timeout);
|
||||||
|
|
||||||
|
if (nfds < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
// FIXME: Return -EBADF if one of the fd sets contains an invalid fd.
|
||||||
|
// FIXME: Return -EINTR if a signal is caught.
|
||||||
|
// FIXME: Return -EINVAL if timeout is invalid.
|
||||||
|
|
||||||
|
auto transfer_fds = [nfds] (fd_set* set, auto& vector) {
|
||||||
|
if (!set)
|
||||||
|
return;
|
||||||
|
vector.clear_with_capacity();
|
||||||
|
auto bitmap = Bitmap::wrap((byte*)set, FD_SETSIZE);
|
||||||
|
for (int i = 0; i < nfds; ++i) {
|
||||||
|
if (bitmap.get(i))
|
||||||
|
vector.append(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
transfer_fds(writefds, m_select_write_fds);
|
||||||
|
transfer_fds(readfds, m_select_read_fds);
|
||||||
|
|
||||||
|
block(BlockedSelect);
|
||||||
|
Scheduler::yield();
|
||||||
|
|
||||||
|
int markedfds = 0;
|
||||||
|
|
||||||
|
if (readfds) {
|
||||||
|
memset(readfds, 0, sizeof(fd_set));
|
||||||
|
auto bitmap = Bitmap::wrap((byte*)readfds, FD_SETSIZE);
|
||||||
|
for (int fd : m_select_read_fds) {
|
||||||
|
if (m_fds[fd].descriptor->has_data_available_for_reading(*this)) {
|
||||||
|
bitmap.set(fd, true);
|
||||||
|
++markedfds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writefds) {
|
||||||
|
memset(writefds, 0, sizeof(fd_set));
|
||||||
|
auto bitmap = Bitmap::wrap((byte*)writefds, FD_SETSIZE);
|
||||||
|
for (int fd : m_select_write_fds) {
|
||||||
|
if (m_fds[fd].descriptor->can_write(*this)) {
|
||||||
|
bitmap.set(fd, true);
|
||||||
|
++markedfds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return markedfds;
|
||||||
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
BlockedRead,
|
BlockedRead,
|
||||||
BlockedWrite,
|
BlockedWrite,
|
||||||
BlockedSignal,
|
BlockedSignal,
|
||||||
|
BlockedSelect,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RingLevel {
|
enum RingLevel {
|
||||||
|
@ -81,7 +82,7 @@ public:
|
||||||
|
|
||||||
bool is_blocked() const
|
bool is_blocked() const
|
||||||
{
|
{
|
||||||
return m_state == BlockedSleep || m_state == BlockedWait || m_state == BlockedRead || m_state == BlockedSignal;
|
return m_state == BlockedSleep || m_state == BlockedWait || m_state == BlockedRead || m_state == BlockedSignal || m_state == BlockedSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirectory& page_directory() { return *m_page_directory; }
|
PageDirectory& page_directory() { return *m_page_directory; }
|
||||||
|
@ -156,6 +157,7 @@ public:
|
||||||
void* sys$mmap(const Syscall::SC_mmap_params*);
|
void* sys$mmap(const Syscall::SC_mmap_params*);
|
||||||
int sys$munmap(void*, size_t size);
|
int sys$munmap(void*, size_t size);
|
||||||
int sys$set_mmap_name(void*, size_t, const char*);
|
int sys$set_mmap_name(void*, size_t, const char*);
|
||||||
|
int sys$select(const Syscall::SC_select_params*);
|
||||||
ssize_t sys$get_dir_entries(int fd, void*, size_t);
|
ssize_t sys$get_dir_entries(int fd, void*, size_t);
|
||||||
int sys$getcwd(char*, size_t);
|
int sys$getcwd(char*, size_t);
|
||||||
int sys$chdir(const char*);
|
int sys$chdir(const char*);
|
||||||
|
@ -304,6 +306,8 @@ private:
|
||||||
dword m_timesScheduled { 0 };
|
dword m_timesScheduled { 0 };
|
||||||
pid_t m_waitee_pid { -1 };
|
pid_t m_waitee_pid { -1 };
|
||||||
int m_blocked_fd { -1 };
|
int m_blocked_fd { -1 };
|
||||||
|
Vector<int> m_select_read_fds;
|
||||||
|
Vector<int> m_select_write_fds;
|
||||||
size_t m_max_open_file_descriptors { 16 };
|
size_t m_max_open_file_descriptors { 16 };
|
||||||
SignalActionData m_signal_action_data[32];
|
SignalActionData m_signal_action_data[32];
|
||||||
dword m_pending_signals { 0 };
|
dword m_pending_signals { 0 };
|
||||||
|
@ -394,6 +398,7 @@ static inline const char* toString(Process::State state)
|
||||||
case Process::BlockedRead: return "Read";
|
case Process::BlockedRead: return "Read";
|
||||||
case Process::BlockedWrite: return "Write";
|
case Process::BlockedWrite: return "Write";
|
||||||
case Process::BlockedSignal: return "Signal";
|
case Process::BlockedSignal: return "Signal";
|
||||||
|
case Process::BlockedSelect: return "Select";
|
||||||
case Process::BeingInspected: return "Inspect";
|
case Process::BeingInspected: return "Inspect";
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
|
|
@ -64,6 +64,22 @@ bool Scheduler::pick_next()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.state() == Process::BlockedSelect) {
|
||||||
|
for (int fd : process.m_select_read_fds) {
|
||||||
|
if (process.m_fds[fd].descriptor->has_data_available_for_reading(process)) {
|
||||||
|
process.unblock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int fd : process.m_select_write_fds) {
|
||||||
|
if (process.m_fds[fd].descriptor->can_write(process)) {
|
||||||
|
process.unblock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (process.state() == Process::Skip1SchedulerPass) {
|
if (process.state() == Process::Skip1SchedulerPass) {
|
||||||
process.set_state(Process::Skip0SchedulerPasses);
|
process.set_state(Process::Skip0SchedulerPasses);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -98,6 +98,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
||||||
return current->sys$waitpid((pid_t)arg1, (int*)arg2, (int)arg3);
|
return current->sys$waitpid((pid_t)arg1, (int*)arg2, (int)arg3);
|
||||||
case Syscall::SC_mmap:
|
case Syscall::SC_mmap:
|
||||||
return (dword)current->sys$mmap((const SC_mmap_params*)arg1);
|
return (dword)current->sys$mmap((const SC_mmap_params*)arg1);
|
||||||
|
case Syscall::SC_select:
|
||||||
|
return current->sys$select((const SC_select_params*)arg1);
|
||||||
case Syscall::SC_munmap:
|
case Syscall::SC_munmap:
|
||||||
return current->sys$munmap((void*)arg1, (size_t)arg2);
|
return current->sys$munmap((void*)arg1, (size_t)arg2);
|
||||||
case Syscall::SC_gethostname:
|
case Syscall::SC_gethostname:
|
||||||
|
|
|
@ -71,8 +71,11 @@
|
||||||
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
||||||
__ENUMERATE_SYSCALL(gui_get_window_backing_store) \
|
__ENUMERATE_SYSCALL(gui_get_window_backing_store) \
|
||||||
__ENUMERATE_SYSCALL(gui_invalidate_window) \
|
__ENUMERATE_SYSCALL(gui_invalidate_window) \
|
||||||
|
__ENUMERATE_SYSCALL(select) \
|
||||||
|
|
||||||
|
|
||||||
|
struct fd_set;
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
enum Function {
|
enum Function {
|
||||||
|
@ -102,6 +105,14 @@ struct SC_mmap_params {
|
||||||
int32_t offset; // FIXME: 64-bit off_t?
|
int32_t offset; // FIXME: 64-bit off_t?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_select_params {
|
||||||
|
int nfds;
|
||||||
|
fd_set* readfds;
|
||||||
|
fd_set* writefds;
|
||||||
|
fd_set* exceptfds;
|
||||||
|
struct timeval* timeout;
|
||||||
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
int sync();
|
int sync();
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ LIBC_OBJS = \
|
||||||
math.o \
|
math.o \
|
||||||
utime.o \
|
utime.o \
|
||||||
gui.o \
|
gui.o \
|
||||||
|
sys/select.o \
|
||||||
entry.o
|
entry.o
|
||||||
|
|
||||||
OBJS = $(AK_OBJS) $(WIDGETS_OBJS) $(LIBC_OBJS)
|
OBJS = $(AK_OBJS) $(WIDGETS_OBJS) $(LIBC_OBJS)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <Widgets/GraphicsBitmap.h>
|
#include <Widgets/GraphicsBitmap.h>
|
||||||
#include <Widgets/Painter.h>
|
#include <Widgets/Painter.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
#include <gui.h>
|
#include <gui.h>
|
||||||
#include "Terminal.h"
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
@ -53,9 +54,14 @@ static void make_shell(int ptm_fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int max(int a, int b)
|
||||||
|
{
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int, char**)
|
int main(int, char**)
|
||||||
{
|
{
|
||||||
int ptm_fd = open("/dev/ptm0", O_RDWR | O_NONBLOCK);
|
int ptm_fd = open("/dev/ptm0", O_RDWR);
|
||||||
if (ptm_fd < 0) {
|
if (ptm_fd < 0) {
|
||||||
perror("open");
|
perror("open");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -63,7 +69,7 @@ int main(int, char**)
|
||||||
|
|
||||||
make_shell(ptm_fd);
|
make_shell(ptm_fd);
|
||||||
|
|
||||||
int event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK);
|
int event_fd = open("/dev/gui_events", O_RDONLY);
|
||||||
if (event_fd < 0) {
|
if (event_fd < 0) {
|
||||||
perror("open");
|
perror("open");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -74,38 +80,53 @@ int main(int, char**)
|
||||||
terminal.paint();
|
terminal.paint();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
byte buffer[1024];
|
fd_set rfds;
|
||||||
ssize_t ptm_nread = read(ptm_fd, buffer, sizeof(buffer));
|
FD_ZERO(&rfds);
|
||||||
if (ptm_nread > 0) {
|
FD_SET(ptm_fd, &rfds);
|
||||||
for (ssize_t i = 0; i < ptm_nread; ++i)
|
FD_SET(event_fd, &rfds);
|
||||||
|
int nfds = select(max(ptm_fd, event_fd) + 1, &rfds, nullptr, nullptr, nullptr);
|
||||||
|
if (nfds < 0) {
|
||||||
|
dbgprintf("Terminal(%u) select() failed :( errno=%d\n", getpid(), errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(ptm_fd, &rfds)) {
|
||||||
|
byte buffer[1024];
|
||||||
|
ssize_t nread = read(ptm_fd, buffer, sizeof(buffer));
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("read(ptm)");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert(nread != 0);
|
||||||
|
for (ssize_t i = 0; i < nread; ++i)
|
||||||
terminal.on_char(buffer[i]);
|
terminal.on_char(buffer[i]);
|
||||||
terminal.paint();
|
terminal.paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI_Event event;
|
if (FD_ISSET(event_fd, &rfds)) {
|
||||||
ssize_t nread = read(event_fd, &event, sizeof(event));
|
GUI_Event event;
|
||||||
if (nread < 0) {
|
ssize_t nread = read(event_fd, &event, sizeof(event));
|
||||||
perror("read");
|
if (nread < 0) {
|
||||||
return 1;
|
perror("read(event)");
|
||||||
}
|
return 1;
|
||||||
if (nread == 0)
|
}
|
||||||
continue;
|
assert(nread != 0);
|
||||||
assert(nread == sizeof(event));
|
assert(nread == sizeof(event));
|
||||||
dbgprintf("(Terminal:%d) ", getpid());
|
dbgprintf("(Terminal:%d) ", getpid());
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case GUI_Event::Type::Paint: dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
|
case GUI_Event::Type::Paint: dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
|
||||||
case GUI_Event::Type::MouseDown: dbgprintf("WID=%x MouseDown %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
case GUI_Event::Type::MouseDown: dbgprintf("WID=%x MouseDown %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
case GUI_Event::Type::MouseUp: dbgprintf("WID=%x MouseUp %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
case GUI_Event::Type::MouseUp: dbgprintf("WID=%x MouseUp %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
case GUI_Event::Type::MouseMove: dbgprintf("WID=%x MouseMove %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
case GUI_Event::Type::MouseMove: dbgprintf("WID=%x MouseMove %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
case GUI_Event::Type::KeyDown: dbgprintf("WID=%x KeyDown 0x%b (%c)\n", event.window_id, event.key.character, event.key.character); break;
|
case GUI_Event::Type::KeyDown: dbgprintf("WID=%x KeyDown 0x%b (%c)\n", event.window_id, event.key.character, event.key.character); break;
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == GUI_Event::Type::Paint) {
|
if (event.type == GUI_Event::Type::Paint) {
|
||||||
terminal.paint();
|
terminal.paint();
|
||||||
} else if (event.type == GUI_Event::Type::KeyDown) {
|
} else if (event.type == GUI_Event::Type::KeyDown) {
|
||||||
write(ptm_fd, &event.key.character, 1);
|
write(ptm_fd, &event.key.character, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
#define FD_SETSIZE 64
|
||||||
|
struct fd_set { unsigned char bits[FD_SETSIZE / 8]; };
|
||||||
|
|
||||||
namespace Unix {
|
namespace Unix {
|
||||||
|
|
||||||
#define WNOHANG 1
|
#define WNOHANG 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue