1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 12:25:06 +00:00

Kernel: Consolidate timeout logic

Allow passing in an optional timeout to Thread::block and move
the timeout check out of Thread::Blocker. This way all Blockers
implicitly support timeouts and don't need to implement it
themselves. Do however allow them to override timeouts (e.g.
for sockets).
This commit is contained in:
Tom 2020-08-03 09:43:19 -06:00 committed by Andreas Kling
parent df52061cdb
commit f4a5c9b6c2
15 changed files with 60 additions and 77 deletions

View file

@ -27,6 +27,7 @@
#include <AK/QuickSort.h>
#include <AK/ScopeGuard.h>
#include <AK/TemporaryChange.h>
#include <AK/Time.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/Net/Socket.h>
#include <Kernel/Process.h>
@ -131,26 +132,21 @@ bool Thread::ConnectBlocker::should_unblock(Thread&)
Thread::WriteBlocker::WriteBlocker(const FileDescription& description)
: FileDescriptionBlocker(description)
{
}
timespec* Thread::WriteBlocker::override_timeout(timespec* timeout)
{
auto& description = blocked_description();
if (description.is_socket()) {
auto& socket = *description.socket();
if (socket.has_send_timeout()) {
timeval deadline = Scheduler::time_since_boot();
deadline.tv_sec += socket.send_timeout().tv_sec;
deadline.tv_usec += socket.send_timeout().tv_usec;
deadline.tv_sec += (socket.send_timeout().tv_usec / 1000000) * 1;
deadline.tv_usec %= 1000000;
m_deadline = deadline;
timeval_to_timespec(Scheduler::time_since_boot(), m_deadline);
timespec_add_timeval(m_deadline, socket.send_timeout(), m_deadline);
if (!timeout || m_deadline < *timeout)
return &m_deadline;
}
}
}
bool Thread::WriteBlocker::should_unblock(Thread& thread, time_t now_sec, long now_usec)
{
if (m_deadline.has_value()) {
bool timed_out = now_sec > m_deadline.value().tv_sec || (now_sec == m_deadline.value().tv_sec && now_usec >= m_deadline.value().tv_usec);
return timed_out || blocked_description().can_write();
}
return should_unblock(thread);
return timeout;
}
bool Thread::WriteBlocker::should_unblock(Thread&)
@ -161,26 +157,21 @@ bool Thread::WriteBlocker::should_unblock(Thread&)
Thread::ReadBlocker::ReadBlocker(const FileDescription& description)
: FileDescriptionBlocker(description)
{
}
timespec* Thread::ReadBlocker::override_timeout(timespec* timeout)
{
auto& description = blocked_description();
if (description.is_socket()) {
auto& socket = *description.socket();
if (socket.has_receive_timeout()) {
timeval deadline = Scheduler::time_since_boot();
deadline.tv_sec += socket.receive_timeout().tv_sec;
deadline.tv_usec += socket.receive_timeout().tv_usec;
deadline.tv_sec += (socket.receive_timeout().tv_usec / 1000000) * 1;
deadline.tv_usec %= 1000000;
m_deadline = deadline;
timeval_to_timespec(Scheduler::time_since_boot(), m_deadline);
timespec_add_timeval(m_deadline, socket.receive_timeout(), m_deadline);
if (!timeout || m_deadline < *timeout)
return &m_deadline;
}
}
}
bool Thread::ReadBlocker::should_unblock(Thread& thread, time_t now_sec, long now_usec)
{
if (m_deadline.has_value()) {
bool timed_out = now_sec > m_deadline.value().tv_sec || (now_sec == m_deadline.value().tv_sec && now_usec >= m_deadline.value().tv_usec);
return timed_out || blocked_description().can_read();
}
return should_unblock(thread);
return timeout;
}
bool Thread::ReadBlocker::should_unblock(Thread&)
@ -210,24 +201,13 @@ bool Thread::SleepBlocker::should_unblock(Thread&)
return m_wakeup_time <= g_uptime;
}
Thread::SelectBlocker::SelectBlocker(const timespec& ts, bool select_has_timeout, const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds)
: m_select_timeout(ts)
, m_select_has_timeout(select_has_timeout)
, m_select_read_fds(read_fds)
Thread::SelectBlocker::SelectBlocker(const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds)
: m_select_read_fds(read_fds)
, m_select_write_fds(write_fds)
, m_select_exceptional_fds(except_fds)
{
}
bool Thread::SelectBlocker::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 * 1000 >= m_select_timeout.tv_nsec))
return true;
}
return should_unblock(thread);
}
bool Thread::SelectBlocker::should_unblock(Thread& thread)
{
auto& process = thread.process();
@ -317,10 +297,16 @@ void Thread::consider_unblock(time_t now_sec, long now_usec)
/* don't know, don't care */
return;
case Thread::Blocked:
{
ASSERT(m_blocker != nullptr);
if (m_blocker->should_unblock(*this, now_sec, now_usec))
timespec now;
now.tv_sec = now_sec,
now.tv_nsec = now_usec * 1000ull;
bool timed_out = m_blocker_timeout && now >= *m_blocker_timeout;
if (timed_out || m_blocker->should_unblock(*this))
unblock();
return;
}
case Thread::Skip1SchedulerPass:
set_state(Thread::Skip0SchedulerPasses);
return;