summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2017-06-21 10:55:34 +0000
committerPavel Labath <labath@google.com>2017-06-21 10:55:34 +0000
commit1f6aea2eb3cee9adad6c6975f674957dabd37c7b (patch)
treeb87b8b2663a2ee1aba7268f3e7233525670905ad
parent71d72135b05c85c81745f25801fb137d02a3e796 (diff)
downloadbcm5719-llvm-1f6aea2eb3cee9adad6c6975f674957dabd37c7b.tar.gz
bcm5719-llvm-1f6aea2eb3cee9adad6c6975f674957dabd37c7b.zip
[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 llvm-svn: 305892
-rw-r--r--llvm/include/llvm/Support/Errno.h13
-rw-r--r--llvm/lib/Support/MemoryBuffer.cpp13
-rw-r--r--llvm/lib/Support/Unix/Path.inc12
-rw-r--r--llvm/lib/Support/Unix/Process.inc12
-rw-r--r--llvm/unittests/Support/CMakeLists.txt1
-rw-r--r--llvm/unittests/Support/ErrnoTest.cpp33
6 files changed, 59 insertions, 25 deletions
diff --git a/llvm/include/llvm/Support/Errno.h b/llvm/include/llvm/Support/Errno.h
index 8e145c7b0b5..6fe9ae9be53 100644
--- a/llvm/include/llvm/Support/Errno.h
+++ b/llvm/include/llvm/Support/Errno.h
@@ -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
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index 227e792d83d..85e782b2c04 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -240,11 +240,9 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) {
// 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 &Filename, uint64_t FileSize,
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());
}
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index b6774692595..45097eb918b 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -737,10 +737,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
#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 Twine &Name, int &ResultFD,
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;
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index 1d0143c6716..2d466209468 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -207,13 +207,10 @@ std::error_code Process::FixupStandardFileDescriptors() {
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::FixupStandardFileDescriptors() {
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)
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index e2a6561089b..641163e39ed 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_unittest(SupportTests
DebugTest.cpp
EndianStreamTest.cpp
EndianTest.cpp
+ ErrnoTest.cpp
ErrorOrTest.cpp
ErrorTest.cpp
FileOutputBufferTest.cpp
diff --git a/llvm/unittests/Support/ErrnoTest.cpp b/llvm/unittests/Support/ErrnoTest.cpp
new file mode 100644
index 00000000000..72b52c01ee3
--- /dev/null
+++ b/llvm/unittests/Support/ErrnoTest.cpp
@@ -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));
+}
OpenPOWER on IntegriCloud