mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
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 llvm-svn: 306671
This commit is contained in:
parent
06eca2506b
commit
ff2168bb61
@ -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
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -21,6 +21,7 @@ add_llvm_unittest(SupportTests
|
||||
DebugTest.cpp
|
||||
EndianStreamTest.cpp
|
||||
EndianTest.cpp
|
||||
ErrnoTest.cpp
|
||||
ErrorOrTest.cpp
|
||||
ErrorTest.cpp
|
||||
FileOutputBufferTest.cpp
|
||||
|
36
unittests/Support/ErrnoTest.cpp
Normal file
36
unittests/Support/ErrnoTest.cpp
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user