Bug 1142693 - Recognize EMSGSIZE as non-fatal on OS X for IPC sendmsg(). r=bent, a=lizzard
authorJed Davis <jld@mozilla.com>
Fri, 10 Apr 2015 22:47:05 -0700
changeset 265644 351de38bffe0a5267473d1304c3b41a90a35da6c
parent 265643 0100f5c33e386a6a0843f8b7c62629e03aff3f80
child 265645 aa1de6662e67a125db8f64a53cadd1200206471b
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, lizzard
bugs1142693
milestone39.0a2
Bug 1142693 - Recognize EMSGSIZE as non-fatal on OS X for IPC sendmsg(). r=bent, a=lizzard Loosely based on Chromium git commit 86c3d9ef4fdf, but redone to insert a sched_yield(), because treating EMSGSIZE as if it were EAGAIN/EWOULDBLOCK is (as the Chromium developers note) likely to act as a busy-wait for the receiver to make progress.
ipc/chromium/src/chrome/common/ipc_channel_posix.cc
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -1,16 +1,19 @@
 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/common/ipc_channel_posix.h"
 
 #include <errno.h>
 #include <fcntl.h>
+#if defined(OS_MACOSX)
+#include <sched.h>
+#endif
 #include <stddef.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 #include <sys/uio.h>
 
@@ -719,19 +722,49 @@ bool Channel::ChannelImpl::ProcessOutgoi
     ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
 #if !defined(OS_MACOSX)
     // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
     // message.
     if (bytes_written > 0)
       msg->file_descriptor_set()->CommitAll();
 #endif
 
-    if (bytes_written < 0 && errno != EAGAIN) {
-      CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
-      return false;
+    if (bytes_written < 0) {
+      switch (errno) {
+      case EAGAIN:
+        // Not an error; the sendmsg would have blocked, so return to the
+        // event loop and try again later.
+        break;
+#if defined(OS_MACOSX)
+        // (Note: this comment is copied from https://crrev.com/86c3d9ef4fdf6;
+        // see also bug 1142693 comment #73.)
+        //
+        // On OS X if sendmsg() is trying to send fds between processes and
+        // there isn't enough room in the output buffer to send the fd
+        // structure over atomically then EMSGSIZE is returned.
+        //
+        // EMSGSIZE presents a problem since the system APIs can only call us
+        // when there's room in the socket buffer and not when there is
+        // "enough" room.
+        //
+        // The current behavior is to return to the event loop when EMSGSIZE
+        // is received and hopefull service another FD.  This is however still
+        // technically a busy wait since the event loop will call us right
+        // back until the receiver has read enough data to allow passing the
+        // FD over atomically.
+      case EMSGSIZE:
+        // Because this is likely to result in a busy-wait, we'll try to make
+        // it easier for the receiver to make progress.
+        sched_yield();
+        break;
+#endif
+      default:
+        CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
+        return false;
+      }
     }
 
     if (static_cast<size_t>(bytes_written) != amt_to_write) {
       if (bytes_written > 0) {
         // If write() fails with EAGAIN then bytes_written will be -1.
         message_send_bytes_written_ += bytes_written;
       }