summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-01-26 17:54:23 +0100
committerAndreas Kling <kling@serenityos.org>2020-01-26 17:54:23 +0100
commit137a45dff2a6c60dbca34ee6b1e27ff476fe9b40 (patch)
tree49e38ba4b9d8938a34ef7a38bd0e856077bcd5f8
parentd1721c761e3dce78ceb27aaaba2ad7836e669306 (diff)
downloadserenity-137a45dff2a6c60dbca34ee6b1e27ff476fe9b40.zip
Kernel: read()/write() should respect timeouts when used on a sockets
Move timeout management to the ReadBlocker and WriteBlocker classes. Also get rid of the specialized ReceiveBlocker since it no longer does anything that ReadBlocker can't do.
-rw-r--r--Kernel/Net/IPv4Socket.cpp6
-rw-r--r--Kernel/Net/LocalSocket.cpp2
-rw-r--r--Kernel/Net/Socket.cpp18
-rw-r--r--Kernel/Net/Socket.h16
-rw-r--r--Kernel/Process.cpp2
-rw-r--r--Kernel/Scheduler.cpp50
-rw-r--r--Kernel/Thread.h11
7 files changed, 48 insertions, 57 deletions
diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp
index b6f78d7c18..368557bb28 100644
--- a/Kernel/Net/IPv4Socket.cpp
+++ b/Kernel/Net/IPv4Socket.cpp
@@ -264,8 +264,7 @@ ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t
return -EAGAIN;
}
- load_receive_deadline();
- auto res = current->block<Thread::ReceiveBlocker>(description);
+ auto res = current->block<Thread::ReadBlocker>(description);
LOCKER(lock());
if (!m_can_read) {
@@ -312,8 +311,7 @@ ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t
return 0;
}
- load_receive_deadline();
- auto res = current->block<Thread::ReceiveBlocker>(description);
+ auto res = current->block<Thread::ReadBlocker>(description);
LOCKER(lock());
if (!m_can_read) {
diff --git a/Kernel/Net/LocalSocket.cpp b/Kernel/Net/LocalSocket.cpp
index e334f41c8f..09df3ce43f 100644
--- a/Kernel/Net/LocalSocket.cpp
+++ b/Kernel/Net/LocalSocket.cpp
@@ -296,7 +296,7 @@ ssize_t LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t
return -EAGAIN;
}
} else if (!can_read(description)) {
- auto result = current->block<Thread::ReceiveBlocker>(description);
+ auto result = current->block<Thread::ReadBlocker>(description);
if (result != Thread::BlockResult::WokeNormally)
return -EINTR;
}
diff --git a/Kernel/Net/Socket.cpp b/Kernel/Net/Socket.cpp
index 4e8346ce42..a7e755d9d3 100644
--- a/Kernel/Net/Socket.cpp
+++ b/Kernel/Net/Socket.cpp
@@ -147,24 +147,6 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, void* value,
}
}
-void Socket::load_receive_deadline()
-{
- kgettimeofday(m_receive_deadline);
- m_receive_deadline.tv_sec += m_receive_timeout.tv_sec;
- m_receive_deadline.tv_usec += m_receive_timeout.tv_usec;
- m_receive_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
- m_receive_deadline.tv_usec %= 1000000;
-}
-
-void Socket::load_send_deadline()
-{
- kgettimeofday(m_send_deadline);
- m_send_deadline.tv_sec += m_send_timeout.tv_sec;
- m_send_deadline.tv_usec += m_send_timeout.tv_usec;
- m_send_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
- m_send_deadline.tv_usec %= 1000000;
-}
-
ssize_t Socket::read(FileDescription& description, u8* buffer, ssize_t size)
{
return recvfrom(description, buffer, size, 0, nullptr, 0);
diff --git a/Kernel/Net/Socket.h b/Kernel/Net/Socket.h
index 68f076ccef..aa794dadd2 100644
--- a/Kernel/Net/Socket.h
+++ b/Kernel/Net/Socket.h
@@ -112,9 +112,6 @@ public:
uid_t acceptor_uid() const { return m_acceptor.uid; }
gid_t acceptor_gid() const { return m_acceptor.gid; }
- timeval receive_deadline() const { return m_receive_deadline; }
- timeval send_deadline() const { return m_send_deadline; }
-
Lock& lock() { return m_lock; }
// ^File
@@ -122,14 +119,18 @@ public:
virtual ssize_t write(FileDescription&, const u8*, ssize_t) override final;
virtual String absolute_path(const FileDescription&) const override = 0;
+
+ bool has_receive_timeout() const { return m_receive_timeout.tv_sec || m_receive_timeout.tv_usec; }
+ const timeval& receive_timeout() const { return m_receive_timeout; }
+
+ bool has_send_timeout() const { return m_send_timeout.tv_sec || m_send_timeout.tv_usec; }
+ const timeval& send_timeout() const { return m_send_timeout; }
+
protected:
Socket(int domain, int type, int protocol);
KResult queue_connection_from(NonnullRefPtr<Socket>);
- void load_receive_deadline();
- void load_send_deadline();
-
int backlog() const { return m_backlog; }
void set_backlog(int backlog) { m_backlog = backlog; }
@@ -156,9 +157,6 @@ private:
timeval m_receive_timeout { 0, 0 };
timeval m_send_timeout { 0, 0 };
- timeval m_receive_deadline { 0, 0 };
- timeval m_send_deadline { 0, 0 };
-
NonnullRefPtrVector<Socket> m_pending;
};
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index a2d2c39bb5..0bcc5bc5fa 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -1658,6 +1658,8 @@ ssize_t Process::sys$read(int fd, u8* buffer, ssize_t size)
if (!description->can_read()) {
if (current->block<Thread::ReadBlocker>(*description) != Thread::BlockResult::WokeNormally)
return -EINTR;
+ if (!description->can_read())
+ return -EAGAIN;
}
}
return description->read(buffer, size);
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp
index c42126e990..d5a6ff9314 100644
--- a/Kernel/Scheduler.cpp
+++ b/Kernel/Scheduler.cpp
@@ -118,21 +118,6 @@ bool Thread::AcceptBlocker::should_unblock(Thread&, time_t, long)
return socket.can_accept();
}
-Thread::ReceiveBlocker::ReceiveBlocker(const FileDescription& description)
- : FileDescriptionBlocker(description)
-{
-}
-
-bool Thread::ReceiveBlocker::should_unblock(Thread&, time_t now_sec, long now_usec)
-{
- auto& socket = *blocked_description().socket();
- // FIXME: Block until the amount of data wanted is available.
- bool timed_out = now_sec > socket.receive_deadline().tv_sec || (now_sec == socket.receive_deadline().tv_sec && now_usec >= socket.receive_deadline().tv_usec);
- if (timed_out || blocked_description().can_read())
- return true;
- return false;
-}
-
Thread::ConnectBlocker::ConnectBlocker(const FileDescription& description)
: FileDescriptionBlocker(description)
{
@@ -147,21 +132,50 @@ bool Thread::ConnectBlocker::should_unblock(Thread&, time_t, long)
Thread::WriteBlocker::WriteBlocker(const FileDescription& description)
: FileDescriptionBlocker(description)
{
+ if (description.is_socket()) {
+ auto& socket = *description.socket();
+ if (socket.has_send_timeout()) {
+ timeval deadline = kgettimeofday();
+ 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;
+ }
+ }
}
-bool Thread::WriteBlocker::should_unblock(Thread&, time_t, long)
+bool Thread::WriteBlocker::should_unblock(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 blocked_description().can_write();
}
Thread::ReadBlocker::ReadBlocker(const FileDescription& description)
: FileDescriptionBlocker(description)
{
+ if (description.is_socket()) {
+ auto& socket = *description.socket();
+ if (socket.has_receive_timeout()) {
+ timeval deadline = kgettimeofday();
+ 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;
+ }
+ }
}
-bool Thread::ReadBlocker::should_unblock(Thread&, time_t, long)
+bool Thread::ReadBlocker::should_unblock(Thread&, time_t now_sec, long now_usec)
{
- // FIXME: Block until the amount of data wanted is available.
+ 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 blocked_description().can_read();
}
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index c73c7a5931..76c6f994bd 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -167,13 +167,6 @@ public:
virtual const char* state_string() const override { return "Accepting"; }
};
- class ReceiveBlocker final : public FileDescriptionBlocker {
- public:
- explicit ReceiveBlocker(const FileDescription&);
- virtual bool should_unblock(Thread&, time_t, long) override;
- virtual const char* state_string() const override { return "Receiving"; }
- };
-
class ConnectBlocker final : public FileDescriptionBlocker {
public:
explicit ConnectBlocker(const FileDescription&);
@@ -186,6 +179,8 @@ public:
explicit WriteBlocker(const FileDescription&);
virtual bool should_unblock(Thread&, time_t, long) override;
virtual const char* state_string() const override { return "Writing"; }
+ private:
+ Optional<timeval> m_deadline;
};
class ReadBlocker final : public FileDescriptionBlocker {
@@ -193,6 +188,8 @@ public:
explicit ReadBlocker(const FileDescription&);
virtual bool should_unblock(Thread&, time_t, long) override;
virtual const char* state_string() const override { return "Reading"; }
+ private:
+ Optional<timeval> m_deadline;
};
class ConditionBlocker final : public Blocker {