Skip to content

Commit be57e23

Browse files
committed
Fix lost bytes on cancelled io
1 parent 829c6e7 commit be57e23

2 files changed

Lines changed: 81 additions & 1 deletion

File tree

src/fibers/fiber.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,6 @@ void FiberScheduler::poll(int fd, uint32_t events, uint64_t * triggeredEvents, I
14381438

14391439
void FiberScheduler::cancelIo(IoFuture * future) noexcept
14401440
{
1441-
future->result = nullptr;
14421441
enqueueIo(
14431442
nullptr,
14441443
[=](io_uring_sqe * sqe) noexcept
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#include <silk/fibers/fiber.h>
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <string>
6+
7+
#include <unistd.h>
8+
9+
namespace silk
10+
{
11+
12+
// Repeatedly read then immediately cancel.
13+
// Make sure no data is lost.
14+
TEST(IoCancel, cancelMustNotDropDeliveredBytes)
15+
{
16+
static constexpr uint64_t TOTAL = 4096;
17+
18+
struct Params
19+
{
20+
int readFd;
21+
int writeFd;
22+
23+
static int fiberMain(Params * p) noexcept
24+
{
25+
std::string expected(TOTAL, '\0');
26+
for (uint64_t i = 0; i < TOTAL; ++i)
27+
{
28+
expected[i] = static_cast<char>(i & 0xFF);
29+
}
30+
31+
EXPECT_EQ(::write(p->writeFd, expected.data(), TOTAL), static_cast<ssize_t>(TOTAL));
32+
::close(p->writeFd);
33+
34+
std::string got;
35+
for (;;)
36+
{
37+
char buf[64] = {};
38+
uint64_t bytes_read = 0;
39+
FiberScheduler::IoFuture future;
40+
iovec iov{buf, sizeof(buf)};
41+
FiberScheduler::read(p->readFd, &iov, 1, 0, &bytes_read, &future);
42+
future.cancel();
43+
if (future.wait() == 0)
44+
{
45+
// Read won (likely).
46+
if (bytes_read == 0)
47+
{
48+
break;
49+
}
50+
got.append(buf, bytes_read);
51+
}
52+
else
53+
{
54+
// Cancel won.
55+
// It's unlikely to happen consistently,
56+
// but to keep the test independent of kernel internals, read to make progress.
57+
if (!FiberScheduler::read(p->readFd, buf, sizeof(buf), 0, &bytes_read))
58+
{
59+
if (bytes_read == 0)
60+
{
61+
break;
62+
}
63+
got.append(buf, bytes_read);
64+
}
65+
}
66+
}
67+
68+
EXPECT_EQ(got, expected);
69+
return 0;
70+
}
71+
};
72+
73+
int fds[2];
74+
ASSERT_EQ(::pipe(fds), 0);
75+
76+
EXPECT_EQ(FiberScheduler::run(Params::fiberMain, Params{fds[0], fds[1]}), 0);
77+
78+
::close(fds[0]);
79+
}
80+
81+
} // namespace silk

0 commit comments

Comments
 (0)