Bladeren bron

LocalSocket: Teach recvfrom() how to block if needed, and simplify it

If we can't already read when we enter recvfrom() on a LocalSocket,
we'll now block the current thread until we can.

Also added a buffer_for(FileDescription&) helper so that the client
and server can share some of the code. :^)
Andreas Kling 5 jaren geleden
bovenliggende
commit
65409e8f04
2 gewijzigde bestanden met toevoegingen van 25 en 22 verwijderingen
  1. 24 22
      Kernel/Net/LocalSocket.cpp
  2. 1 0
      Kernel/Net/LocalSocket.h

+ 24 - 22
Kernel/Net/LocalSocket.cpp

@@ -229,32 +229,34 @@ ssize_t LocalSocket::sendto(FileDescription& description, const void* data, size
     ASSERT_NOT_REACHED();
     ASSERT_NOT_REACHED();
 }
 }
 
 
-ssize_t LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t buffer_size, int, sockaddr*, socklen_t*)
+DoubleBuffer& LocalSocket::buffer_for(FileDescription& description)
 {
 {
     auto role = this->role(description);
     auto role = this->role(description);
-    if (role == Role::Accepted) {
-        if (!description.is_blocking()) {
-            if (m_for_server.is_empty()) {
-                if (!has_attached_peer(description))
-                    return 0;
-                return -EAGAIN;
-            }
-        }
-        ASSERT(!m_for_server.is_empty());
-        return m_for_server.read((u8*)buffer, buffer_size);
-    }
-    if (role == Role::Connected) {
-        if (!description.is_blocking()) {
-            if (m_for_client.is_empty()) {
-                if (!has_attached_peer(description))
-                    return 0;
-                return -EAGAIN;
-            }
+    if (role == Role::Accepted)
+        return m_for_server;
+    if (role == Role::Connected)
+        return m_for_client;
+    ASSERT_NOT_REACHED();
+}
+
+ssize_t LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t buffer_size, int, sockaddr*, socklen_t*)
+{
+    auto& buffer_for_me = buffer_for(description);
+    if (!description.is_blocking()) {
+        if (buffer_for_me.is_empty()) {
+            if (!has_attached_peer(description))
+                return 0;
+            return -EAGAIN;
         }
         }
-        ASSERT(!m_for_client.is_empty());
-        return m_for_client.read((u8*)buffer, buffer_size);
+    } else if (!can_read(description)) {
+        auto result = current->block<Thread::ReceiveBlocker>(description);
+        if (result == Thread::BlockResult::InterruptedBySignal)
+            return -EINTR;
     }
     }
-    ASSERT_NOT_REACHED();
+    if (!has_attached_peer(description) && buffer_for_me.is_empty())
+        return 0;
+    ASSERT(!buffer_for_me.is_empty());
+    return buffer_for_me.read((u8*)buffer, buffer_size);
 }
 }
 
 
 StringView LocalSocket::socket_path() const
 StringView LocalSocket::socket_path() const

+ 1 - 0
Kernel/Net/LocalSocket.h

@@ -36,6 +36,7 @@ private:
     virtual bool is_local() const override { return true; }
     virtual bool is_local() const override { return true; }
     bool has_attached_peer(const FileDescription&) const;
     bool has_attached_peer(const FileDescription&) const;
     static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
     static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
+    DoubleBuffer& buffer_for(FileDescription&);
 
 
     // An open socket file on the filesystem.
     // An open socket file on the filesystem.
     RefPtr<FileDescription> m_file;
     RefPtr<FileDescription> m_file;