1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 22:47:44 +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:
Andreas Kling 2019-01-15 23:12:20 +01:00
parent 46181cf023
commit 10387beda7
8 changed files with 164 additions and 30 deletions

View file

@ -1909,3 +1909,78 @@ DisplayInfo Process::get_display_info()
info.framebuffer = m_display_framebuffer_region->linearAddress.asPtr();
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;
}

View file

@ -69,6 +69,7 @@ public:
BlockedRead,
BlockedWrite,
BlockedSignal,
BlockedSelect,
};
enum RingLevel {
@ -81,7 +82,7 @@ public:
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; }
@ -156,6 +157,7 @@ public:
void* sys$mmap(const Syscall::SC_mmap_params*);
int sys$munmap(void*, size_t size);
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);
int sys$getcwd(char*, size_t);
int sys$chdir(const char*);
@ -304,6 +306,8 @@ private:
dword m_timesScheduled { 0 };
pid_t m_waitee_pid { -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 };
SignalActionData m_signal_action_data[32];
dword m_pending_signals { 0 };
@ -394,6 +398,7 @@ static inline const char* toString(Process::State state)
case Process::BlockedRead: return "Read";
case Process::BlockedWrite: return "Write";
case Process::BlockedSignal: return "Signal";
case Process::BlockedSelect: return "Select";
case Process::BeingInspected: return "Inspect";
}
ASSERT_NOT_REACHED();

View file

@ -64,6 +64,22 @@ bool Scheduler::pick_next()
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) {
process.set_state(Process::Skip0SchedulerPasses);
return true;

View file

@ -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);
case Syscall::SC_mmap:
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:
return current->sys$munmap((void*)arg1, (size_t)arg2);
case Syscall::SC_gethostname:

View file

@ -71,8 +71,11 @@
__ENUMERATE_SYSCALL(gui_destroy_window) \
__ENUMERATE_SYSCALL(gui_get_window_backing_store) \
__ENUMERATE_SYSCALL(gui_invalidate_window) \
__ENUMERATE_SYSCALL(select) \
struct fd_set;
namespace Syscall {
enum Function {
@ -102,6 +105,14 @@ struct SC_mmap_params {
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();
int sync();