Handle EWOULDBLOCK as EAGAIN. And add a comment explaining why
[oota-llvm.git] / lib / Support / raw_ostream.cpp
index 7a02db1aeb3905b68303a49f7e05a609d440eda7..ad47cb6cf5e917f697d78d8850f388ebd3479780 100644 (file)
@@ -21,6 +21,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/ADT/STLExtras.h"
 #include <cctype>
+#include <cerrno>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -420,8 +421,31 @@ raw_fd_ostream::~raw_fd_ostream() {
 void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
   assert(FD >= 0 && "File already closed.");
   pos += Size;
-  if (::write(FD, Ptr, Size) != (ssize_t) Size)
-    error_detected();
+  ssize_t ret;
+
+  do {
+    ret = ::write(FD, Ptr, Size);
+
+    if (ret < 0) {
+      // If it's a recoverable error, swallow it and retry the write.
+      // EAGAIN and EWOULDBLOCK are not unambiguously recoverable, but
+      // some programs, such as bjam, assume that their child processes
+      // will treat them as if they are. If you don't want this code to
+      // spin, don't use O_NONBLOCK file descriptors with raw_ostream.
+      if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+        continue;
+
+      // Otherwise it's a non-recoverable error. Note it and quit.
+      error_detected();
+      break;
+    }
+
+    // The write may have written some or all of the data. Update the
+    // size and buffer pointer to reflect the remainder that needs
+    // to be written. If there are no bytes left, we're done.
+    Ptr += ret;
+    Size -= ret;
+  } while (Size > 0);
 }
 
 void raw_fd_ostream::close() {
@@ -442,7 +466,8 @@ uint64_t raw_fd_ostream::seek(uint64_t off) {
 }
 
 size_t raw_fd_ostream::preferred_buffer_size() const {
-#if !defined(_MSC_VER) && !defined(__MINGW32__) // Windows has no st_blksize.
+#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_MINIX)
+  // Windows and Minix have no st_blksize.
   assert(FD >= 0 && "File not yet open!");
   struct stat statbuf;
   if (fstat(FD, &statbuf) != 0)