Windows async read EOF handling (#3162)

fix Windows "file::preadv" emulation EOF handling
This commit is contained in:
Andrei Kurushin 2018-07-13 00:30:50 +03:00 committed by Arvid Norberg
parent 7ce20fd9d0
commit 5399a14027
2 changed files with 60 additions and 19 deletions

View File

@ -202,28 +202,42 @@ namespace {
} }
int ret = 0; int ret = 0;
int num_waits = num_bufs;
for (int i = 0; i < num_bufs; ++i) for (int i = 0; i < num_bufs; ++i)
{ {
DWORD num_read; DWORD num_read;
if (ReadFile(fd, bufs[i].iov_base, DWORD(bufs[i].iov_len), &num_read, &ol[i]) == FALSE if (ReadFile(fd, bufs[i].iov_base, DWORD(bufs[i].iov_len), &num_read, &ol[i]) == FALSE)
&& GetLastError() != ERROR_IO_PENDING
#ifdef ERROR_CANT_WAIT
&& GetLastError() != ERROR_CANT_WAIT
#endif
)
{ {
ret = -1; DWORD const last_error = GetLastError();
goto done; if (last_error == ERROR_HANDLE_EOF)
{
num_waits = i;
break;
}
else if (last_error != ERROR_IO_PENDING
#ifdef ERROR_CANT_WAIT
&& last_error != ERROR_CANT_WAIT
#endif
)
{
ret = -1;
goto done;
}
} }
} }
if (wait_for_multiple_objects(int(h.size()), h.data()) == WAIT_FAILED) if (num_waits == 0)
{
goto done;
}
if (wait_for_multiple_objects(num_waits, h.data()) == WAIT_FAILED)
{ {
ret = -1; ret = -1;
goto done; goto done;
} }
for (auto& o : ol) for (auto& o : libtorrent::span<OVERLAPPED>(ol).first(num_waits))
{ {
if (WaitForSingleObject(o.hEvent, INFINITE) == WAIT_FAILED) if (WaitForSingleObject(o.hEvent, INFINITE) == WAIT_FAILED)
{ {
@ -233,11 +247,15 @@ namespace {
DWORD num_read; DWORD num_read;
if (GetOverlappedResult(fd, &o, &num_read, FALSE) == FALSE) if (GetOverlappedResult(fd, &o, &num_read, FALSE) == FALSE)
{ {
DWORD const last_error = GetLastError();
if (last_error != ERROR_HANDLE_EOF)
{
#ifdef ERROR_CANT_WAIT #ifdef ERROR_CANT_WAIT
TORRENT_ASSERT(GetLastError() != ERROR_CANT_WAIT); TORRENT_ASSERT(last_error != ERROR_CANT_WAIT);
#endif #endif
ret = -1; ret = -1;
break; break;
}
} }
ret += num_read; ret += num_read;
} }

View File

@ -287,25 +287,48 @@ TORRENT_TEST(file)
{ {
error_code ec; error_code ec;
file f; file f;
TEST_CHECK(f.open("test_file", open_mode::read_write, ec)); std::string test_file_name = "test_file";
TEST_CHECK(f.open(test_file_name, open_mode::read_write, ec));
if (ec) if (ec)
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str()); std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
TEST_EQUAL(ec, error_code()); TEST_EQUAL(ec, error_code());
if (ec) std::printf("%s\n", ec.message().c_str()); if (ec) std::printf("%s\n", ec.message().c_str());
char test[] = "test"; char test[] = "test";
iovec_t b = {test, 4}; size_t const test_word_size = sizeof(test) - 1;
TEST_EQUAL(f.writev(0, b, ec), 4); iovec_t b = {test, test_word_size};
TEST_EQUAL(f.writev(0, b, ec), test_word_size);
if (ec) if (ec)
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str()); std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
TEST_CHECK(!ec); TEST_CHECK(!ec);
char test_buf[5] = {0}; char test_buf[test_word_size + 1] = {0};
b = { test_buf, 4 }; b = { test_buf, test_word_size };
TEST_EQUAL(f.readv(0, b, ec), 4); TEST_EQUAL(f.readv(0, b, ec), test_word_size);
if (ec) if (ec)
std::printf("readv failed: [%s] %s\n", ec.category().name(), ec.message().c_str()); std::printf("readv failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
TEST_EQUAL(ec, error_code()); TEST_EQUAL(ec, error_code());
TEST_CHECK(test_buf == "test"_sv); TEST_CHECK(test_buf == "test"_sv);
f.close(); f.close();
TEST_CHECK(f.open(test_file_name, open_mode::read_only, ec));
if (ec)
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
TEST_EQUAL(ec, error_code());
if (ec) std::printf("%s\n", ec.message().c_str());
char test_buf2[test_word_size + 1] = {0};
std::memset(test_buf, 0, sizeof(test_buf));
iovec_t two_buffers[2] {
{test_buf, test_word_size},
{test_buf2, test_word_size}
};
TEST_EQUAL(f.readv(0, two_buffers, ec), test_word_size);
if (ec)
std::printf("readv failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
TEST_EQUAL(ec, error_code());
TEST_CHECK(test_buf == "test"_sv);
f.close();
} }
TORRENT_TEST(hard_link) TORRENT_TEST(hard_link)