[llvm] r306671 - Recommit "[Support] Add RetryAfterSignal helper function"
Pavel Labath via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 29 06:15:31 PDT 2017
Author: labath
Date: Thu Jun 29 06:15:31 2017
New Revision: 306671
URL: http://llvm.org/viewvc/llvm-project?rev=306671&view=rev
Log:
Recommit "[Support] Add RetryAfterSignal helper function"
The difference from the previous version is the use of decltype, as the
implementation of std::result_of in libc++ did not work correctly for
variadic function like open(2).
Original 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=306671&r1=306670&r2=306671&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Errno.h (original)
+++ llvm/trunk/include/llvm/Support/Errno.h Thu Jun 29 06:15:31 2017
@@ -16,6 +16,7 @@
#include <cerrno>
#include <string>
+#include <type_traits>
namespace llvm {
namespace sys {
@@ -29,6 +30,16 @@ std::string StrError();
/// Like the no-argument version above, but uses \p errnum instead of errno.
std::string StrError(int errnum);
+template <typename FailT, typename Fun, typename... Args>
+inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
+ const Args &... As) -> decltype(F(As...)) {
+ decltype(F(As...)) 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=306671&r1=306670&r2=306671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/MemoryBuffer.cpp (original)
+++ llvm/trunk/lib/Support/MemoryBuffer.cpp Thu Jun 29 06:15:31 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=306671&r1=306670&r2=306671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/Path.inc (original)
+++ llvm/trunk/lib/Support/Unix/Path.inc Thu Jun 29 06:15:31 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=306671&r1=306670&r2=306671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/Process.inc (original)
+++ llvm/trunk/lib/Support/Unix/Process.inc Thu Jun 29 06:15:31 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=306671&r1=306670&r2=306671&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/CMakeLists.txt (original)
+++ llvm/trunk/unittests/Support/CMakeLists.txt Thu Jun 29 06:15:31 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=306671&view=auto
==============================================================================
--- llvm/trunk/unittests/Support/ErrnoTest.cpp (added)
+++ llvm/trunk/unittests/Support/ErrnoTest.cpp Thu Jun 29 06:15:31 2017
@@ -0,0 +1,36 @@
+//===- 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));
+
+ std::unique_ptr<int> P(RetryAfterSignal(nullptr, [] { return new int(47); }));
+ EXPECT_EQ(47, *P);
+}
More information about the llvm-commits
mailing list