Просмотр исходного кода

Kernel: Report EAGAIN from read() on a non-blocking socket if the buffer is empty

This is not EOF, and never should have been so -- can trip up other code
when porting.

Also updates LibGUI and WindowServer which both relied on the old
behaviour (and didn't work without changes). There may be others, but I
didn't run into them with a quick inspection.
Robin Burchell 6 лет назад
Родитель
Сommit
a8864dc590
3 измененных файлов с 20 добавлено и 11 удалено
  1. 12 2
      Kernel/Net/LocalSocket.cpp
  2. 7 8
      LibGUI/GEventLoop.cpp
  3. 1 1
      Servers/WindowServer/WSEventLoop.cpp

+ 12 - 2
Kernel/Net/LocalSocket.cpp

@@ -153,10 +153,20 @@ bool LocalSocket::can_read(FileDescriptor& descriptor) const
 ssize_t LocalSocket::read(FileDescriptor& descriptor, byte* buffer, ssize_t size)
 ssize_t LocalSocket::read(FileDescriptor& descriptor, byte* buffer, ssize_t size)
 {
 {
     auto role = descriptor.socket_role();
     auto role = descriptor.socket_role();
-    if (role == SocketRole::Accepted)
+    if (role == SocketRole::Accepted) {
+        if (!descriptor.is_blocking()) {
+            if (m_for_server.is_empty())
+                return -EAGAIN;
+        }
         return m_for_server.read(buffer, size);
         return m_for_server.read(buffer, size);
-    if (role == SocketRole::Connected)
+    }
+    if (role == SocketRole::Connected) {
+        if (!descriptor.is_blocking()) {
+            if (m_for_client.is_empty())
+                return -EAGAIN;
+        }
         return m_for_client.read(buffer, size);
         return m_for_client.read(buffer, size);
+    }
     ASSERT_NOT_REACHED();
     ASSERT_NOT_REACHED();
 }
 }
 
 

+ 7 - 8
LibGUI/GEventLoop.cpp

@@ -324,22 +324,22 @@ void GEventLoop::process_unprocessed_bundles()
 
 
 bool GEventLoop::drain_messages_from_server()
 bool GEventLoop::drain_messages_from_server()
 {
 {
-    bool is_first_pass = true;
     for (;;) {
     for (;;) {
         WSAPI_ServerMessage message;
         WSAPI_ServerMessage message;
         ssize_t nread = read(s_windowserver_fd, &message, sizeof(WSAPI_ServerMessage));
         ssize_t nread = read(s_windowserver_fd, &message, sizeof(WSAPI_ServerMessage));
         if (nread < 0) {
         if (nread < 0) {
+            if (errno == EAGAIN) {
+                return true;
+            }
             perror("read");
             perror("read");
             quit(1);
             quit(1);
             return false;
             return false;
         }
         }
         if (nread == 0) {
         if (nread == 0) {
-            if (is_first_pass) {
-                fprintf(stderr, "EOF on WindowServer fd\n");
-                quit(1);
-                return false;
-            }
-            return true;
+            fprintf(stderr, "EOF on WindowServer fd\n");
+            quit(1);
+            exit(-1);
+            return false;
         }
         }
         assert(nread == sizeof(message));
         assert(nread == sizeof(message));
         ByteBuffer extra_data;
         ByteBuffer extra_data;
@@ -355,7 +355,6 @@ bool GEventLoop::drain_messages_from_server()
             ASSERT(extra_nread == message.extra_size);
             ASSERT(extra_nread == message.extra_size);
         }
         }
         m_unprocessed_bundles.append({ move(message), move(extra_data) });
         m_unprocessed_bundles.append({ move(message), move(extra_data) });
-        is_first_pass = false;
     }
     }
 }
 }
 
 

+ 1 - 1
Servers/WindowServer/WSEventLoop.cpp

@@ -301,7 +301,7 @@ void WSEventLoop::drain_client(WSClientConnection& client)
         WSAPI_ClientMessage message;
         WSAPI_ClientMessage message;
         // FIXME: Don't go one message at a time, that's so much context switching, oof.
         // FIXME: Don't go one message at a time, that's so much context switching, oof.
         ssize_t nread = read(client.fd(), &message, sizeof(WSAPI_ClientMessage));
         ssize_t nread = read(client.fd(), &message, sizeof(WSAPI_ClientMessage));
-        if (nread == 0) {
+        if (nread == 0 || (nread == -1 && errno == EAGAIN)) {
             if (!messages_received)
             if (!messages_received)
                 post_event(client, make<WSClientDisconnectedNotification>(client.client_id()));
                 post_event(client, make<WSClientDisconnectedNotification>(client.client_id()));
             break;
             break;