[llvm] r305892 - [Support] Add RetryAfterSignal helper function

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 21 03:55:35 PDT 2017


Author: labath
Date: Wed Jun 21 05:55:34 2017
New Revision: 305892

URL: http://llvm.org/viewvc/llvm-project?rev=305892&view=rev
Log:
[Support] Add RetryAfterSignal helper function

Summary:
This function retries an operation if it was interrupted by a signal
(failed with EINTR). It's inspired by the TEMP_FAILURE_RETRY macro in
glibc, but I've turned that into a template function. I've also added a
fail-value argument, to enable the function to be used with e.g.
fopen(3), which is documented to fail for any reason that open(2) can
fail (which includes EINTR).

The main user of this function will be lldb, but there were also a
couple of uses within llvm that I could simplify using this function.

Reviewers: zturner, silvas, joerg

Subscribers: mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D33895

Added:
    llvm/trunk/unittests/Support/ErrnoTest.cpp
Modified:
    llvm/trunk/include/llvm/Support/Errno.h
    llvm/trunk/lib/Support/MemoryBuffer.cpp
    llvm/trunk/lib/Support/Unix/Path.inc
    llvm/trunk/lib/Support/Unix/Process.inc
    llvm/trunk/unittests/Support/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Support/Errno.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Errno.h?rev=305892&r1=305891&r2=305892&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Errno.h (original)
+++ llvm/trunk/include/llvm/Support/Errno.h Wed Jun 21 05:55:34 2017
@@ -15,6 +15,7 @@
 #define LLVM_SUPPORT_ERRNO_H
 
 #include <string>
+#include <type_traits>
 
 namespace llvm {
 namespace sys {
@@ -28,6 +29,18 @@ std::string StrError();
 /// Like the no-argument version above, but uses \p errnum instead of errno.
 std::string StrError(int errnum);
 
+template <typename Fun, typename... Args,
+          typename ResultT =
+              typename std::result_of<Fun const &(const Args &...)>::type>
+inline ResultT RetryAfterSignal(ResultT Fail, const Fun &F,
+                                const Args &... As) {
+  ResultT Res;
+  do
+    Res = F(As...);
+  while (Res == Fail && errno == EINTR);
+  return Res;
+}
+
 }  // namespace sys
 }  // namespace llvm
 

Modified: llvm/trunk/lib/Support/MemoryBuffer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/MemoryBuffer.cpp?rev=305892&r1=305891&r2=305892&view=diff
==============================================================================
--- llvm/trunk/lib/Support/MemoryBuffer.cpp (original)
+++ llvm/trunk/lib/Support/MemoryBuffer.cpp Wed Jun 21 05:55:34 2017
@@ -240,11 +240,9 @@ getMemoryBufferForStream(int FD, const T
   // Read into Buffer until we hit EOF.
   do {
     Buffer.reserve(Buffer.size() + ChunkSize);
-    ReadBytes = read(FD, Buffer.end(), ChunkSize);
-    if (ReadBytes == -1) {
-      if (errno == EINTR) continue;
+    ReadBytes = sys::RetryAfterSignal(-1, read, FD, Buffer.end(), ChunkSize);
+    if (ReadBytes == -1)
       return std::error_code(errno, std::generic_category());
-    }
     Buffer.set_size(Buffer.size() + ReadBytes);
   } while (ReadBytes != 0);
 
@@ -391,13 +389,12 @@ getOpenFileImpl(int FD, const Twine &Fil
 
   while (BytesLeft) {
 #ifdef HAVE_PREAD
-    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
+    ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft,
+                                            MapSize - BytesLeft + Offset);
 #else
-    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
+    ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft);
 #endif
     if (NumRead == -1) {
-      if (errno == EINTR)
-        continue;
       // Error while reading.
       return std::error_code(errno, std::generic_category());
     }

Modified: llvm/trunk/lib/Support/Unix/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Path.inc?rev=305892&r1=305891&r2=305892&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/Path.inc (original)
+++ llvm/trunk/lib/Support/Unix/Path.inc Wed Jun 21 05:55:34 2017
@@ -737,10 +737,8 @@ std::error_code openFileForRead(const Tw
 #ifdef O_CLOEXEC
   OpenFlags |= O_CLOEXEC;
 #endif
-  while ((ResultFD = open(P.begin(), OpenFlags)) < 0) {
-    if (errno != EINTR)
-      return std::error_code(errno, std::generic_category());
-  }
+  if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0)
+    return std::error_code(errno, std::generic_category());
 #ifndef O_CLOEXEC
   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
   (void)r;
@@ -800,10 +798,8 @@ std::error_code openFileForWrite(const T
 
   SmallString<128> Storage;
   StringRef P = Name.toNullTerminatedStringRef(Storage);
-  while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
-    if (errno != EINTR)
-      return std::error_code(errno, std::generic_category());
-  }
+  if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0)
+    return std::error_code(errno, std::generic_category());
 #ifndef O_CLOEXEC
   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
   (void)r;

Modified: llvm/trunk/lib/Support/Unix/Process.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Process.inc?rev=305892&r1=305891&r2=305892&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/Process.inc (original)
+++ llvm/trunk/lib/Support/Unix/Process.inc Wed Jun 21 05:55:34 2017
@@ -207,13 +207,10 @@ std::error_code Process::FixupStandardFi
   for (int StandardFD : StandardFDs) {
     struct stat st;
     errno = 0;
-    while (fstat(StandardFD, &st) < 0) {
+    if (RetryAfterSignal(-1, fstat, StandardFD, &st) < 0) {
       assert(errno && "expected errno to be set if fstat failed!");
       // fstat should return EBADF if the file descriptor is closed.
-      if (errno == EBADF)
-        break;
-      // retry fstat if we got EINTR, otherwise bubble up the failure.
-      if (errno != EINTR)
+      if (errno != EBADF)
         return std::error_code(errno, std::generic_category());
     }
     // if fstat succeeds, move on to the next FD.
@@ -222,11 +219,8 @@ std::error_code Process::FixupStandardFi
     assert(errno == EBADF && "expected errno to have EBADF at this point!");
 
     if (NullFD < 0) {
-      while ((NullFD = open("/dev/null", O_RDWR)) < 0) {
-        if (errno == EINTR)
-          continue;
+      if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 0)
         return std::error_code(errno, std::generic_category());
-      }
     }
 
     if (NullFD == StandardFD)

Modified: llvm/trunk/unittests/Support/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CMakeLists.txt?rev=305892&r1=305891&r2=305892&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/CMakeLists.txt (original)
+++ llvm/trunk/unittests/Support/CMakeLists.txt Wed Jun 21 05:55:34 2017
@@ -21,6 +21,7 @@ add_llvm_unittest(SupportTests
   DebugTest.cpp
   EndianStreamTest.cpp
   EndianTest.cpp
+  ErrnoTest.cpp
   ErrorOrTest.cpp
   ErrorTest.cpp
   FileOutputBufferTest.cpp

Added: llvm/trunk/unittests/Support/ErrnoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrnoTest.cpp?rev=305892&view=auto
==============================================================================
--- llvm/trunk/unittests/Support/ErrnoTest.cpp (added)
+++ llvm/trunk/unittests/Support/ErrnoTest.cpp Wed Jun 21 05:55:34 2017
@@ -0,0 +1,33 @@
+//===- ErrnoTest.cpp - Error handling unit tests --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Errno.h"
+#include "gtest/gtest.h"
+
+using namespace llvm::sys;
+
+TEST(ErrnoTest, RetryAfterSignal) {
+  EXPECT_EQ(1, RetryAfterSignal(-1, [] { return 1; }));
+
+  EXPECT_EQ(-1, RetryAfterSignal(-1, [] {
+    errno = EAGAIN;
+    return -1;
+  }));
+  EXPECT_EQ(EAGAIN, errno);
+
+  unsigned calls = 0;
+  EXPECT_EQ(1, RetryAfterSignal(-1, [&calls] {
+              errno = EINTR;
+              ++calls;
+              return calls == 1 ? -1 : 1;
+            }));
+  EXPECT_EQ(2u, calls);
+
+  EXPECT_EQ(1, RetryAfterSignal(-1, [](int x) { return x; }, 1));
+}




More information about the llvm-commits mailing list