diff options
author | Andreas Kling <kling@serenityos.org> | 2020-01-26 17:54:23 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-01-26 17:54:23 +0100 |
commit | 137a45dff2a6c60dbca34ee6b1e27ff476fe9b40 (patch) | |
tree | 49e38ba4b9d8938a34ef7a38bd0e856077bcd5f8 | |
parent | d1721c761e3dce78ceb27aaaba2ad7836e669306 (diff) | |
download | serenity-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.cpp | 6 | ||||
-rw-r--r-- | Kernel/Net/LocalSocket.cpp | 2 | ||||
-rw-r--r-- | Kernel/Net/Socket.cpp | 18 | ||||
-rw-r--r-- | Kernel/Net/Socket.h | 16 | ||||
-rw-r--r-- | Kernel/Process.cpp | 2 | ||||
-rw-r--r-- | Kernel/Scheduler.cpp | 50 | ||||
-rw-r--r-- | Kernel/Thread.h | 11 |
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 { |