mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 13:57:35 +00:00
Kernel: Port select to ThreadBlocker
This commit is contained in:
parent
32fcfb79e9
commit
4f9ae9b970
4 changed files with 86 additions and 68 deletions
|
@ -1792,13 +1792,17 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
if (params->nfds < 0)
|
if (params->nfds < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
timeval timeout;
|
||||||
|
bool select_has_timeout = false;
|
||||||
if (params->timeout && (params->timeout->tv_sec || params->timeout->tv_usec)) {
|
if (params->timeout && (params->timeout->tv_sec || params->timeout->tv_usec)) {
|
||||||
timeval_add(kgettimeofday(), *params->timeout, current->m_select_timeout);
|
timeval_add(kgettimeofday(), *params->timeout, timeout);
|
||||||
current->m_select_has_timeout = true;
|
select_has_timeout = true;
|
||||||
} else {
|
|
||||||
current->m_select_has_timeout = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<int> rfds;
|
||||||
|
Vector<int> wfds;
|
||||||
|
Vector<int> efds;
|
||||||
|
|
||||||
auto transfer_fds = [&](auto* fds, auto& vector) -> int {
|
auto transfer_fds = [&](auto* fds, auto& vector) -> int {
|
||||||
vector.clear_with_capacity();
|
vector.clear_with_capacity();
|
||||||
if (!fds)
|
if (!fds)
|
||||||
|
@ -1812,19 +1816,19 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
if (int error = transfer_fds(params->writefds, current->m_select_write_fds))
|
if (int error = transfer_fds(params->writefds, wfds))
|
||||||
return error;
|
return error;
|
||||||
if (int error = transfer_fds(params->readfds, current->m_select_read_fds))
|
if (int error = transfer_fds(params->readfds, rfds))
|
||||||
return error;
|
return error;
|
||||||
if (int error = transfer_fds(params->exceptfds, current->m_select_exceptional_fds))
|
if (int error = transfer_fds(params->exceptfds, efds))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
||||||
dbgprintf("%s<%u> selecting on (read:%u, write:%u), timeout=%p\n", name().characters(), pid(), current->m_select_read_fds.size(), current->m_select_write_fds.size(), params->timeout);
|
dbgprintf("%s<%u> selecting on (read:%u, write:%u), timeout=%p\n", name().characters(), pid(), rfds.size(), wfds.size(), params->timeout);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!params->timeout || current->m_select_has_timeout)
|
if (!params->timeout || select_has_timeout)
|
||||||
current->block(Thread::State::BlockedSelect);
|
current->block(*new Thread::ThreadBlockerSelect(timeout, select_has_timeout, rfds, wfds, efds));
|
||||||
|
|
||||||
int marked_fd_count = 0;
|
int marked_fd_count = 0;
|
||||||
auto mark_fds = [&](auto* fds, auto& vector, auto should_mark) {
|
auto mark_fds = [&](auto* fds, auto& vector, auto should_mark) {
|
||||||
|
@ -1838,8 +1842,8 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mark_fds(params->readfds, current->m_select_read_fds, [](auto& description) { return description.can_read(); });
|
mark_fds(params->readfds, rfds, [](auto& description) { return description.can_read(); });
|
||||||
mark_fds(params->writefds, current->m_select_write_fds, [](auto& description) { return description.can_write(); });
|
mark_fds(params->writefds, wfds, [](auto& description) { return description.can_write(); });
|
||||||
// FIXME: We should also mark params->exceptfds as appropriate.
|
// FIXME: We should also mark params->exceptfds as appropriate.
|
||||||
return marked_fd_count;
|
return marked_fd_count;
|
||||||
}
|
}
|
||||||
|
@ -1849,15 +1853,18 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout)
|
||||||
if (!validate_read_typed(fds))
|
if (!validate_read_typed(fds))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
current->m_select_write_fds.clear_with_capacity();
|
Vector<int> rfds;
|
||||||
current->m_select_read_fds.clear_with_capacity();
|
Vector<int> wfds;
|
||||||
|
|
||||||
for (int i = 0; i < nfds; ++i) {
|
for (int i = 0; i < nfds; ++i) {
|
||||||
if (fds[i].events & POLLIN)
|
if (fds[i].events & POLLIN)
|
||||||
current->m_select_read_fds.append(fds[i].fd);
|
rfds.append(fds[i].fd);
|
||||||
if (fds[i].events & POLLOUT)
|
if (fds[i].events & POLLOUT)
|
||||||
current->m_select_write_fds.append(fds[i].fd);
|
wfds.append(fds[i].fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeval actual_timeout;
|
||||||
|
bool has_timeout = false;
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
// poll is in ms, we want s/us.
|
// poll is in ms, we want s/us.
|
||||||
struct timeval tvtimeout;
|
struct timeval tvtimeout;
|
||||||
|
@ -1867,19 +1874,16 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout)
|
||||||
timeout -= 1000;
|
timeout -= 1000;
|
||||||
}
|
}
|
||||||
tvtimeout.tv_usec = timeout * 1000;
|
tvtimeout.tv_usec = timeout * 1000;
|
||||||
timeval_add(kgettimeofday(), tvtimeout, current->m_select_timeout);
|
timeval_add(kgettimeofday(), tvtimeout, actual_timeout);
|
||||||
current->m_select_has_timeout = true;
|
has_timeout = true;
|
||||||
} else {
|
|
||||||
current->m_select_has_timeout = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
||||||
dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), current->m_select_read_fds.size(), current->m_select_write_fds.size(), timeout);
|
dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), rfds.size(), wfds.size(), timeout);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (current->m_select_has_timeout || timeout < 0) {
|
if (has_timeout|| timeout < 0)
|
||||||
current->block(Thread::State::BlockedSelect);
|
current->block(*new Thread::ThreadBlockerSelect(actual_timeout, has_timeout, rfds, wfds, Vector<int>()));
|
||||||
}
|
|
||||||
|
|
||||||
int fds_with_revents = 0;
|
int fds_with_revents = 0;
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ Thread::ThreadBlockerAccept::ThreadBlockerAccept(const RefPtr<FileDescription>&
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerAccept::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerAccept::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
auto& description = *blocked_description();
|
auto& description = *blocked_description();
|
||||||
auto& socket = *description.socket();
|
auto& socket = *description.socket();
|
||||||
|
@ -78,7 +78,7 @@ Thread::ThreadBlockerReceive::ThreadBlockerReceive(const RefPtr<FileDescription>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerReceive::should_unblock(time_t now_sec, long now_usec)
|
bool Thread::ThreadBlockerReceive::should_unblock(Thread&, time_t now_sec, long now_usec)
|
||||||
{
|
{
|
||||||
auto& description = *blocked_description();
|
auto& description = *blocked_description();
|
||||||
auto& socket = *description.socket();
|
auto& socket = *description.socket();
|
||||||
|
@ -94,7 +94,7 @@ Thread::ThreadBlockerConnect::ThreadBlockerConnect(const RefPtr<FileDescription>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerConnect::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerConnect::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
auto& description = *blocked_description();
|
auto& description = *blocked_description();
|
||||||
auto& socket = *description.socket();
|
auto& socket = *description.socket();
|
||||||
|
@ -106,7 +106,7 @@ Thread::ThreadBlockerWrite::ThreadBlockerWrite(const RefPtr<FileDescription>& de
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerWrite::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerWrite::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
return blocked_description()->can_write();
|
return blocked_description()->can_write();
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ Thread::ThreadBlockerRead::ThreadBlockerRead(const RefPtr<FileDescription>& desc
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerRead::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerRead::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
// FIXME: Block until the amount of data wanted is available.
|
// FIXME: Block until the amount of data wanted is available.
|
||||||
return blocked_description()->can_read();
|
return blocked_description()->can_read();
|
||||||
|
@ -128,7 +128,7 @@ Thread::ThreadBlockerCondition::ThreadBlockerCondition(Function<bool()> &conditi
|
||||||
ASSERT(m_block_until_condition);
|
ASSERT(m_block_until_condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerCondition::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerCondition::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
return m_block_until_condition();
|
return m_block_until_condition();
|
||||||
}
|
}
|
||||||
|
@ -138,11 +138,40 @@ Thread::ThreadBlockerSleep::ThreadBlockerSleep(u64 wakeup_time)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::ThreadBlockerSleep::should_unblock(time_t, long)
|
bool Thread::ThreadBlockerSleep::should_unblock(Thread&, time_t, long)
|
||||||
{
|
{
|
||||||
return m_wakeup_time <= g_uptime;
|
return m_wakeup_time <= g_uptime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Thread::ThreadBlockerSelect::ThreadBlockerSelect(const timeval& tv, bool select_has_timeout, const Vector<int>& read_fds, const Vector<int>& write_fds, const Vector<int>& except_fds)
|
||||||
|
: m_select_timeout(tv)
|
||||||
|
, m_select_has_timeout(select_has_timeout)
|
||||||
|
, m_select_read_fds(read_fds)
|
||||||
|
, m_select_write_fds(write_fds)
|
||||||
|
, m_select_exceptional_fds(except_fds)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::ThreadBlockerSelect::should_unblock(Thread& thread, time_t now_sec, long now_usec)
|
||||||
|
{
|
||||||
|
if (m_select_has_timeout) {
|
||||||
|
if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec >= m_select_timeout.tv_usec))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& process = thread.process();
|
||||||
|
for (int fd : m_select_read_fds) {
|
||||||
|
if (process.m_fds[fd].description->can_read())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int fd : m_select_write_fds) {
|
||||||
|
if (process.m_fds[fd].description->can_write())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Called by the scheduler on threads that are blocked for some reason.
|
// Called by the scheduler on threads that are blocked for some reason.
|
||||||
// Make a decision as to whether to unblock them or not.
|
// Make a decision as to whether to unblock them or not.
|
||||||
void Thread::consider_unblock(time_t now_sec, long now_usec)
|
void Thread::consider_unblock(time_t now_sec, long now_usec)
|
||||||
|
@ -181,29 +210,9 @@ void Thread::consider_unblock(time_t now_sec, long now_usec)
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
case Thread::BlockedSelect:
|
|
||||||
if (m_select_has_timeout) {
|
|
||||||
if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec >= m_select_timeout.tv_usec)) {
|
|
||||||
unblock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int fd : m_select_read_fds) {
|
|
||||||
if (process.m_fds[fd].description->can_read()) {
|
|
||||||
unblock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int fd : m_select_write_fds) {
|
|
||||||
if (process.m_fds[fd].description->can_write()) {
|
|
||||||
unblock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case Thread::BlockedCondition:
|
case Thread::BlockedCondition:
|
||||||
ASSERT(m_blocker);
|
ASSERT(m_blocker);
|
||||||
if (m_blocker->should_unblock(now_sec, now_usec)) {
|
if (m_blocker->should_unblock(*this, now_sec, now_usec)) {
|
||||||
unblock();
|
unblock();
|
||||||
m_blocker = nullptr;
|
m_blocker = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,6 @@ const char* to_string(Thread::State state)
|
||||||
return "Wait";
|
return "Wait";
|
||||||
case Thread::BlockedSignal:
|
case Thread::BlockedSignal:
|
||||||
return "Signal";
|
return "Signal";
|
||||||
case Thread::BlockedSelect:
|
|
||||||
return "Select";
|
|
||||||
case Thread::BlockedLurking:
|
case Thread::BlockedLurking:
|
||||||
return "Lurking";
|
return "Lurking";
|
||||||
case Thread::BlockedCondition:
|
case Thread::BlockedCondition:
|
||||||
|
|
|
@ -67,7 +67,6 @@ public:
|
||||||
BlockedLurking,
|
BlockedLurking,
|
||||||
BlockedWait,
|
BlockedWait,
|
||||||
BlockedSignal,
|
BlockedSignal,
|
||||||
BlockedSelect,
|
|
||||||
BlockedCondition,
|
BlockedCondition,
|
||||||
__End_Blocked_States__
|
__End_Blocked_States__
|
||||||
};
|
};
|
||||||
|
@ -75,7 +74,7 @@ public:
|
||||||
class ThreadBlocker {
|
class ThreadBlocker {
|
||||||
public:
|
public:
|
||||||
virtual ~ThreadBlocker() {}
|
virtual ~ThreadBlocker() {}
|
||||||
virtual bool should_unblock(time_t now_s, long us) = 0;
|
virtual bool should_unblock(Thread&, time_t now_s, long us) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerFileDescription : public ThreadBlocker {
|
class ThreadBlockerFileDescription : public ThreadBlocker {
|
||||||
|
@ -90,37 +89,37 @@ public:
|
||||||
class ThreadBlockerAccept : public ThreadBlockerFileDescription {
|
class ThreadBlockerAccept : public ThreadBlockerFileDescription {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerAccept(const RefPtr<FileDescription>& description);
|
ThreadBlockerAccept(const RefPtr<FileDescription>& description);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerReceive : public ThreadBlockerFileDescription {
|
class ThreadBlockerReceive : public ThreadBlockerFileDescription {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerReceive(const RefPtr<FileDescription>& description);
|
ThreadBlockerReceive(const RefPtr<FileDescription>& description);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerConnect : public ThreadBlockerFileDescription {
|
class ThreadBlockerConnect : public ThreadBlockerFileDescription {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerConnect(const RefPtr<FileDescription>& description);
|
ThreadBlockerConnect(const RefPtr<FileDescription>& description);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerWrite : public ThreadBlockerFileDescription {
|
class ThreadBlockerWrite : public ThreadBlockerFileDescription {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerWrite(const RefPtr<FileDescription>& description);
|
ThreadBlockerWrite(const RefPtr<FileDescription>& description);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerRead : public ThreadBlockerFileDescription {
|
class ThreadBlockerRead : public ThreadBlockerFileDescription {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerRead(const RefPtr<FileDescription>& description);
|
ThreadBlockerRead(const RefPtr<FileDescription>& description);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadBlockerCondition : public ThreadBlocker {
|
class ThreadBlockerCondition : public ThreadBlocker {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerCondition(Function<bool()> &condition);
|
ThreadBlockerCondition(Function<bool()> &condition);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Function<bool()> m_block_until_condition;
|
Function<bool()> m_block_until_condition;
|
||||||
|
@ -129,12 +128,25 @@ public:
|
||||||
class ThreadBlockerSleep : public ThreadBlocker {
|
class ThreadBlockerSleep : public ThreadBlocker {
|
||||||
public:
|
public:
|
||||||
ThreadBlockerSleep(u64 wakeup_time);
|
ThreadBlockerSleep(u64 wakeup_time);
|
||||||
virtual bool should_unblock(time_t, long) override;
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u64 m_wakeup_time { 0 };
|
u64 m_wakeup_time { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ThreadBlockerSelect : public ThreadBlocker {
|
||||||
|
public:
|
||||||
|
ThreadBlockerSelect(const timeval& tv, bool select_has_timeout, const Vector<int>& read_fds, const Vector<int>& write_fds, const Vector<int>& except_fds);
|
||||||
|
virtual bool should_unblock(Thread&, time_t, long) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
timeval m_select_timeout;
|
||||||
|
bool m_select_has_timeout { false };
|
||||||
|
const Vector<int>& m_select_read_fds;
|
||||||
|
const Vector<int>& m_select_write_fds;
|
||||||
|
const Vector<int>& m_select_exceptional_fds;
|
||||||
|
};
|
||||||
|
|
||||||
void did_schedule() { ++m_times_scheduled; }
|
void did_schedule() { ++m_times_scheduled; }
|
||||||
u32 times_scheduled() const { return m_times_scheduled; }
|
u32 times_scheduled() const { return m_times_scheduled; }
|
||||||
|
|
||||||
|
@ -240,17 +252,12 @@ private:
|
||||||
RefPtr<Region> m_kernel_stack_for_signal_handler_region;
|
RefPtr<Region> m_kernel_stack_for_signal_handler_region;
|
||||||
pid_t m_waitee_pid { -1 };
|
pid_t m_waitee_pid { -1 };
|
||||||
int m_wait_options { 0 };
|
int m_wait_options { 0 };
|
||||||
timeval m_select_timeout;
|
|
||||||
SignalActionData m_signal_action_data[32];
|
SignalActionData m_signal_action_data[32];
|
||||||
Region* m_signal_stack_user_region { nullptr };
|
Region* m_signal_stack_user_region { nullptr };
|
||||||
OwnPtr<ThreadBlocker> m_blocker;
|
OwnPtr<ThreadBlocker> m_blocker;
|
||||||
Vector<int> m_select_read_fds;
|
|
||||||
Vector<int> m_select_write_fds;
|
|
||||||
Vector<int> m_select_exceptional_fds;
|
|
||||||
FPUState* m_fpu_state { nullptr };
|
FPUState* m_fpu_state { nullptr };
|
||||||
InlineLinkedList<Thread>* m_thread_list { nullptr };
|
InlineLinkedList<Thread>* m_thread_list { nullptr };
|
||||||
State m_state { Invalid };
|
State m_state { Invalid };
|
||||||
bool m_select_has_timeout { false };
|
|
||||||
bool m_has_used_fpu { false };
|
bool m_has_used_fpu { false };
|
||||||
bool m_was_interrupted_while_blocked { false };
|
bool m_was_interrupted_while_blocked { false };
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue