Skip to content

Commit 67ebe2e

Browse files
committed
Retry poll calls on EINTR
When signals are delievered to the process, calls here to poll may be interrupted and return with a spurious failure. The call instead should be restarted.
1 parent 1dab2c1 commit 67ebe2e

File tree

1 file changed

+24
-2
lines changed
  • sdk/core/azure-core/src/http/curl

1 file changed

+24
-2
lines changed

sdk/core/azure-core/src/http/curl/curl.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "curl_session_private.hpp"
1515

1616
#if defined(AZ_PLATFORM_POSIX)
17+
#include <chrono>
1718
#include <poll.h> // for poll()
1819
#include <sys/socket.h> // for socket shutdown
1920
#elif defined(AZ_PLATFORM_WINDOWS)
@@ -102,17 +103,38 @@ int pollSocketUntilEventOrTimeout(
102103
interval = timeout;
103104
}
104105
int result = 0;
105-
for (long counter = 0; counter < timeout && result == 0; counter = counter + interval)
106+
bool poll_interrupted = false; // deadline and now are only valid if poll_interrupted
107+
long deadline{};
108+
long now{};
109+
for (long counter = 0; (poll_interrupted ? now < deadline : counter < timeout) && result == 0;
110+
counter = counter + interval)
106111
{
107112
// check cancelation
108113
context.ThrowIfCancelled();
109114
#if defined(AZ_PLATFORM_POSIX)
110115
result = poll(&poller, 1, interval);
116+
if (result < 0 && EINTR == errno)
117+
{
118+
// Only make extra syscalls to get the time in the (rare) event that poll
119+
// is interrupted. We jump through these hoops because the poll call does
120+
// not tell us how long it waited before being interrupted. For the first
121+
// interruption only, assume no time has passed during the interrupted
122+
// call.
123+
now = std::chrono::duration_cast<std::chrono::milliseconds>(
124+
std::chrono::steady_clock::now().time_since_epoch())
125+
.count();
126+
if (!poll_interrupted)
127+
{
128+
poll_interrupted = true;
129+
deadline = now + timeout - counter;
130+
result = 0;
131+
}
132+
}
111133
#elif defined(AZ_PLATFORM_WINDOWS)
112134
result = WSAPoll(&poller, 1, interval);
113135
#endif
114136
}
115-
// result can be either 0 (timeout) or > 1 (socket ready)
137+
// result can be 0 (timeout), > 0 (socket ready), or < 0 (error)
116138
return result;
117139
}
118140

0 commit comments

Comments
 (0)