[llvm][Support] ListeningSocket::accept returns operation_canceled if FD is set to -1 (#89479)
If `::poll` returns and `FD` equals -1, then `ListeningSocket::shutdown` has been called. So, regardless of any other information that could be gleaned from `FDs.revents` or `PollStatus`, it is appropriate to return `std::errc::operation_canceled`. `ListeningSocket::shutdown` copies `FD`'s value to `ObservedFD` then sets `FD` to -1 before canceling `::poll` by calling `::close(ObservedFD)` and writing to the pipe.
This commit is contained in:
parent
0170bd5d11
commit
203232ffbd
@ -204,17 +204,26 @@ ListeningSocket::accept(std::chrono::milliseconds Timeout) {
|
|||||||
auto Start = std::chrono::steady_clock::now();
|
auto Start = std::chrono::steady_clock::now();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
PollStatus = WSAPoll(FDs, 2, RemainingTime);
|
PollStatus = WSAPoll(FDs, 2, RemainingTime);
|
||||||
if (PollStatus == SOCKET_ERROR) {
|
|
||||||
#else
|
#else
|
||||||
PollStatus = ::poll(FDs, 2, RemainingTime);
|
PollStatus = ::poll(FDs, 2, RemainingTime);
|
||||||
|
#endif
|
||||||
|
// If FD equals -1 then ListeningSocket::shutdown has been called and it is
|
||||||
|
// appropriate to return operation_canceled
|
||||||
|
if (FD.load() == -1)
|
||||||
|
return llvm::make_error<StringError>(
|
||||||
|
std::make_error_code(std::errc::operation_canceled),
|
||||||
|
"Accept canceled");
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
if (PollStatus == SOCKET_ERROR) {
|
||||||
|
#else
|
||||||
if (PollStatus == -1) {
|
if (PollStatus == -1) {
|
||||||
#endif
|
#endif
|
||||||
// Ignore error if caused by interupting signal
|
|
||||||
std::error_code PollErrCode = getLastSocketErrorCode();
|
std::error_code PollErrCode = getLastSocketErrorCode();
|
||||||
|
// Ignore EINTR (signal occured before any request event) and retry
|
||||||
if (PollErrCode != std::errc::interrupted)
|
if (PollErrCode != std::errc::interrupted)
|
||||||
return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
|
return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PollStatus == 0)
|
if (PollStatus == 0)
|
||||||
return llvm::make_error<StringError>(
|
return llvm::make_error<StringError>(
|
||||||
std::make_error_code(std::errc::timed_out),
|
std::make_error_code(std::errc::timed_out),
|
||||||
@ -222,13 +231,7 @@ ListeningSocket::accept(std::chrono::milliseconds Timeout) {
|
|||||||
|
|
||||||
if (FDs[0].revents & POLLNVAL)
|
if (FDs[0].revents & POLLNVAL)
|
||||||
return llvm::make_error<StringError>(
|
return llvm::make_error<StringError>(
|
||||||
std::make_error_code(std::errc::bad_file_descriptor),
|
std::make_error_code(std::errc::bad_file_descriptor));
|
||||||
"File descriptor closed by another thread");
|
|
||||||
|
|
||||||
if (FDs[1].revents & POLLIN)
|
|
||||||
return llvm::make_error<StringError>(
|
|
||||||
std::make_error_code(std::errc::operation_canceled),
|
|
||||||
"Accept canceled");
|
|
||||||
|
|
||||||
auto Stop = std::chrono::steady_clock::now();
|
auto Stop = std::chrono::steady_clock::now();
|
||||||
ElapsedTime +=
|
ElapsedTime +=
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "llvm/Testing/Support/Error.h"
|
#include "llvm/Testing/Support/Error.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <iostream>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@ -86,13 +85,8 @@ TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) {
|
|||||||
std::chrono::milliseconds Timeout = std::chrono::milliseconds(100);
|
std::chrono::milliseconds Timeout = std::chrono::milliseconds(100);
|
||||||
Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
|
Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
|
||||||
ServerListener.accept(Timeout);
|
ServerListener.accept(Timeout);
|
||||||
|
ASSERT_EQ(llvm::errorToErrorCode(MaybeServer.takeError()),
|
||||||
ASSERT_THAT_EXPECTED(MaybeServer, Failed());
|
std::errc::timed_out);
|
||||||
llvm::Error Err = MaybeServer.takeError();
|
|
||||||
llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
|
|
||||||
std::error_code EC = SE.convertToErrorCode();
|
|
||||||
ASSERT_EQ(EC, std::errc::timed_out);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) {
|
TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) {
|
||||||
@ -122,12 +116,7 @@ TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) {
|
|||||||
|
|
||||||
// Wait for the CloseThread to finish
|
// Wait for the CloseThread to finish
|
||||||
CloseThread.join();
|
CloseThread.join();
|
||||||
|
ASSERT_EQ(llvm::errorToErrorCode(MaybeServer.takeError()),
|
||||||
ASSERT_THAT_EXPECTED(MaybeServer, Failed());
|
std::errc::operation_canceled);
|
||||||
llvm::Error Err = MaybeServer.takeError();
|
|
||||||
llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
|
|
||||||
std::error_code EC = SE.convertToErrorCode();
|
|
||||||
ASSERT_EQ(EC, std::errc::operation_canceled);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user