Procházet zdrojové kódy

[LibOS] Handle corner-cases during {send,receive}_ipc_message

This commit adds additional logic around DkStreamWrite() and
DkStreamRead() in send_ipc_message() and receive_ipc_message()
respectively: interrupts and partial reads/writes are handled correctly.
Dmitrii Kuvaiskii před 4 roky
rodič
revize
9dea9384ee

+ 18 - 9
LibOS/shim/src/ipc/shim_ipc.c

@@ -257,15 +257,24 @@ int send_ipc_message(struct shim_ipc_msg* msg, struct shim_ipc_port* port) {
     msg->src = cur_process.vmid;
     debug("Sending ipc message to port %p (handle %p)\n", port, port->pal_handle);
 
-    /* TODO: Handle benign EINTR case? */
-    /* TODO: Add while-loop to send all msg */
-    int ret = DkStreamWrite(port->pal_handle, 0, msg->size, msg, NULL);
-
-    if (ret == 0 && PAL_NATIVE_ERRNO) {
-        debug("Port %p (handle %p) was removed during sending\n", port, port->pal_handle);
-        del_ipc_port_fini(port, -ECHILD);
-        return -PAL_ERRNO;
-    }
+    size_t total_bytes = msg->size;
+    size_t bytes = 0;
+
+    do {
+        size_t ret = DkStreamWrite(port->pal_handle, 0, total_bytes - bytes,
+                                   (void *)msg + bytes, NULL);
+
+        if (!ret) {
+            if (PAL_ERRNO == EINTR || PAL_ERRNO == EAGAIN || PAL_ERRNO == EWOULDBLOCK)
+                continue;
+
+            debug("Port %p (handle %p) was removed during sending\n", port, port->pal_handle);
+            del_ipc_port_fini(port, -ECHILD);
+            return -PAL_ERRNO;
+        }
+
+        bytes += ret;
+    } while (bytes < total_bytes);
 
     return 0;
 }

+ 5 - 4
LibOS/shim/src/ipc/shim_ipc_helper.c

@@ -495,12 +495,13 @@ static int receive_ipc_message(struct shim_ipc_port* port) {
                 msg = tmp_buf;
             }
 
-            /* TODO: Add while-loop to receive all msg */
             int read = DkStreamRead(port->pal_handle, /*offset*/ 0, expected_size - bytes + readahead,
                                      (void *) msg + bytes, NULL, 0);
 
-            if (read == 0) {
-                /* TODO: Handle benign EINTR case? */
+            if (!read) {
+                if (PAL_ERRNO == EINTR || PAL_ERRNO == EAGAIN || PAL_ERRNO == EWOULDBLOCK)
+                    continue;
+
                 debug("Port %p (handle %p) closed while receiving IPC message\n", port, port->pal_handle);
                 del_ipc_port_fini(port, -ECHILD);
                 ret = -PAL_ERRNO;
@@ -639,7 +640,7 @@ noreturn static void shim_ipc_helper(void* dummy) {
                 if (DkStreamAttributesQueryByHandle(polled_port->pal_handle, &attr)) {
                     /* can read on this port, so receive messages */
                     if (attr.readable) {
-                        /* TODO: IPC helper thread does not handle failures currently */
+                        /* NOTE: IPC helper thread does not handle failures currently */
                         receive_ipc_message(polled_port);
                     }